morph的意思是变形,在landmark和Delaunay Triangulation的基础上,这里介绍一种融合多张脸的变形方法。我们把小布什和奥巴马的脸融合到一起去。
- 原理:
在Delaunay Triangulation之后,将对应三角形仿射变换到target上,并将颜色进行融合。就两张图来说,一种简单的融合方式就是 ,具体步骤如下:
a). 将两张图标定landmark, 之后再在边角处标上另外几个定位点(正确的定位点越多越好),然后做Delaunay Triangulation:
obm_xbs_delauney.png
b). 复制第一幅图像,把第二幅图像上对应的三角形区域通过仿射变换映射过来,将其颜色进行融合,以各占一半比例为例:0.5 * c1 + 0.5 * c2,周边模糊是因为缺少定位点,缺少定位点就会导致仿射映射不准确而重影。而自动检测的landmark只位于正脸部,所以那一部分比较清晰。
morph.png - 示例代码:
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)
网友评论