如何使用 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 可能会提供不错的结果,而无需使用其他方法。如果它影响更大的区域,它也有可能会明显扭曲眼镜。这些应该有所帮助,


我不确定如何单独在 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.