【问题标题】:Detect markers in 2D Image [Python/OpenCV]检测二维图像中的标记[Python/OpenCV]
【发布时间】:2023-04-09 19:19:01
【问题描述】:

我想在 Python 中创建一个脚本(使用 OpenCV 库)来确定图片中的标记。标记看起来像这样:

Markers

加载图像后,脚本应该打印图片中有哪些标记(返回标记的数量)。例如,如果我加载这张图片:

Image with markers

对于这个图像,脚本应该返回三个数字:1、2 和 3。我有一个脚本,它可以加载图像并识别数字(圆圈、正方形等 - 在脚本中只有正方形),但我不知道识别由几个数字组成的整个标记。有任何想法吗?请对算法或任何解决方案提出任何建议。

import numpy as np
import cv2

img = cv2.imread('B.jpg')
gray = cv2.imread('B.jpg',0)

ret,thresh = cv2.threshold(gray,120,255,1)

contours,h = cv2.findContours(thresh,1,2)

for cnt in contours:
    approx = cv2.approxPolyDP(cnt,0.01*cv2.arcLength(cnt,True),True)
    print len(approx)
    if len(approx)==4:
        print "square"
        cv2.drawContours(img,[cnt],0,(0,0,255))

cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

但显然这不是我需要的,它只围绕矩形。 感谢您提供任何提示和帮助。

【问题讨论】:

  • 1.找到外部轮廓。 2. 为每个轮廓选择边界框(应该与轮廓相同,因为图像中的外部轮廓是正方形) 3. 调整图像大小,使其与参考标记具有相同的大小。 4.在调整大小的图像区域和参考标记的canny边缘图像上使用倒角匹配。 5.如果一个倒角匹配足够小,则选择最小的一个作为检测标记
  • 如果您有额外的透视变形,您必须找到四边形而不是边界框并使用透视变形。
  • 我可能会尝试这里描述的特征匹配docs.opencv.org/3.1.0/d1/de0/…,但我没有得到它的工作。也看看这个帖子:stackoverflow.com/questions/20259025/…
  • 感谢您的提示,我会阅读并尝试在我的脚本中使用它。
  • 您可以为每种类型的标记进行模板匹配。

标签: python opencv computer-vision


【解决方案1】:

首先我尝试使用特征匹配(@tfv 用户的提议),但这可能不是一个好的解决方案。在许多方法中,它给出的匹配太多(但图像完全不同)或匹配太少(当图像相同时)

现在我将尝试使用@Micka 的算法,但我对第二点和第三点有疑问。我上面帖子中的代码找到了正方形。如何将新矩形另存为新图像?

【讨论】:

    【解决方案2】:

    特征匹配的效果会很差,因为这些标记的特征很少(您需要角集群和特征匹配的精细细节)。

    这些标记更适合Template Matching 方案。对于正确的模板类型,输入图像和模板之间的相关性最高(假设模板被正确定位、定向和缩放)。以下代码适用于您的示例。它包括许多必需的预处理,但本质是找到最高的相关性:np.correlate(img.flatten(), templ.flatten())。该代码可以通过多种方式进行改进,使其在标记位置、比例、方向、噪声等方面的变化更加稳健。

    import matplotlib.pyplot as plt
    import numpy as np
    import cv2
    
    # Detect and store the 6 templates (markers)
    fig0, axs0 = plt.subplots(2)
    imgs = cv2.imread("markers.png")
    imgs_gray = cv2.cvtColor(imgs, cv2.COLOR_BGR2GRAY)
    ret, imgs_th = cv2.threshold(imgs_gray, 100, 255, cv2.THRESH_BINARY)
    xywh = np.zeros((0, 4), dtype=np.int32)
    contours, hierarchies = cv2.findContours(
        imgs_th, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE
    )
    for idx, c in enumerate(contours):
        if hierarchies[0, idx, 3] == 0 and cv2.contourArea(c) > 20000:
            x, y, w, h = cv2.boundingRect(c)
            xywh = np.vstack((xywh, np.array([x, y, w, h])))
    axs0[0].set_title("thresholded markers image")
    axs0[0].imshow(imgs_th, cmap="gray")
    sortx_xywh = xywh[np.argsort(xywh[:, 0])]
    sortyx_xywh = sortx_xywh[np.argsort(sortx_xywh[:, 1])]
    max_w = np.amax(sortyx_xywh[:, 2])
    max_h = np.amax(sortyx_xywh[:, 3])
    templates = np.zeros((max_h, max_w, 6))
    for i, xy in enumerate(sortyx_xywh[:, 0:2]):
        templates[:, :, i] = imgs_th[xy[1] : xy[1] + max_h, xy[0] : xy[0] + max_w]
    
    # Detect the marker regions in the input image
    img_in = cv2.imread("input.jpg")
    img_gray = cv2.cvtColor(img_in, cv2.COLOR_BGR2GRAY)
    ret, img_th = cv2.threshold(img_gray, 100, 255, cv2.THRESH_BINARY)
    xywh = np.zeros((0, 4), dtype=np.int32)
    contours, hierarchies = cv2.findContours(img_th, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    for idx, c in enumerate(contours):
        if hierarchies[0, idx, 3] == 0 and cv2.contourArea(c) > 20000:
            x, y, w, h = cv2.boundingRect(c)
            xywh = np.vstack((xywh, np.array([x, y, w, h])))
    axs0[1].set_title("thresholded input  image")
    axs0[1].imshow(img_th, cmap="gray")
    fig0.show()
    
    # Use simplified template matching (correlation) to determine marker type and orientation
    for xy in xywh[:, 0:2]:
        fig1, axs1 = plt.subplots(5, 6)
        img = img_th[xy[1] : xy[1] + max_h, xy[0] : xy[0] + max_w]
        axs1[0, 0].imshow(img, cmap="gray")
        axs1[0, 0].set_title("input image")
        corr = np.zeros((4, 6))
        for t in range(6):  # 6 templates
            templ = templates[:, :, t]
            for o in range(4):  # 4 orientations
                corr[o, t] = np.correlate(img.flatten(), templ.flatten())
                axs1[o + 1, t].imshow(templ, cmap="gray")
                axs1[o + 1, t].set_title("corr = {:.2e}".format(corr[o, t]))
                templ = np.rot90(templ)
        rot, typ = np.unravel_index(np.argmax(corr, axis=None), corr.shape)
        print("Input marker at ({},{}) is type {}, rotated {} degrees.".format(xy[0], xy[1], typ + 1, rot * 90))
        fig1.tight_layout(pad=0.001)
        fig1.show()
    

    【讨论】:

      猜你喜欢
      • 2023-01-05
      • 2020-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-09
      • 2019-02-27
      相关资源
      最近更新 更多