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

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)

输入图像

输入图像

结果图像

结果图像


解决方案

问题根源

  1. 轮廓检索模式cv.RETR_CCOMP会检测所有层级的轮廓,加上当前的层级判断,误将线条边缘、内部小轮廓当成了目标闭合区域。
  2. 未过滤小面积轮廓,导致噪点、线条这类非目标区域被识别为有效轮廓。
  3. 固定阈值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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 17:56:03