You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用OpenCV检测面部痘痘?新手遇识别难题求技术指导

面部痘痘检测标记优化方案与入门指导

一、先搞定面部区域精准隔离(解决误标嘴唇问题)

你之前用MediaPipe Face Mesh裁剪效果差,是没利用它的关键点生成精准掩码。正确步骤:

  • 用MediaPipe Face Mesh检测面部468个关键点,提取面部轮廓的关键点集合(比如下巴、脸颊、额头的特征点)
  • 将这些点转换成闭合多边形,生成仅覆盖面部的掩码,再减去嘴唇区域的掩码,直接排除嘴唇、头发等非目标区域

二、适配深色皮肤的颜色特征选择

HSV对深色皮肤的红色区分度差,换成Lab颜色空间更适配肤色分析:

  • Lab的a通道代表红绿色差,痘痘在a通道会呈现明显偏红特征;结合L通道(亮度)区分痘痘和斑点——痘痘与周围皮肤有明显亮度差,斑点颜色则更均匀
  • 不要单靠颜色,结合纹理特征:痘痘有凸起、边缘清晰,用Canny边缘检测或局部方差筛选有纹理的区域,过滤平滑的斑点

三、区分痘痘与斑点/嘴唇的具体方法

  • 排除嘴唇:用MediaPipe Face Mesh的嘴唇外围关键点生成掩码,从面部区域中直接减去这部分
  • 过滤斑点:用形态学开运算(先腐蚀再膨胀)去掉细小斑点;或通过轮廓面积、圆度筛选——痘痘轮廓通常更不规则,面积比斑点更大

四、改进后的代码示例

import cv2
import numpy as np
import mediapipe as mp

# 初始化MediaPipe Face Mesh
mp_face_mesh = mp.solutions.face_mesh
face_mesh = mp_face_mesh.FaceMesh(static_image_mode=True, max_num_faces=1, refine_landmarks=True)

def get_face_mask_without_lip(image):
    h, w = image.shape[:2]
    rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    results = face_mesh.process(rgb_image)
    
    face_mask = np.zeros((h, w), dtype=np.uint8)
    lip_mask = np.zeros((h, w), dtype=np.uint8)
    
    if results.multi_face_landmarks:
        for face_landmarks in results.multi_face_landmarks:
            # 提取面部轮廓关键点索引集合
            face_contour_indices = [10,338,297,332,284,251,389,356,454,323,361,288,397,365,379,378,400,377,152,148,176,149,150,136,172,58,132,93,234,127,162,21,54,103,67,109]
            face_points = np.array([(int(landmark.x*w), int(landmark.y*h)) for landmark in [face_landmarks.landmark[i] for i in face_contour_indices]], np.int32)
            cv2.fillPoly(face_mask, [face_points], 255)
            
            # 提取嘴唇外围关键点索引集合
            lip_contour_indices = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
            lip_points = np.array([(int(landmark.x*w), int(landmark.y*h)) for landmark in [face_landmarks.landmark[i] for i in lip_contour_indices]], np.int32)
            cv2.fillPoly(lip_mask, [lip_points], 255)
    
    # 面部掩码减去嘴唇掩码,得到仅保留非嘴唇面部区域的掩码
    return cv2.subtract(face_mask, lip_mask)

# 读取图片
image = cv2.imread('./acne.jpeg')
h, w = image.shape[:2]

# 获取过滤嘴唇后的面部掩码
face_mask = get_face_mask_without_lip(image)

# 转换到Lab颜色空间分析
lab_image = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
l_channel, a_channel, b_channel = cv2.split(lab_image)

# 筛选a通道偏红区域(痘痘特征)+ L通道亮度差异区域
a_thresh = cv2.inRange(a_channel, 130, 170)  # 可根据不同肤色调整阈值
l_thresh = cv2.inRange(l_channel, 50, 200)
color_candidate = cv2.bitwise_and(a_thresh, l_thresh)

# 用面部掩码过滤,仅保留面部区域的候选
candidate_mask = cv2.bitwise_and(color_candidate, color_candidate, mask=face_mask)

# 形态学操作:去小斑点+填补痘痘空隙
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
processed_mask = cv2.morphologyEx(candidate_mask, cv2.MORPH_OPEN, kernel, iterations=1)
processed_mask = cv2.morphologyEx(processed_mask, cv2.MORPH_CLOSE, kernel, iterations=2)

# 查找轮廓并筛选痘痘
contours, _ = cv2.findContours(processed_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
result_image = image.copy()

for cnt in contours:
    area = cv2.contourArea(cnt)
    # 过滤太小的斑点,面积阈值根据图片分辨率调整
    if 10 < area < 200:
        x, y, cnt_w, cnt_h = cv2.boundingRect(cnt)
        cv2.rectangle(result_image, (x,y), (x+cnt_w, y+cnt_h), (0,0,255), 2)

# 显示结果
cv2.imshow('Original', image)
cv2.imshow('Processed Mask', processed_mask)
cv2.imshow('Pimple Detection Result', result_image)

cv2.waitKey(0)
cv2.destroyAllWindows()

五、后续优化方向

  • 机器学习进阶:收集不同肤色的痘痘标注图片,用YOLO、轻量CNN等模型训练,比传统图像处理鲁棒性强很多
  • 自适应阈值:用Otsu二值化代替固定阈值,针对不同肤色自动调整参数
  • 纹理特征强化:加入局部二值模式(LBP)提取痘痘纹理,结合颜色特征提升准确率

内容的提问来源于stack exchange,提问作者vmin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 08:37:18