如何使用OpenCV与dlib实现人脸五官(鼻子、眼睛等)的缩放调整
你当前代码存在3个核心问题导致无法正确实现局部缩放:
- 条件判断逻辑错误:原判断式
name != "Jaw" and name == "Left_Eye" or name == "Nose"冗余且存在逻辑优先级隐患,直接判断目标区域即可 - 仿射变换矩阵宽高维度搞反:OpenCV读取的图像
shape返回顺序是(高度, 宽度, 通道数),你计算偏移时把宽高的对应参数写反了,导致缩放后区域错位 - 直接替换矩形区域会出现硬边缘:没有用五官凸包做遮罩,缩放后会导致周围皮肤区域被拉伸变形,拼接痕迹明显
修改后的完整代码如下:
import cv2 import numpy as np # 需提前定义好FACIAL_LANDMARKS_INDEXES和facial_features_cordinates变量 def visualize_facial_landmarks(image, shape, colors=None, alpha=0.75, scale=2): overlay = image.copy() output = image.copy() 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)] for (i, name) in enumerate(FACIAL_LANDMARKS_INDEXES.keys()): (j, k) = FACIAL_LANDMARKS_INDEXES[name] pts = shape[j:k] facial_features_cordinates[name] = pts # 仅处理左眼和鼻子区域 if name in ("Left_Eye", "Nose"): minX = int(min(pts[:,0])) maxX = int(max(pts[:,0])) minY = int(min(pts[:,1])) maxY = int(max(pts[:,1])) # 截取五官局部区域 tmp = overlay[minY:maxY, minX:maxX, :].copy() h, w = tmp.shape[:2] # 修正仿射矩阵,以区域中心为基准做缩放 cx = w / 2.0 cy = h / 2.0 M = np.array([ [scale, 0, cx - scale * cx], [0, scale, cy - scale * cy] ], dtype=np.float32) tmp = cv2.warpAffine(tmp, M, (w, h)) # 生成五官凸包遮罩,仅替换五官区域不影响周围皮肤 local_pts = pts - [minX, minY] hull = cv2.convexHull(local_pts.astype(np.int32)) mask = np.zeros_like(tmp, dtype=np.uint8) cv2.fillConvexPoly(mask, hull, (255,255,255)) # 把缩放后的五官融合到原图 overlay[minY:maxY, minX:maxX] = np.where(mask == 255, tmp, overlay[minY:maxY, minX:maxX]) # 可选alpha融合,让效果更自然 cv2.addWeighted(overlay, alpha, output, 1 - alpha, 0, output) return output
使用说明:
- 调整参数
scale即可控制缩放效果,大于1为放大,小于1为缩小 - 调整
alpha参数可以控制缩放后五官和原图的融合程度,数值越低效果越自然
示例人脸图像:
内容的提问来源于stack exchange,提问作者Emad Kebriaei
相关产品推荐
相关产品推荐

