如何裁剪或叠加人脸面罩图像的多边形区域以匹配输出规格
人脸面罩图像处理方案
需求说明
共有3张样本图像用于参考,需将输入的人脸面罩图像处理为指定的输出形态:
- 样本输入图像:

- 上色后的输入图像:

- 样本输出图像:

原有方案问题
此前采用固定阈值二值化+面积阈值筛选轮廓的处理逻辑,未能得到预期输出,原有实现代码如下:
import cv2 import matplotlib.pyplot as plt face_mask = cv2.imread('data/mask5.png') face_mask = cv2.cvtColor(face_mask, cv2.COLOR_BGR2RGB) gray_mask = cv2.cvtColor(face_mask, cv2.COLOR_RGB2GRAY) # 二值化阈值处理 _, binary = cv2.threshold(gray_mask, 225, 255, cv2.THRESH_BINARY_INV) contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) contour_list = [] for c in contours: area = cv2.contourArea(c) if area > 2000: print(area) contour_list.append(c) # 绘制轮廓 img = cv2.drawContours(face_mask, contour_list, -1, (0, 255, 0), 2) plt.imshow(img) plt.show()
原有方案的核心问题是固定灰度阈值二值化受光照、背景干扰影响大,仅靠面积筛选轮廓无法排除背景中大块的非面罩区域,无法精准定位面罩范围。
最优处理方案
推荐采用颜色空间分割+形态学预处理+多条件轮廓筛选的组合方案,处理步骤如下:
- 颜色空间转换:将原图从RGB转为HSV颜色空间,根据面罩的颜色范围设置阈值生成初始掩码,相比灰度二值化能精准区分面罩、人脸皮肤和背景区域。
- 掩码优化:对初始掩码做开运算+闭运算的形态学处理,消除小噪点、填补面罩区域的空洞,得到完整的掩码区域。
- 多条件轮廓筛选:对优化后的掩码提取轮廓,除了面积阈值,额外增加外接矩形宽高比的筛选条件,排除背景中符合面积但不符合面罩形态的干扰轮廓。
- 输出裁剪:取筛选后的最大轮廓的外接矩形,裁剪原图对应区域后,用掩码将区域外的背景替换为白色/透明,得到和样本一致的输出。
优化后实现代码
import cv2 import numpy as np import matplotlib.pyplot as plt face_mask = cv2.imread('data/mask5.png') face_mask_rgb = cv2.cvtColor(face_mask, cv2.COLOR_BGR2RGB) hsv = cv2.cvtColor(face_mask_rgb, cv2.COLOR_RGB2HSV) # 面罩颜色阈值(可根据实际样本调整HSV范围,这里以上色后的蓝色面罩为例) lower_mask = np.array([90, 50, 50]) upper_mask = np.array([130, 255, 255]) # 生成初始掩码 mask = cv2.inRange(hsv, lower_mask, upper_mask) # 形态学处理优化掩码 kernel = np.ones((5,5), np.uint8) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 提取轮廓 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 多条件筛选轮廓 max_contour = None max_area = 0 for c in contours: area = cv2.contourArea(c) if area < 2000: continue x,y,w,h = cv2.boundingRect(c) aspect_ratio = w / h # 面罩宽高比范围可根据样本调整 if 1.2 <= aspect_ratio <= 2.5 and area > max_area: max_area = area max_contour = c # 裁剪输出 if max_contour is not None: x,y,w,h = cv2.boundingRect(max_contour) output = face_mask_rgb[y:y+h, x:x+w] # 可选:将区域外背景设为白色 output_mask = mask[y:y+h, x:x+w] output[output_mask == 0] = [255,255,255] plt.imshow(output) plt.axis('off') plt.show()
内容的提问来源于stack exchange,提问作者Ankit Kumar
相关产品推荐
相关产品推荐

