提高python中重心坐标计算的效率

key*_*ris 7 python numpy delaunay linear-algebra

背景:我试图将一张脸变成另一张不同形状的脸.

为了将一个图像扭曲成另一个图像,我使用面部地标的delaunay三角剖分并将一个肖像的三角形扭曲成第二个肖像的相应三角形.我正在使用重心坐标系将三角形内的一个点映射到另一个三角形上相应的扭曲位置.

我的第一种方法是用逆乘法求解系统Ax = b,其中A由三角形的三个角组成,b代表当前点,x代表该点的重心坐标(alpha,beta和gamma) ).我发现每个三角形一次矩阵A的倒数,然后对于该三角形内的每个点,通过找到A ^ -1和点b的点积来计算重心坐标.我发现这很慢(该功能需要36秒才能完成).

根据其他帖子的建议,我尝试使用最小二乘解决方案来提高此过程的效率.但是,当我使用numpy的lsq方法时,时间增加到154秒.我相信这是因为A矩阵在内部循环运行时每次都被考虑在内,而在我能够在两个循环开始之前只能找到一次反转之前.

我的问题是,我怎样才能提高这个功能的效率?有没有办法存储A的因子分解,以便每次为新点计算最小二乘解,它不会重复相同的工作?

该函数的伪代码:

# Iterate through each triangle (and get corresponding warp triangle)
for triangle in triangulation:

    # Extract corners of the unwarped triangle
    a = firstCornerUW
    b = secondCornerUW
    c = thirdCornerUW

    # Extract corners of the warp triangle
    a_prime = firstCornerW
    b_prime = secondCornerW
    c_prime = thirdCornerW

    # This matrix will be the same for all points within the triangle
    triMatrix = matrix of a, b, and c

    # Bounding box of the triangle
    xleft = min(ax, bx, cx)
    xright = max(ax, bx, cx)
    ytop = min(ay, by, cy)
    ybottom = max(ay, by, cy)

    for x in range(xleft, xright):

        for y in range(ytop, ybottom):

            # Store the current point as a matrix
            p = np.array([[x], [y], [1]])

            # Solve for least squares solution to get barycentric coordinates
            barycoor = np.linalg.lstsq(triMatrix, p)

            # Pull individual coordinates from the array
            alpha = barycoor[0]
            beta = barycoor[1]
            gamma = barycoor[2]

            # If any of these conditions are not met, the point is not inside the triangle
            if alpha, beta, gamma > 0 and alpha + beta + gamma <= 1:

                # Now calculate the warped point by multiplying by alpha, beta, and gamma
                # Warp the point from image to warped image
Run Code Online (Sandbox Code Playgroud)

Eel*_*orn 3

这是我的建议,用伪代码表达。请注意,矢量化三角形上的循环也不应该更困难。

# Iterate through each triangle (and get corresponding warp triangle)
for triangle in triangulation:

    # Extract corners of the unwarped triangle
    a = firstCornerUW
    b = secondCornerUW
    c = thirdCornerUW

    # Bounding box of the triangle
    xleft = min(ax, bx, cx)
    xright = max(ax, bx, cx)
    ytop = min(ay, by, cy)
    ybottom = max(ay, by, cy)

    barytransform = np.linalg.inv([[ax,bx,cx], [ay,by,cy], [1,1,1]])     

    grid = np.mgrid[xleft:xright, ytop:ybottom].reshape(2,-1)
    grid = np.vstack((grid, np.ones((1, grid.shape[1]))))

    barycoords = np.dot(barytransform, grid)
    barycoords = barycoords[:,np.all(barycoords>=0, axis=0)]
Run Code Online (Sandbox Code Playgroud)