如何使用 Opencv shrink/expand 面部特征?
How to shrink/expand facial features using Opencv?
我正在尝试编写一个应用程序,使用 opencv 和 dlib 使面部图像的某些部分变大或变小。我使用 shape_predictor_68_face_landmarks.dat
检测面部标志。在以下函数中,tmp
变量应该以在图像上缩放鼻子或左眼的方式进行转换。
def visualize_facial_landmarks(image, shape, colors=None, alpha=0.75):
# create two copies of the input image -- one for the
# overlay and one for the final output image
overlay = image.copy()
output = image.copy()
# if the colors list is None, initialize it with a unique
# color for each facial landmark region
if colors is None:
colors = [(19, 199, 109), (79, 76, 240), (230, 159, 23),
(168, 100, 168), (158, 163, 32),
(163, 38, 32), (180, 42, 220)]
# loop over the facial landmark regions individually
for (i, name) in enumerate(FACIAL_LANDMARKS_INDEXES.keys()):
# grab the (x, y)-coordinates associated with the
# face landmark
(j, k) = FACIAL_LANDMARKS_INDEXES[name]
pts = shape[j:k]
facial_features_cordinates[name] = pts
if name != "Jaw" and name == "Left_Eye" or name == "Nose":
minX = min(pts[:,0])
maxX = max(pts[:,0])
minY = min(pts[:,1])
maxY = max(pts[:,1])
rect = []
rect.append([minX, minY])
rect.append([minX, maxY])
rect.append([maxX, minY])
rect.append([maxX, maxY])
rect = np.array(rect)
hull = cv2.convexHull(rect)
# print(hull)
# output = cv2.resize(overlay, dsize)
# print(overlay[minX:maxX,minY:maxX,:])
tmp = overlay[minY:maxY, minX:maxX, :]
print(tmp.shape)
s = 2
Affine_Mat_w = [s, 0, tmp.shape[0]/2.0 - s*tmp.shape[0]/2.0]
Affine_Mat_h = [0, s, tmp.shape[1]/2.0 - s*tmp.shape[1]/2.0]
M = np.c_[ Affine_Mat_w, Affine_Mat_h].T
tmp = cv2.warpAffine(tmp, M, (tmp.shape[1], tmp.shape[0]))
overlay[minY:maxY, minX:maxX, :] = tmp
return overlay
作为示例,附上以下图片:
更新 #1
沿着眼睛和鼻子周围的面部标志少量应用 pinch and bulge distortion
可能会提供不错的结果,而无需使用其他方法。如果它影响更大的区域,它也有可能会明显扭曲眼镜。这些应该有所帮助,
- Image Warping - Bulge Effect Algorithm
- https://math.stackexchange.com/questions/266250/explanation-of-this-image-warping-bulge-filter-algorithm
- Formulas for Barrel/Pincushion distortion
我不确定如何单独在 opencv 中执行此操作而不会使面部看起来不自然。下面根据我自己的探索做一个大概的解释。如果我有任何错误,请随时纠正我。
3D 网格
我认为当前人脸美化方法(例如 Android 相机上的方法)的一种方法是将 3d 人脸网格或整个头部模型对准原始人脸。
它使用面部标志提取面部纹理,并将它们与应用了纹理的相应 3d 网格对齐。这样可以调整 3d 网格,纹理将遵循面部几何形状。可能还有其他步骤,例如将结果传递给另一个网络,post-涉及处理以使其看起来更自然。
Mediapipe Face Mesh will probably be helpful also as it provides dense 3d face landmarks with 3D face models, UV visualization, coordinates. This is a discussion 用于 Mediapipe 中面部的 UV 展开。
示例来自,https://github.com/YadiraF/DECA。
示例来自,https://github.com/sicxu/Deep3DFaceRecon_pytorch。
GAN
另一种方法是使用 GAN 来编辑面部特征、应用灯光、化妆等
示例来自,https://github.com/run-youngjoo/SC-FEGAN。
另一个例子,https://github.com/genforce/idinvert_pytorch.
我正在尝试编写一个应用程序,使用 opencv 和 dlib 使面部图像的某些部分变大或变小。我使用 shape_predictor_68_face_landmarks.dat
检测面部标志。在以下函数中,tmp
变量应该以在图像上缩放鼻子或左眼的方式进行转换。
def visualize_facial_landmarks(image, shape, colors=None, alpha=0.75):
# create two copies of the input image -- one for the
# overlay and one for the final output image
overlay = image.copy()
output = image.copy()
# if the colors list is None, initialize it with a unique
# color for each facial landmark region
if colors is None:
colors = [(19, 199, 109), (79, 76, 240), (230, 159, 23),
(168, 100, 168), (158, 163, 32),
(163, 38, 32), (180, 42, 220)]
# loop over the facial landmark regions individually
for (i, name) in enumerate(FACIAL_LANDMARKS_INDEXES.keys()):
# grab the (x, y)-coordinates associated with the
# face landmark
(j, k) = FACIAL_LANDMARKS_INDEXES[name]
pts = shape[j:k]
facial_features_cordinates[name] = pts
if name != "Jaw" and name == "Left_Eye" or name == "Nose":
minX = min(pts[:,0])
maxX = max(pts[:,0])
minY = min(pts[:,1])
maxY = max(pts[:,1])
rect = []
rect.append([minX, minY])
rect.append([minX, maxY])
rect.append([maxX, minY])
rect.append([maxX, maxY])
rect = np.array(rect)
hull = cv2.convexHull(rect)
# print(hull)
# output = cv2.resize(overlay, dsize)
# print(overlay[minX:maxX,minY:maxX,:])
tmp = overlay[minY:maxY, minX:maxX, :]
print(tmp.shape)
s = 2
Affine_Mat_w = [s, 0, tmp.shape[0]/2.0 - s*tmp.shape[0]/2.0]
Affine_Mat_h = [0, s, tmp.shape[1]/2.0 - s*tmp.shape[1]/2.0]
M = np.c_[ Affine_Mat_w, Affine_Mat_h].T
tmp = cv2.warpAffine(tmp, M, (tmp.shape[1], tmp.shape[0]))
overlay[minY:maxY, minX:maxX, :] = tmp
return overlay
作为示例,附上以下图片:
更新 #1
沿着眼睛和鼻子周围的面部标志少量应用 pinch and bulge distortion
可能会提供不错的结果,而无需使用其他方法。如果它影响更大的区域,它也有可能会明显扭曲眼镜。这些应该有所帮助,
- Image Warping - Bulge Effect Algorithm
- https://math.stackexchange.com/questions/266250/explanation-of-this-image-warping-bulge-filter-algorithm
- Formulas for Barrel/Pincushion distortion
我不确定如何单独在 opencv 中执行此操作而不会使面部看起来不自然。下面根据我自己的探索做一个大概的解释。如果我有任何错误,请随时纠正我。
3D 网格
我认为当前人脸美化方法(例如 Android 相机上的方法)的一种方法是将 3d 人脸网格或整个头部模型对准原始人脸。
它使用面部标志提取面部纹理,并将它们与应用了纹理的相应 3d 网格对齐。这样可以调整 3d 网格,纹理将遵循面部几何形状。可能还有其他步骤,例如将结果传递给另一个网络,post-涉及处理以使其看起来更自然。
Mediapipe Face Mesh will probably be helpful also as it provides dense 3d face landmarks with 3D face models, UV visualization, coordinates. This is a discussion 用于 Mediapipe 中面部的 UV 展开。
示例来自,https://github.com/YadiraF/DECA。
示例来自,https://github.com/sicxu/Deep3DFaceRecon_pytorch。
GAN
另一种方法是使用 GAN 来编辑面部特征、应用灯光、化妆等