如何优化手部图像阈值分割效果?解决光照不均问题
手部阈值分割优化与光照不均修复方案
问题描述
尝试对某手部图像进行阈值分割,使用代码如下:
img = cv2.GaussianBlur(crop_img,(25,25),0) img_YCrCb = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb) #skin color range for hsv color space YCrCb_mask = cv2.inRange(img_YCrCb, (0, 135, 85), (255,180,135)) YCrCb_mask = cv2.morphologyEx(YCrCb_mask, cv2.MORPH_CLOSE, np.ones((3,3), np.uint8)) thresh = cv2.morphologyEx(YCrCb_mask, cv2.MORPH_OPEN, np.ones((3,3), np.uint8)) #morphological operation to close -in the vertical direction- the gaps due to accessories morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 31)))
该代码在其他测试案例中表现良好,但在目标图像上的阈值分割结果存在手指分割不完整的问题,需优化阈值分割以完整分割所有手指,或检测并修复光照不均问题。
优化方案
1. 修复光照不均问题
光照不均是导致部分手指区域肤色阈值不匹配的核心原因,可通过以下方法处理:
- 自适应阈值分割:替换全局阈值为自适应阈值,针对Cr分量单独处理局部光照差异:
# 提取YCrCb中的Cr分量 cr_channel = img_YCrCb[:,:,1] # 高斯加权自适应阈值,适配局部光照 adaptive_thresh = cv2.adaptiveThreshold(cr_channel, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) - CLAHE光照补偿:对Y通道做限制对比度自适应直方图均衡,抑制过曝区域同时增强暗部细节:
# 拆分YCrCb通道 y_channel, cr_channel, cb_channel = cv2.split(img_YCrCb) # 初始化CLAHE clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) # 增强Y通道对比度 y_channel_clahe = clahe.apply(y_channel) # 合并处理后的通道 img_YCrCb_clahe = cv2.merge((y_channel_clahe, cr_channel, cb_channel)) # 基于增强后的图像重新生成肤色掩码 YCrCb_mask = cv2.inRange(img_YCrCb_clahe, (0, 135, 85), (255,180,135))
2. 优化肤色阈值范围
原固定阈值无法适配光照变化区域,可调整阈值范围或结合多通道校验:
- 放宽Cr通道下限,适配较亮区域的肤色:
# 调整YCrCb肤色范围,降低Cr通道下限以覆盖亮部肤色 YCrCb_mask = cv2.inRange(img_YCrCb, (0, 120, 70), (255,180,135)) - 结合HSV通道做掩码与运算,提升肤色区域判断精度:
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # HSV肤色范围 hsv_mask = cv2.inRange(img_hsv, (0, 40, 80), (20, 255, 255)) # 合并YCrCb与HSV掩码,保留共同肤色区域 combined_mask = cv2.bitwise_and(YCrCb_mask, hsv_mask)
3. 优化形态学操作
调整形态学核的尺寸与方向,针对性填补手指区域空隙:
- 先做开运算去噪,再结合水平、垂直方向的椭圆核补全手指空隙:
# 用大尺寸开运算去除细碎噪点 thresh = cv2.morphologyEx(YCrCb_mask, cv2.MORPH_OPEN, np.ones((5,5), np.uint8)) # 水平椭圆核补全手指横向空隙 morph_h = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (31, 11))) # 垂直椭圆核补全手指纵向空隙 morph_final = cv2.morphologyEx(morph_h, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 31)))
4. 轮廓后处理补全缺失区域
若仍有手指区域缺失,可通过轮廓分析补全:
- 提取手部最大轮廓并生成凸包,填充凸包内的空隙:
contours, _ = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if contours: # 提取面积最大的轮廓(对应手部区域) max_contour = max(contours, key=cv2.contourArea) # 生成轮廓凸包 hull = cv2.convexHull(max_contour) # 创建凸包掩码 hull_mask = np.zeros_like(morph) cv2.drawContours(hull_mask, [hull], 0, 255, -1) # 合并原掩码与凸包掩码,补全手指空隙 final_mask = cv2.bitwise_or(morph, hull_mask)
内容的提问来源于stack exchange,提问作者SpiritedAwayCat
相关产品推荐
相关产品推荐

