Delaunay 在网络摄像头上进行面部交换,OpenCV 给出 !_src.empty() 错误
我有两个网络摄像头,我想使用 OpenCV 和三角测量在它们之间交换脸部。到目前为止,我可以移动源帧面来替换目标帧面。但现在我尝试用其他方式来做。使用当前代码,我收到以下错误:
new_source_face_canvas_area_gray = cv2.cvtColor(new_source_face_canvas_area, cv2.COLOR_BGR2GRAY)
cv2.error: OpenCV(4.5.3) /tmp/pip-install-7krwkm_h/opencv-contrib-python_1e8bcbc3da2744c690bb65b52d8197bb/opencv/modules/imgproc/src/color.cpp:182:
error: (-215:Assertion failed) !_src.empty() in function 'cvtColor'
有人能指出那里发生了什么吗?当将面部交换从目标帧反转到源帧时,我试图保持逻辑性,但我确信当试图使一切“相反”时我犯了愚蠢的错误。非常感谢您的帮助!
sourceframe = video_process.frame
destinationframe = video_process.frame2
height, width, channels = destinationframe.shape
height2, width2, channels2 = sourceframe.shape
sourcegray = cv2.cvtColor(sourceframe, cv2.COLOR_BGR2GRAY)
destinationgray = cv2.cvtColor(destinationframe, cv2.COLOR_BGR2GRAY)
sourcemask = np.zeros_like(sourcegray)
destinationmask = np.zeros_like(destinationgray)
source_image_canvas = np.zeros((height2, width2, channels2), np.uint8)
destination_image_canvas = np.zeros((height, width, channels), np.uint8)
indexes_triangles = []
#landmarks of first face
sourcefaces = video_process.faces
destinationfaces = video_process.faces2
for sourceface in sourcefaces:
sourcelandmarks = video_process.landmarks
sourcelandmarks_points = []
for n in range(0, 68):
x = sourcelandmarks.part(n).x
y = sourcelandmarks.part(n).y
sourcelandmarks_points.append((x, y))
source_triangle_points = np.array(sourcelandmarks_points, np.int32)
sourceconvexhull = cv2.convexHull(source_triangle_points)
cv2.fillConvexPoly(sourcemask, sourceconvexhull, 255)
# Delaunay triangulation
sourcerect = cv2.boundingRect(sourceconvexhull)
sourcesubdiv = cv2.Subdiv2D(sourcerect)
sourcesubdiv.insert(sourcelandmarks_points)
sourcetriangles = sourcesubdiv.getTriangleList()
sourcetriangles = np.array(sourcetriangles, dtype=np.int32)
for t in sourcetriangles:
pt1 = (t[0], t[1])
pt2 = (t[2], t[3])
pt3 = (t[4], t[5])
index_pt1 = np.where((source_triangle_points == pt1).all(axis=1))
index_pt1 = extract_index_nparray(index_pt1)
index_pt2 = np.where((source_triangle_points == pt2).all(axis=1))
index_pt2 = extract_index_nparray(index_pt2)
index_pt3 = np.where((source_triangle_points == pt3).all(axis=1))
index_pt3 = extract_index_nparray(index_pt3)
if index_pt1 is not None and index_pt2 is not None and index_pt3 is not None:
source_triangle = [index_pt1, index_pt2, index_pt3]
indexes_triangles.append(source_triangle)
# Face 2
for destinationface in destinationfaces:
destinationlandmarks = video_process.landmarks2
destinationlandmarks_points = []
for n in range(0, 68):
x = destinationlandmarks.part(n).x
y = destinationlandmarks.part(n).y
destinationlandmarks_points.append((x, y))
destination_triangle_points = np.array(destinationlandmarks_points, np.int32)
destinationconvexhull = cv2.convexHull(destination_triangle_points)
cv2.fillConvexPoly(destinationmask, destinationconvexhull, 255)
# Iterating through all source delaunay triangle and superimposing source triangles in empty destination canvas after warping to same size as destination triangles' shape
for triangle_index in indexes_triangles:
# Triangulation of the first face
tr1_pt1 = sourcelandmarks_points[triangle_index[0]]
tr1_pt2 = sourcelandmarks_points[triangle_index[1]]
tr1_pt3 = sourcelandmarks_points[triangle_index[2]]
source_triangle = np.array([tr1_pt1, tr1_pt2, tr1_pt3], np.int32)
# Source rectangle
source_rectangle = cv2.boundingRect(source_triangle)
(x, y, w, h) = source_rectangle
(xu, yu, wu, hu) = source_rectangle
cropped_source_rectangle = sourceframe[y: yu + hu, x: xu + wu]
cropped_source_rectangle_mask = np.zeros((hu, wu), np.uint8)
source_triangle_points = np.array([[tr1_pt1[0] - x, tr1_pt1[1] - y],
[tr1_pt2[0] - x, tr1_pt2[1] - y],
[tr1_pt3[0] - x, tr1_pt3[1] - y]], np.int32)
cv2.fillConvexPoly(cropped_source_rectangle_mask, source_triangle_points, 255)
# Triangulation of second face
tr2_pt1 = destinationlandmarks_points[triangle_index[0]]
tr2_pt2 = destinationlandmarks_points[triangle_index[1]]
tr2_pt3 = destinationlandmarks_points[triangle_index[2]]
destination_triangle = np.array([tr2_pt1, tr2_pt2, tr2_pt3], np.int32)
# Dest rectangle
destination_rectangle = cv2.boundingRect(destination_triangle)
(x, y, w, h) = destination_rectangle
cropped_destination_rectangle = sourceframe[y: y + h, x: x + w]
cropped_destination_rectangle_mask = np.zeros((h, w), np.uint8)
destination_triangle_points = np.array([[tr2_pt1[0] - x, tr2_pt1[1] - y],
[tr2_pt2[0] - x, tr2_pt2[1] - y],
[tr2_pt3[0] - x, tr2_pt3[1] - y]], np.int32)
cv2.fillConvexPoly(cropped_destination_rectangle_mask, destination_triangle_points, 255)
# Warp source triangle to match shape of destination triangle and put it over destination triangle mask
source_triangle_points = np.float32(source_triangle_points)
destination_triangle_points = np.float32(destination_triangle_points)
matrix = cv2.getAffineTransform(source_triangle_points, destination_triangle_points)
matrix2 = cv2.getAffineTransform(destination_triangle_points, source_triangle_points)
warped_rectangle = cv2.warpAffine(cropped_source_rectangle, matrix, (w, h))
warped_triangle = cv2.bitwise_and(warped_rectangle, warped_rectangle, mask=cropped_destination_rectangle_mask)
warped_rectangle_2 = cv2.warpAffine(cropped_destination_rectangle, matrix2, (wu, hu))
warped_triangle_2 = cv2.bitwise_and(warped_rectangle_2, warped_rectangle_2, mask=cropped_source_rectangle_mask)
# Reconstructing destination face in empty canvas of destination image
new_dest_face_canvas_area = destination_image_canvas[y: y + h, x: x + w] # h y etc. are from dest rect and it works
new_dest_face_canvas_area_gray = cv2.cvtColor(new_dest_face_canvas_area, cv2.COLOR_BGR2GRAY)
_, mask_created_triangle = cv2.threshold(new_dest_face_canvas_area_gray, 1, 255, cv2.THRESH_BINARY_INV)
warped_triangle = cv2.bitwise_and(warped_triangle, warped_triangle, mask=mask_created_triangle)
new_dest_face_canvas_area = cv2.add(new_dest_face_canvas_area, warped_triangle)
destination_image_canvas[y: y + h, x: x + w] = new_dest_face_canvas_area
# Reconstructing source face in empty canvas of source image
new_source_face_canvas_area = source_image_canvas[y: yu + hu, x: xu + wu] # hu et are from source rect now
new_source_face_canvas_area_gray = cv2.cvtColor(new_source_face_canvas_area, cv2.COLOR_BGR2GRAY)
_, mask_created_triangle_2 = cv2.threshold(new_source_face_canvas_area_gray, 1, 255, cv2.THRESH_BINARY_INV)
warped_triangle_2 = cv2.bitwise_and(warped_triangle_2, warped_triangle_2, mask=mask_created_triangle_2)
new_source_face_canvas_area = cv2.add(new_source_face_canvas_area, warped_triangle_2)
source_image_canvas[y: yu + hu, x: xu + wu] = new_source_face_canvas_area
I have two webcam feeds and I want to swap faces between them using OpenCV and triangulation. So far I'm able to move sourceframe face to replace destinationframe face. However now I try to do it other way around. With current code, I get the following error:
new_source_face_canvas_area_gray = cv2.cvtColor(new_source_face_canvas_area, cv2.COLOR_BGR2GRAY)
cv2.error: OpenCV(4.5.3) /tmp/pip-install-7krwkm_h/opencv-contrib-python_1e8bcbc3da2744c690bb65b52d8197bb/opencv/modules/imgproc/src/color.cpp:182:
error: (-215:Assertion failed) !_src.empty() in function 'cvtColor'
Is anyone able to point out what's happening there? I've tried to be logical when reversing the face swap from destionationframe to sourceframe, but I'm sure I'm doing silly mistake when trying to make everything "the opposite". Many thanks for your help!
sourceframe = video_process.frame
destinationframe = video_process.frame2
height, width, channels = destinationframe.shape
height2, width2, channels2 = sourceframe.shape
sourcegray = cv2.cvtColor(sourceframe, cv2.COLOR_BGR2GRAY)
destinationgray = cv2.cvtColor(destinationframe, cv2.COLOR_BGR2GRAY)
sourcemask = np.zeros_like(sourcegray)
destinationmask = np.zeros_like(destinationgray)
source_image_canvas = np.zeros((height2, width2, channels2), np.uint8)
destination_image_canvas = np.zeros((height, width, channels), np.uint8)
indexes_triangles = []
#landmarks of first face
sourcefaces = video_process.faces
destinationfaces = video_process.faces2
for sourceface in sourcefaces:
sourcelandmarks = video_process.landmarks
sourcelandmarks_points = []
for n in range(0, 68):
x = sourcelandmarks.part(n).x
y = sourcelandmarks.part(n).y
sourcelandmarks_points.append((x, y))
source_triangle_points = np.array(sourcelandmarks_points, np.int32)
sourceconvexhull = cv2.convexHull(source_triangle_points)
cv2.fillConvexPoly(sourcemask, sourceconvexhull, 255)
# Delaunay triangulation
sourcerect = cv2.boundingRect(sourceconvexhull)
sourcesubdiv = cv2.Subdiv2D(sourcerect)
sourcesubdiv.insert(sourcelandmarks_points)
sourcetriangles = sourcesubdiv.getTriangleList()
sourcetriangles = np.array(sourcetriangles, dtype=np.int32)
for t in sourcetriangles:
pt1 = (t[0], t[1])
pt2 = (t[2], t[3])
pt3 = (t[4], t[5])
index_pt1 = np.where((source_triangle_points == pt1).all(axis=1))
index_pt1 = extract_index_nparray(index_pt1)
index_pt2 = np.where((source_triangle_points == pt2).all(axis=1))
index_pt2 = extract_index_nparray(index_pt2)
index_pt3 = np.where((source_triangle_points == pt3).all(axis=1))
index_pt3 = extract_index_nparray(index_pt3)
if index_pt1 is not None and index_pt2 is not None and index_pt3 is not None:
source_triangle = [index_pt1, index_pt2, index_pt3]
indexes_triangles.append(source_triangle)
# Face 2
for destinationface in destinationfaces:
destinationlandmarks = video_process.landmarks2
destinationlandmarks_points = []
for n in range(0, 68):
x = destinationlandmarks.part(n).x
y = destinationlandmarks.part(n).y
destinationlandmarks_points.append((x, y))
destination_triangle_points = np.array(destinationlandmarks_points, np.int32)
destinationconvexhull = cv2.convexHull(destination_triangle_points)
cv2.fillConvexPoly(destinationmask, destinationconvexhull, 255)
# Iterating through all source delaunay triangle and superimposing source triangles in empty destination canvas after warping to same size as destination triangles' shape
for triangle_index in indexes_triangles:
# Triangulation of the first face
tr1_pt1 = sourcelandmarks_points[triangle_index[0]]
tr1_pt2 = sourcelandmarks_points[triangle_index[1]]
tr1_pt3 = sourcelandmarks_points[triangle_index[2]]
source_triangle = np.array([tr1_pt1, tr1_pt2, tr1_pt3], np.int32)
# Source rectangle
source_rectangle = cv2.boundingRect(source_triangle)
(x, y, w, h) = source_rectangle
(xu, yu, wu, hu) = source_rectangle
cropped_source_rectangle = sourceframe[y: yu + hu, x: xu + wu]
cropped_source_rectangle_mask = np.zeros((hu, wu), np.uint8)
source_triangle_points = np.array([[tr1_pt1[0] - x, tr1_pt1[1] - y],
[tr1_pt2[0] - x, tr1_pt2[1] - y],
[tr1_pt3[0] - x, tr1_pt3[1] - y]], np.int32)
cv2.fillConvexPoly(cropped_source_rectangle_mask, source_triangle_points, 255)
# Triangulation of second face
tr2_pt1 = destinationlandmarks_points[triangle_index[0]]
tr2_pt2 = destinationlandmarks_points[triangle_index[1]]
tr2_pt3 = destinationlandmarks_points[triangle_index[2]]
destination_triangle = np.array([tr2_pt1, tr2_pt2, tr2_pt3], np.int32)
# Dest rectangle
destination_rectangle = cv2.boundingRect(destination_triangle)
(x, y, w, h) = destination_rectangle
cropped_destination_rectangle = sourceframe[y: y + h, x: x + w]
cropped_destination_rectangle_mask = np.zeros((h, w), np.uint8)
destination_triangle_points = np.array([[tr2_pt1[0] - x, tr2_pt1[1] - y],
[tr2_pt2[0] - x, tr2_pt2[1] - y],
[tr2_pt3[0] - x, tr2_pt3[1] - y]], np.int32)
cv2.fillConvexPoly(cropped_destination_rectangle_mask, destination_triangle_points, 255)
# Warp source triangle to match shape of destination triangle and put it over destination triangle mask
source_triangle_points = np.float32(source_triangle_points)
destination_triangle_points = np.float32(destination_triangle_points)
matrix = cv2.getAffineTransform(source_triangle_points, destination_triangle_points)
matrix2 = cv2.getAffineTransform(destination_triangle_points, source_triangle_points)
warped_rectangle = cv2.warpAffine(cropped_source_rectangle, matrix, (w, h))
warped_triangle = cv2.bitwise_and(warped_rectangle, warped_rectangle, mask=cropped_destination_rectangle_mask)
warped_rectangle_2 = cv2.warpAffine(cropped_destination_rectangle, matrix2, (wu, hu))
warped_triangle_2 = cv2.bitwise_and(warped_rectangle_2, warped_rectangle_2, mask=cropped_source_rectangle_mask)
# Reconstructing destination face in empty canvas of destination image
new_dest_face_canvas_area = destination_image_canvas[y: y + h, x: x + w] # h y etc. are from dest rect and it works
new_dest_face_canvas_area_gray = cv2.cvtColor(new_dest_face_canvas_area, cv2.COLOR_BGR2GRAY)
_, mask_created_triangle = cv2.threshold(new_dest_face_canvas_area_gray, 1, 255, cv2.THRESH_BINARY_INV)
warped_triangle = cv2.bitwise_and(warped_triangle, warped_triangle, mask=mask_created_triangle)
new_dest_face_canvas_area = cv2.add(new_dest_face_canvas_area, warped_triangle)
destination_image_canvas[y: y + h, x: x + w] = new_dest_face_canvas_area
# Reconstructing source face in empty canvas of source image
new_source_face_canvas_area = source_image_canvas[y: yu + hu, x: xu + wu] # hu et are from source rect now
new_source_face_canvas_area_gray = cv2.cvtColor(new_source_face_canvas_area, cv2.COLOR_BGR2GRAY)
_, mask_created_triangle_2 = cv2.threshold(new_source_face_canvas_area_gray, 1, 255, cv2.THRESH_BINARY_INV)
warped_triangle_2 = cv2.bitwise_and(warped_triangle_2, warped_triangle_2, mask=mask_created_triangle_2)
new_source_face_canvas_area = cv2.add(new_source_face_canvas_area, warped_triangle_2)
source_image_canvas[y: yu + hu, x: xu + wu] = new_source_face_canvas_area
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论