opencv 如何检测图像中具有特定宽度值的正方形,并检查圆内两条线的交点?

ajsxfq5m  于 2023-08-06  发布在  其他
关注(0)|答案(1)|浏览(110)

我想使用PythonOpenCV库执行图像处理并检测图像中的正方形。正方形具有一定的宽度,但具体宽度值未知。然后我想画一个圆,以正方形的中心为圆心,半径等于中心到正方形轮廓线距离的四倍。图像中有两条相交的线,它们的位置并不固定。线的清晰度在不同的图像中可以变化。你可以注意到图像上有很多噪点,不同图像的亮度水平也不一致。**如何确定两条直线的交点是否福尔斯圆内?**红色箭头表示下图中两条线的交点。


我使用了4张图片进行测试。目前,我将彩色图像转换为灰度,应用高斯模糊,使用Canny算法进行边缘检测,然后进行轮廓检测。我面临的问题是,由于正方形的宽度,有些图像的正方形轮廓画在正方形的外面,有些画在正方形的里面,有些既有内部轮廓又有外部轮廓。如何更新算法以仅绘制外轮廓?我已经尝试过调整cv2.Canny(blur, 50, 100)中的值,但很难找到一组适用于所有图像的值。而cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE),如果将cv2.RETR_TREE改为cv2.EXTERNAL,则找不到圆心和圆。
期待收到您的一些有用的建议。
用于测试的4个图像如下所示。
Pic_1:

Pic_2:

图片_3:

图片_4:


Python代码如下。

import cv2
import glob
import os
import numpy as np

def detect_squares(img_path):
    
    file_name = os.path.basename(img_path)
    
    # Read the image and create a copy for drawing results
    img = cv2.imread(img_path)
    image_with_rectangles = img.copy()

    # Convert to grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    # Apply Gaussian blur
    blur = cv2.GaussianBlur(gray, (5, 5), 0)
    # Perform edge detection
    edges = cv2.Canny(blur, 50, 100)

    # Find contours
    contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

    # Traverse through the detected contours
    for contour in contours:
        # Calculate contour perimeter
        perimeter = cv2.arcLength(contour, True)
        # Get the coordinates of contour vertices
        approx = cv2.approxPolyDP(contour, 0.04 * perimeter, True)
        # Get the coordinate values, width, and height
        x, y, w, h = cv2.boundingRect(approx)
        # Classify the contour
        if len(approx) == 4 and perimeter >= 350 and 0.9 <= float(w) / h <= 1.1:

            # Draw red contour lines
            cv2.drawContours(image_with_rectangles, contour, -1, (0, 0, 255), cv2.FILLED)
    
            # Calculate contour moments
            M = cv2.moments(contour)

            # Calculate the centroid coordinates of the contour
            if M["m00"] != 0:
                center_x = int(M["m10"] / M["m00"])
                center_y = int(M["m01"] / M["m00"])
                center = (center_x, center_y)

                # Draw the center point on the image
                cv2.circle(image_with_rectangles, center, 5, (0, 255, 255), 3)

                # Calculate the distance from the center to the square contour
                distance = int(cv2.pointPolygonTest(approx, center, True))

                # Calculate the radius of the circle
                radius = 4 * distance

                # Draw the circle
                cv2.circle(image_with_rectangles, (center_x, center_y), radius, (0, 255, 255), 2)

    # Show the resulting image
#     cv2.imshow(f"Canny Detection - {file_name}", edges)
    cv2.imshow(f"Shape Detection - {file_name}", image_with_rectangles)

    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
detect_squares(image_path)

字符串

gc0ot86w

gc0ot86w1#

由于正方形是图像中唯一完全封闭的形状(除了数字中的零),因此它们是唯一的地方,如果您进行泛色填充,您将不会填充(几乎)整个图像。因此,您可以从图像的中心或最亮的点开始,进行泛洪填充,直到您获得泛洪填充区域的正确形状/大小。你不需要在每一个像素点上进行泛色填充,只要在正方形边长的80%处使用中心即可。或者,如果你正常化的照明,你可以填补从一个边缘和你的广场将是唯一剩下的未填补的形状。
因此,照明的除法归一化给出了:
x1c 0d1x的数据
我用ImageMagick这样做:

magick INPUT.JPG \( +clone -blur 0x19 \) +swap -compose divide -composite  -threshold 90% result.jpg

字符串
但是Fred@fmw42给出了一个Python版本here
然后你可以做一个flood-fill --我也是用ImageMagick做的,但是OpenCV也有类似的功能。如果你用红色填充,从[1350,950]开始,你会得到:



如果你从[1300,900]开始泛洪填充,你会得到:



注意,我使用红色只是为了说明的目的--没有必要引入第三个通道,也没有必要将真实的应用中的内存和处理需求增加三倍。由于图像的阈值已经设置为纯黑色和白色,因此您可以使用中间灰色或类似的填充颜色。

相关问题