OpenCV叠加人脸照片到相框时眼镜被误识别为背景如何解决
人脸叠加相框时眼镜区域被误识别为背景
问题描述
- 实现功能:编写代码将人脸照片叠加到相框
- 异常现象:运行时眼镜区域被误识别为背景,叠加后眼镜区域透明缺失
- 待叠加原始人脸图:

- 实际错误叠加结果:

- 初步排查:问题与alpha通道透明度处理逻辑相关,当前问题代码如下:
def fourChannels(img): height, width, channels = img.shape if channels < 4: new_img = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA) return new_img def transBg(img): gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) th, threshed = cv2.threshold(gray, 187, 255, cv2.THRESH_BINARY_INV) # threshed= cv2.adaptiveThreshold(gray, 300, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11)) morphed = cv2.morphologyEx(threshed, cv2.MORPH_OPEN, kernel) roi, _ = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) mask = np.zeros(img.shape, img.dtype) cv2.fillPoly(mask, roi, (255,)*img.shape[2], ) masked_image = cv2.bitwise_and(img, mask) # masked_image = cv2.bitwise_and(img,dilated_img) return masked_image
问题原因
现有代码的核心问题是使用了全局固定阈值二值化做前景分割:灰度值高于187的像素会被直接判定为背景,眼镜镜片透光率高、灰度值刚好超过该阈值,被直接标记为背景区域。后续的外轮廓填充逻辑只会填充轮廓外部区域,镜片位置被扣出的内部空洞不会被补全,最终叠加时就会出现眼镜区域透明的问题。
另外原代码没有正确写入alpha通道值,仅做了色彩域与运算,叠加时容易出现边缘硬边异常。
修复方案
替换全局固定阈值逻辑为GrabCut前景分割算法,对高透、高反光的眼镜区域识别准确率更高,同时补全alpha通道赋值逻辑:
import cv2 import numpy as np def fourChannels(img): height, width, channels = img.shape if channels < 4: new_img = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA) return new_img return img def transBg(img): img = fourChannels(img) h, w = img.shape[:2] # 初始化GrabCut算法所需参数 mask = np.zeros((h, w), np.uint8) bg_model = np.zeros((1, 65), np.float64) fg_model = np.zeros((1, 65), np.float64) # 框选人脸所在的大致前景区域,留5px边距避免裁切边缘 fg_rect = (5, 5, w - 10, h - 10) cv2.grabCut(img, mask, fg_rect, bg_model, fg_model, 5, cv2.GC_INIT_WITH_RECT) # 合并确定前景、疑似前景区域为最终可见掩码 fg_mask = np.where((mask == 0) | (mask == 2), 0, 255).astype(np.uint8) # 小尺寸闭运算补全掩码内的细小空洞,平滑边缘 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) fg_mask = cv2.morphologyEx(fg_mask, cv2.MORPH_CLOSE, kernel, iterations=2) # 写入alpha通道 img[:, :, 3] = fg_mask return img
调参说明
- 如果输入图片的人脸没有占满画幅,调整
fg_rect的坐标参数,确保完整人脸被框入矩形区域即可 - 如果边缘存在细小白边,可以将形态学核大小调整为(5,5),不要使用过大的核,避免边缘模糊发虚
内容的提问来源于stack exchange,提问作者kodeinoslave
相关产品推荐
相关产品推荐

