基于Python与OpenCV定位毛巾最低边角的最优方法咨询
嘿,结合你说的背景颜色固定、毛巾颜色可变的情况,我给你一套亲测有效的最优方案,步骤清晰还鲁棒:
最优解决方案:基于固定背景的毛巾边角定位
核心思路
因为背景颜色始终一致,我们可以先精准分割出毛巾区域,再通过轮廓/凸包分析定位最低边角,完全不受毛巾颜色变化影响。
具体步骤
1. 背景分割(提取毛巾区域)
先把图像转成HSV色彩空间(比RGB更适合颜色阈值分割),然后利用固定背景的颜色特征,创建掩码分离出毛巾:
- 取图像中纯背景区域(比如左上角)计算平均HSV值,设置合理的容差范围;
- 用
cv2.inRange()生成背景掩码,再取反得到毛巾区域的掩码。
2. 掩码优化(去除噪点)
毛巾边缘可能有毛躁或小空隙,用形态学操作处理掩码:
- 闭操作(先膨胀后腐蚀)填充毛巾内部的小空隙;
- 开操作(先腐蚀后膨胀)去掉背景中的小噪点。
3. 轮廓提取与筛选
用cv2.findContours()提取掩码中的轮廓,然后筛选出面积最大的轮廓(就是毛巾本身,排除其他小干扰)。
4. 定位最低边角
这里推荐两种方法,按需选择:
- 方法一:遍历轮廓点:直接遍历轮廓所有点,找到y坐标最大的点(图像坐标系y轴向下,y越大越靠下);如果有多个y值相同的点,取x最大的那个(对应示例中的右下角边角)。
- 方法二:凸包极值点:先对轮廓求凸包,凸包能忽略毛巾褶皱的凹点,更精准定位边角;然后找到凸包中y坐标最大的点,就是我们要的最低边角。
完整代码示例
import cv2 import numpy as np # 读取图像 img = cv2.imread('towel.jpg') hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 步骤1:获取背景HSV范围(以左上角背景区域为例) bg_area = hsv_img[0:50, 0:50] # 取左上角50x50的纯背景区域 bg_h, bg_s, bg_v = np.mean(bg_area, axis=(0, 1)) # 设置颜色容差,可根据实际情况调整 lower_bg = np.array([bg_h - 10, bg_s - 30, bg_v - 30]) upper_bg = np.array([bg_h + 10, bg_s + 30, bg_v + 30]) # 创建毛巾掩码(非背景区域) bg_mask = cv2.inRange(hsv_img, lower_bg, upper_bg) towel_mask = cv2.bitwise_not(bg_mask) # 步骤2:形态学优化掩码 kernel = np.ones((5, 5), np.uint8) towel_mask = cv2.morphologyEx(towel_mask, cv2.MORPH_CLOSE, kernel) # 填充空隙 towel_mask = cv2.morphologyEx(towel_mask, cv2.MORPH_OPEN, kernel) # 去除噪点 # 步骤3:提取并筛选毛巾轮廓 contours, _ = cv2.findContours(towel_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) towel_contour = max(contours, key=cv2.contourArea) # 取面积最大的轮廓 # 步骤4:定位最低边角(推荐凸包方法) hull = cv2.convexHull(towel_contour) max_y_index = np.argmax(hull[:, 0, 1]) # 找到y最大的点索引 target_corner = tuple(hull[max_y_index][0]) # 标记目标点 cv2.circle(img, target_corner, 6, (0, 0, 255), -1) # 红色实心圆标记 cv2.imshow('Target Corner', img) cv2.waitKey(0) cv2.destroyAllWindows()
注意事项
- 如果背景颜色有轻微光影变化,可适当调大HSV的容差范围(比如把10改成15,30改成40);
- 形态学核的大小可以根据图像分辨率调整,比如分辨率高就用(7,7)的核;
- 如果毛巾和背景颜色非常接近,可尝试先做边缘检测(
cv2.Canny())再提取轮廓,同样能得到不错的效果。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

