Python OpenCV提取白色区域轮廓:单个闭合图形中心坐标异常问题
问题
正在学习Python和OpenCV,尝试通过轮廓定位图像中每个闭合白色形状的中心。但运行代码后,每个形状会得到多组cx、cy坐标,部分中心未处于形状真正中心,还存在多余点。怀疑轮廓算法识别了图像中的线条,尝试通过筛选白色区域排除线条,但不确定该方法是否正确。
附相关内容
原代码
import os import cv2 as cv import numpy as np from IPython.display import Image as IPImage, display def extract_color_code(image, x, y): color = image[y, x] r, g, b = color return '#{:02x}{:02x}{:02x}'.format(b, g, r) def generate_X_Y(image_path): image = cv.imread(image_path) gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(gray, 128, 255, cv.THRESH_BINARY_INV) cv.imwrite("image2.jpg", thresh) contours, hierarchies = cv.findContours(thresh, cv.RETR_CCOMP, cv.CHAIN_APPROX_SIMPLE) hierarchies = hierarchies[0] blank = np.zeros(thresh.shape[:2], dtype='uint8') for i, (contour, hierarchy) in enumerate(zip(contours, hierarchies)): if hierarchy[2] == -1 and hierarchy[3] != -1: # Check if it is not an inner part of a contour M = cv.moments(contour) if M['m00'] != 0: cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) color = extract_color_code(image, cx, cy) #if str(color) == '#ffffff': cv.drawContours(image, [contour], -1, (0, 255, 0), 2) cv.circle(image, (cx, cy), 3, (0, 0, 255), -1) #cv.putText(image, "center", (cx - 20, cy - 20), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 2) cv.imwrite("image.png", image) display(IPImage("image.png")) # Display the image in Colab if __name__ == '__main__': image_path = '/content/pic_24.png' # Provide the correct path in Colab generate_X_Y(image_path)
输入图像

结果图像

解决方案
问题根源
- 轮廓检索模式
cv.RETR_CCOMP会检测所有层级的轮廓,加上当前的层级判断,误将线条边缘、内部小轮廓当成了目标闭合区域。 - 未过滤小面积轮廓,导致噪点、线条这类非目标区域被识别为有效轮廓。
- 固定阈值
128可能无法精准区分白色闭合区域和线条,造成阈值处理后线条残留。
修改后的代码
import os import cv2 as cv import numpy as np from IPython.display import Image as IPImage, display def extract_color_code(image, x, y): color = image[y, x] r, g, b = color return '#{:02x}{:02x}{:02x}'.format(b, g, r) def generate_X_Y(image_path): image = cv.imread(image_path) gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) # 改用自适应阈值,更好区分白色区域和线条 thresh = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, 11, 2) # 只检测最外层轮廓,避免内部干扰 contours, _ = cv.findContours(thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) # 设置面积阈值,过滤线条、噪点等小轮廓(可根据实际图像调整) MIN_AREA = 500 for contour in contours: area = cv.contourArea(contour) if area < MIN_AREA: continue M = cv.moments(contour) if M['m00'] != 0: cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) color = extract_color_code(image, cx, cy) # 验证中心是否在白色区域内 if color == '#ffffff': cv.drawContours(image, [contour], -1, (0, 255, 0), 2) cv.circle(image, (cx, cy), 3, (0, 0, 255), -1) cv.imwrite("image.png", image) display(IPImage("image.png")) if __name__ == '__main__': image_path = '/content/pic_24.png' generate_X_Y(image_path)
关键修改说明
- 轮廓检索模式:改用
cv.RETR_EXTERNAL只提取最外层轮廓,直接排除内部小轮廓的干扰。 - 面积过滤:通过
cv.contourArea计算轮廓面积,设置最小面积阈值(示例为500),过滤掉线条、噪点这类小区域。 - 阈值优化:使用
cv.adaptiveThreshold自适应阈值,根据局部区域调整阈值,比固定阈值更适合区分复杂背景下的白色闭合区域。 - 颜色验证:启用你之前注释的颜色筛选逻辑,确保计算出的中心确实位于白色区域内,进一步排除错误点。
内容的提问来源于stack exchange,提问作者Mark Pole
相关产品推荐
相关产品推荐

