美文网首页
人脸morph

人脸morph

作者: johnzhang123 | 来源:发表于2019-01-16 09:56 被阅读0次

  morph的意思是变形,在landmark和Delaunay Triangulation的基础上,这里介绍一种融合多张脸的变形方法。我们把小布什和奥巴马的脸融合到一起去。

  1. 原理:
      在Delaunay Triangulation之后,将对应三角形仿射变换到target上,并将颜色进行融合。就两张图来说,一种简单的融合方式就是(1 - \alpha) * c1 + \alpha * c2 ,具体步骤如下:
      a). 将两张图标定landmark, 之后再在边角处标上另外几个定位点(正确的定位点越多越好),然后做Delaunay Triangulation:
    obm_xbs_delauney.png
      b). 复制第一幅图像,把第二幅图像上对应的三角形区域通过仿射变换映射过来,将其颜色进行融合,以各占一半比例为例:0.5 * c1 + 0.5 * c2,周边模糊是因为缺少定位点,缺少定位点就会导致仿射映射不准确而重影。而自动检测的landmark只位于正脸部,所以那一部分比较清晰。
    morph.png
  2. 示例代码:
def rectContains(rect, point) :
    if point[0] < rect[0] :
        return False
    elif point[1] < rect[1] :
        return False
    elif point[0] > rect[0] + rect[2] :
        return False
    elif point[1] > rect[1] + rect[3] :
        return False
    return True

def applyAffineTransform(src, srcTri, dstTri, size) :
    # Given a pair of triangles, find the affine transform.
    warpMat = cv2.getAffineTransform( np.float32(srcTri), np.float32(dstTri) )
    # Apply the Affine Transform just found to the src image
    dst = cv2.warpAffine( src, warpMat, (size[0], size[1]), None, flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101 )
    return dst

def morphTriangle(img_list, img, t_list, t, alpha) :
    # Find bounding rectangle for each triangle
    r_list = []
    for i in range(len(t_list)):
        r_list.append(cv2.boundingRect(np.float32([t_list[i]])))
    r = cv2.boundingRect(np.float32([t]))
    # Offset points by left top corner of the respective rectangles
    tRect_list = []
    tRect = []
    for i in range(len(t_list)):
        tmp_list = []
        for j in range(0, 3):
            tmp_list.append(((t_list[i][j][0] - r_list[i][0]),(t_list[i][j][1] - r_list[i][1])))
        tRect_list.append(tmp_list)
    for j in range(0, 3):
        tRect.append(((t[j][0] - r[0]),(t[j][1] - r[1])))
    # Get mask by filling triangle
    mask = np.zeros((r[3], r[2], 3), dtype = np.float32)
    cv2.fillConvexPoly(mask, np.int32(tRect), (1.0, 1.0, 1.0), 16, 0);
    # Apply warpImage to small rectangular patches
    imgRect_list = []
    for i in range(len(r_list)):
        imgRect_list.append(img_list[i][r_list[i][1]:r_list[i][1] + r_list[i][3], r_list[i][0]:r_list[i][0] + r_list[i][2]])
    size = (r[2], r[3])
    warpImage_list = []
    for i in range(len(imgRect_list)):
        warpImage_list.append(np.float32(applyAffineTransform(imgRect_list[i], tRect_list[i], tRect, size)))
    # Alpha blend rectangular patches
    imgRect = alpha * sum(warpImage_list[:-1]) + (1 - alpha * (len(warpImage_list) - 1)) * warpImage_list[-1]
        # Copy triangular region of the rectangular patch to the output image
    img[r[1]:r[1]+r[3], r[0]:r[0]+r[2]] = img[r[1]:r[1]+r[3], r[0]:r[0]+r[2]] * ( 1 - mask ) + imgRect * mask

def calculateDelaunayTriangles(rect, points):
    #create subdiv
    subdiv = cv2.Subdiv2D(rect);
    # Insert points into subdiv
    for p in points:
        subdiv.insert(p)
    triangleList = subdiv.getTriangleList();
    delaunayTri = []
    pt = []
    for t in triangleList:
        pt.append((t[0], t[1]))
        pt.append((t[2], t[3]))
        pt.append((t[4], t[5]))
        pt1 = (t[0], t[1])
        pt2 = (t[2], t[3])
        pt3 = (t[4], t[5])
        if rectContains(rect, pt1) and rectContains(rect, pt2) and rectContains(rect, pt3):
            ind = []
            #Get face-points (from 68 face detector) by coordinates
            for j in range(0, 3):
                for k in range(0, len(points)):
                    if(abs(pt[j][0] - points[k][0]) < 1.0 and abs(pt[j][1] - points[k][1]) < 1.0):
                        ind.append(k)
            # Three points form a triangle. Triangle array corresponds to the file tri.txt in FaceMorph
            if len(ind) == 3:
                delaunayTri.append((ind[0], ind[1], ind[2]))
        pt = []
    return delaunayTri

img1 = cv2.imread('../jianshu/abm.jpg')
keypoints1 = get_keypoints(img1)
img2 = cv2.imread('../jianshu/xbs.jpg')
keypoints2 = get_keypoints(img2)

alpha = 0.5
# Read images
img_list = []
img_list.append(img1)
img_list.append(img2)
points_list = []
points_list.append(keypoints1)
points_list.append(keypoints2)

points = []
for i in range(0, len(points_list[0])):
    x = alpha * sum(t[i][0] for t in points_list)
    y = alpha * sum(t[i][1] for t in points_list)
    points.append((x,y))
dt = calculateDelaunayTriangles((0, 0, (img_list[0].shape)[1], (img_list[0].shape)[0]), points_list[0])
imgMorph = np.zeros(img_list[0].shape, dtype = img_list[0].dtype)
for line in dt:
    x,y,z = line
    x = int(x)
    y = int(y)
    z = int(z)
    t_list = []
    for i in range(len(points_list)):
        t_list.append((points_list[i][x], points_list[i][y], points_list[i][z]))
    t = [points[x], points[y], points[z]]
    # Morph one triangle at a time.
    morphTriangle(img_list, imgMorph, t_list, t, alpha)
show_img(imgMorph)

相关文章

网友评论

      本文标题:人脸morph

      本文链接:https://www.haomeiwen.com/subject/pejpdqtx.html