Python 仅查找轮廓白色区域 OpenCV

问题描述 投票:0回答:1

我目前正在学习Python和OpenCV,我正在尝试使用轮廓来定位图像中每个形状的中心。但是,当我实现代码时,我会为每个形状获取多个 cx 和 cy 值。理想情况下,我只需要图像中每个闭合形状的一组 cx 和 cy 坐标。我怀疑轮廓算法也在考虑图像中的线条,我想排除这些线条。为了解决这个问题,我尝试通过关注白色来过滤掉这些线条,但我不确定这是否是正确的方法。下面是我正在使用的代码片段:

import os
from PIL import Image
from xml.etree.ElementTree import Element, SubElement, tostring
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)
    blur = cv.GaussianBlur(gray, (5, 5), 0)
    ret, thresh = cv.threshold(blur, 200, 255, cv.THRESH_BINARY_INV)
    cv.imwrite("image2.jpg", thresh)
    contours, hierarchies = cv.findContours(thresh, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
    blank = np.zeros(thresh.shape[:2], dtype='uint8')
    cv.drawContours(blank, contours, -1, (255, 0, 0), 1)
    cv.imwrite("Contours.png", blank)

    zones = []
    for i in contours:
        M = cv.moments(i)
        if M['m00'] != 0:
            cx = int(M['m10'] / M['m00'])
            cy = int(M['m01'] / M['m00'])
            color = extract_color_code(image, cx, cy)
            #print(str(color))
            if str(color) == '#ffffff':
              #print(str(color))
              cv.drawContours(image, [i], -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)
              zones.append({'x': cx, 'y': cy})
              #print(f"x: {cx} y: {cy}")


    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)

输入图像

我得到以下输出,有一个我不想要的带有蓝色方块的圆圈。简而言之,我只想要每个 cx 和 cy 。

colab 链接 gcolab 分别找到 cx 和 cy

python python-3.x opencv image-processing
1个回答
0
投票

我很难理解你的代码的逻辑。因为您似乎要做的是提取轮廓(即某些区域周围的线条),然后尝试获取封闭区域的中心。但这不是轮廓。轮廓与封闭区域无关。这是关于线条的。您可能会说,很多时候都是同样的事情,但并不总是如此,正如您所看到的(有些线并不分隔区域)。

加上您以这种方式计算的中心是线的重心,而不是封闭区域的重心。根据您想要做什么,这可能并不重要(甚至可能是您想要的),但了解这一点很重要。例如,如果您的轮廓是德克萨斯州之一,则计算中心将向南移动,因为南部边界更复杂(没有关于南部边界的政治双关语,我听说这确实是一个复杂的问题)美国)比北方的。严格来说,南部沿海边界甚至是一个分形,并且具有无限的长度,因此中心的重量也是无限的。 在你的情况下,这一点更加突出,因为

approx
的事情,这会将北部直线(已经比南部分形线短)总结为只有 2 个点......

所以,如果我正确理解你的目标,我会做的就是专注于连通区域检测

# Binarisation of the image. The color we are interested in (the one of the 
# regions) is the background, 26 in your image
# *255 is just so that it is easier to visualize with any image viewer
binRaw=(img==26).astype(np.uint8)*255 
# Get the regions image (just for display), the bounding box and area (for 
# filtering) and the barycenters of each connected white (26) region
_, outImg, bb, centers = cv2.connectedComponentsWithStats(binRaw)
# Filter out the outer area (x=0) and the background area (here, background=
# contours), and the one with too small area (some isolated pixels)
mask=(bb[:,0]>0) & (bb[:,4]>10) # not touching x=0, and area>10 pixels
mask[0]=False # and we don't want the "black region" (contour)
plt.imshow((outImg*1236).astype(np.uint8), cmap=plt.cm.hsv) # Just to illustrate region separation
# Note the *1236.astype(np.uint8) is just a lazy way to pseudo-randomly shuffle the colors
plt.plot(centers[mask,0], centers[mask,1])
plt.show()

仍然不完美。因为并非所有区域都是凸面,并且非凸面区域的重心可能最终位于该区域之外(想象一下新月:中心在新月之外) 但是,我认为,根据您想要做什么,需要进行一些手动调整,或者需要更深入地重新思考您真正想要的点是什么。

© www.soinside.com 2019 - 2024. All rights reserved.