如何使用OpenCV与Python检测图像中的白色区域?
解决盘子中大型白色区域的坐标提取问题
你的预处理流程(放大、灰度转换、形态学闭运算填充孔洞、OTSU二值化)已经为后续的区域检测打下了不错的基础,轮廓检测效果不理想大概率是因为没有对检测到的轮廓做针对性筛选,或者可以换用连通区域分析的方法来更精准地定位大型白色区域。
方法一:优化轮廓检测与筛选
既然已经得到了二值化后的light图像,我们可以通过轮廓检测结合面积、形状筛选来锁定目标区域:
import cv2 import numpy as np import imutils original = cv2.imread("Plates\24.png") original = cv2.resize(original, None, fx=3, fy=3, interpolation=cv2.INTER_CUBIC) gray = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY) # 形态学闭运算填充孔洞 squareKern = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) light = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, squareKern) # OTSU二值化 light = cv2.threshold(light, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] # 检测轮廓,只保留最外层轮廓避免干扰 cnts = cv2.findContours(light.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = imutils.grab_contours(cnts) # 筛选大型白色区域:根据实际场景调整面积阈值 large_white_regions = [] for c in cnts: area = cv2.contourArea(c) # 假设最小有效面积是1000像素(根据你的图像尺寸调整) if area > 1000: # 获取区域的外接矩形坐标 x, y, w, h = cv2.boundingRect(c) large_white_regions.append((x, y, x+w, y+h)) # 可选:在原图上绘制矩形验证结果 cv2.rectangle(original, (x, y), (x+w, y+h), (0, 255, 0), 2) # 输出大型白色区域的坐标 for idx, coords in enumerate(large_white_regions): print(f"大型白色区域 {idx+1} 坐标:左上角({coords[0]}, {coords[1]}),右下角({coords[2]}, {coords[3]})") # 展示处理后的图像 cv2.imshow("Detected Regions", original) cv2.waitKey(0) cv2.destroyAllWindows()
关键优化点:
- 使用
cv2.RETR_EXTERNAL只检测最外层轮廓,避免内部小轮廓干扰 - 通过
cv2.contourArea()过滤掉面积过小的区域,只保留符合"大型"要求的目标 - 用
cv2.boundingRect()获取区域的矩形坐标,方便后续调用使用
方法二:连通区域分析(更精准的区域定位)
如果轮廓筛选还是达不到预期,可以尝试用连通区域分析(cv2.connectedComponentsWithStats),它能直接给出每个连通区域的面积、坐标等统计信息,逻辑更清晰:
import cv2 import numpy as np import imutils original = cv2.imread("Plates\24.png") original = cv2.resize(original, None, fx=3, fy=3, interpolation=cv2.INTER_CUBIC) gray = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY) squareKern = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) light = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, squareKern) light = cv2.threshold(light, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] # 连通区域分析,8邻域连通 num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(light, connectivity=8) large_white_regions = [] # 跳过标签0(代表背景区域) for i in range(1, num_labels): area = stats[i, cv2.CC_STAT_AREA] if area > 1000: # 根据图像实际尺寸调整面积阈值 x = stats[i, cv2.CC_STAT_LEFT] y = stats[i, cv2.CC_STAT_TOP] w = stats[i, cv2.CC_STAT_WIDTH] h = stats[i, cv2.CC_STAT_HEIGHT] large_white_regions.append((x, y, x+w, y+h)) cv2.rectangle(original, (x, y), (x+w, y+h), (0, 0, 255), 2) # 输出大型白色区域的坐标 for idx, coords in enumerate(large_white_regions): print(f"大型白色区域 {idx+1} 坐标:左上角({coords[0]}, {coords[1]}),右下角({coords[2]}, {coords[3]})") cv2.imshow("Connected Components", original) cv2.waitKey(0) cv2.destroyAllWindows()
优势:
- 能区分所有独立的连通区域,不会出现轮廓检测中可能的轮廓嵌套问题
- 直接提供区域的完整统计信息,筛选逻辑更直观
额外建议:
- 如果白色区域和盘子边缘粘连,可以先尝试用形态学开运算(
cv2.MORPH_OPEN)或者调整闭运算的核大小,分离粘连区域 - 面积阈值需要根据你放大后的图像实际尺寸调整,可以先打印所有区域的面积,找到合适的临界值
内容的提问来源于stack exchange,提问作者Yousef Hesham
相关产品推荐
相关产品推荐

