numpy python cv2形状识别代码

fsi0uk1n  于 9个月前  发布在  Python
关注(0)|答案(1)|浏览(116)

我的代码有问题,它应该得到两行输入,第一行是图像中有多少个形状,第二行是图像路径。
输出应该是形状类型的数量,例如输入:有一个test1.jpg图像,其中有10个圆圈,输出应该是:1
我的代码写在这里:

import cv2
import numpy as np

num_shapes = int(input("Enter the number of shapes in the image: "))
image_path = input("Enter the path to the image: ")

image = cv2.imread(image_path)

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

filtered_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > 100]

num_detected_shapes = len(filtered_contours)

print("Detected shapes:", num_detected_shapes)

字符串
但对于这张图片:


的数据
它给出的输出是1。
为什麽?

cgvd09ve

cgvd09ve1#

您的图像对比度非常差,背景值非常高。强调背景和形状之间差异的一种方法是使用大津阈值而不是二进制:

ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_OTSU)

字符串
之后,您需要反转二进制掩码,因为在您的情况下,最高值是背景而不是形状。

inv_binary = cv2.bitwise_not(binary)


之后,最好通过检查和阈值化来引入一些对比:

kernel = 255*np.ones((10, 10), np.uint8) # dilate the binary mask, here and next line
dilated_binary = cv2.dilate(gray, kernel, iterations=1)

mask = cv2.dilate((dilated_binary < 245).astype(np.uint8)*255, kernel, iterations=1) # create another binary mask where the values are lower than 245, here I did some manual checking

contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # find the contour on the mask

filtered_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > 100] # filter the contours

num_detected_shapes = len(filtered_contours)
print("Detected shapes:", num_detected_shapes)

Results -> Detected shapes: 8


这也是轮廓的图像:


的数据

V2.0:增加形状计数

要识别轮廓的类型,您可以使用cv2.approxPolyDP来近似形状。这个想法是在之后计算顶点:

circles = 0 
triangles = 0 
rectangles = 0  
for contour in filtered_contours:
        M = cv2.moments(contour)
        if M["m00"] != 0:
            cx = int(M["m10"] / M["m00"])
            cy = int(M["m01"] / M["m00"])
        # approximate the contour
        epsilon = 0.04 * cv2.arcLength(contour, True)
        approx = cv2.approxPolyDP(contour, epsilon, True)
        # number of sides
        num_vertices = len(approx)
        # see how many sides and decide which shape
        if num_vertices == 3:
            shape = "Triangle"
            triangles += 1
        elif num_vertices == 4:
            shape = "Rectangle"
            rectangles += 1
        else: # in this case I just put the default as a circle, since there are currently no other options.
            shape = "Circle"
            circles += 1
        plt.text(cx, cy, shape)


之后,这里是总结:

print("Summary:") 
print("Rects or squares: "+str(rectangles)) 
print("Triangles: "+str(triangles))
print("Circles: "+str(circles))


这将给予以下内容:

Summary:
Rects or squares: 3
Triangles: 3
Circles: 2


相关问题