【问题标题】:Robust method to detect cross and or corner contours with Python使用 Python 检测交叉和/或角轮廓的稳健方法
【发布时间】:2022-06-10 19:21:55
【问题描述】:

我正在尝试制作自己的工具来使用 Python 稳健地检测图像中的色卡。 每张色卡都有一些明显的特征,应该很容易从轮廓上识别出来,其中包括中间的小十字和四个双刃角。

从下图中,我制作了一个轮廓列表,它包含 374 个轮廓,我希望能够从中检测出用红色方块突出显示的五个感兴趣的轮廓:

[]

我尝试应用顶点数逻辑,但轮廓非常小,以至于对于角轮廓,顶点数从 4 到 5 不等,我实际上预计是 6...

之后,我计算了旋转的边界框,如果它在宽度和高度方面或多或少相等,我假设轮廓可能是有趣的,不幸的是,许多轮廓都是这种情况。当前应用了以下逻辑,但是随着检测到的轮廓数量,我需要一些东西来更好地定义感兴趣的轮廓的逻辑。

目前:

import numpy as np
for number, contour in enumerate(contours[78:79]):
    
    #We draw a bounding box and expect more or less a square
    rect = cv2.minAreaRect(contour) 
    box = cv2.boxPoints(rect) 
    box = np.int0(box)
    First=[box[0][0],box[1][0],box[2][0],box[3][0]]
    Second=[box[0][1],box[1][1],box[2][1],box[3][1]]
    First_Desc=max(First)-min(First)
    Second_Desc=max(Second)-min(Second)
    
    #Next step would be to check if contour has two lines
    peri = cv2.arcLength(contour, True)
    approx = cv2.approxPolyDP(contour, 0.04 * peri, True)
    if len(approx) == 4 or len(approx) == 5:
    
        if abs(First_Desc-Second_Desc) <= 2:
            print(First_Desc, Second_Desc)
prints:
15 14 #(being the width and height of the rotated bounding box, also returns contours not of interest)

两个例子:

#Corner contour, from which four are present in each image
array([[[651, 732]],

       [[651, 733]],

       [[651, 734]],

       [[651, 735]],

       [[651, 736]],

       [[651, 737]],

       [[651, 738]],

       [[651, 739]],

       [[651, 740]],

       [[651, 741]],

       [[651, 742]],

       [[650, 743]],

       [[649, 743]],

       [[648, 743]],

       [[647, 743]],

       [[646, 743]],

       [[645, 743]],

       [[644, 743]],

       [[643, 743]],

       [[642, 743]],

       [[641, 743]],

       [[640, 743]],

       [[639, 743]],

       [[638, 743]],

       [[638, 744]],

       [[638, 745]],

       [[639, 746]],

       [[640, 746]],

       [[641, 746]],

       [[642, 746]],

       [[643, 746]],

       [[644, 746]],

       [[645, 746]],

       [[646, 746]],

       [[647, 746]],

       [[648, 746]],

       [[649, 746]],

       [[650, 746]],

       [[651, 746]],

       [[652, 746]],

       [[653, 745]],

       [[653, 744]],

       [[653, 743]],

       [[653, 742]],

       [[653, 741]],

       [[653, 740]],

       [[653, 739]],

       [[653, 738]],

       [[653, 737]],

       [[653, 736]],

       [[653, 735]],

       [[653, 734]],

       [[653, 733]],

       [[653, 732]],

       [[652, 732]]], dtype=int32)

Contour of cross in center of color card:
array([[[271, 427]],

       [[271, 428]],

       [[271, 429]],

       [[271, 430]],

       [[271, 431]],

       [[271, 432]],

       [[271, 433]],

       [[271, 434]],

       [[271, 435]],

       [[271, 436]],

       [[271, 437]],

       [[271, 438]],

       [[271, 439]],

       [[271, 440]],

       [[271, 441]],

       [[270, 442]],

       [[270, 443]],

       [[270, 444]],

       [[270, 445]],

       [[270, 446]],

       [[270, 447]],

       [[270, 448]],

       [[270, 449]],

       [[270, 450]],

       [[270, 451]],

       [[270, 452]],

       [[270, 453]],

       [[270, 454]],

       [[270, 455]],

       [[270, 456]],

       [[270, 457]],

       [[270, 458]],

       [[270, 459]],

       [[270, 460]],

       [[270, 461]],

       [[270, 462]],

       [[270, 463]],

       [[270, 464]],

       [[269, 465]],

       [[269, 466]],

       [[270, 467]],

       [[270, 468]],

       [[269, 469]],

       [[269, 470]],

       [[269, 471]],

       [[269, 472]],

       [[269, 473]],

       [[269, 474]],

       [[269, 475]],

       [[269, 476]],

       [[269, 477]],

       [[269, 478]],

       [[269, 479]],

       [[269, 480]],

       [[269, 481]],

       [[269, 482]],

       [[269, 483]],

       [[269, 484]],

       [[269, 485]],

       [[269, 486]],

       [[269, 487]],

       [[269, 488]],

       [[269, 489]],

       [[269, 490]],

       [[269, 491]],

       [[269, 492]],

       [[269, 493]],

       [[268, 494]],

       [[268, 495]],

       [[268, 496]],

       [[268, 497]],

       [[268, 498]],

       [[268, 499]],

       [[269, 500]],

       [[269, 501]],

       [[270, 501]],

       [[271, 501]],

       [[272, 501]],

       [[273, 501]],

       [[274, 501]],

       [[275, 502]],

       [[276, 502]],

       [[277, 502]],

       [[278, 502]],

       [[279, 502]],

       [[280, 502]],

       [[281, 502]],

       [[282, 502]],

       [[283, 502]],

       [[284, 502]],

       [[285, 502]],

       [[286, 502]],

       [[287, 502]],

       [[288, 502]],

       [[289, 503]],

       [[290, 503]],

       [[291, 503]],

       [[292, 503]],

       [[293, 503]],

       [[294, 503]],

       [[295, 503]],

       [[296, 503]],

       [[297, 503]],

       [[298, 503]],

       [[299, 503]],

       [[300, 504]],

       [[301, 504]],

       [[302, 503]],

       [[303, 503]],

       [[304, 504]],

       [[305, 504]],

       [[306, 504]],

       [[307, 504]],

       [[308, 504]],

       [[309, 504]],

       [[310, 504]],

       [[311, 504]],

       [[312, 504]],

       [[313, 504]],

       [[314, 504]],

       [[315, 504]],

       [[316, 504]],

       [[317, 504]],

       [[318, 504]],

       [[319, 505]],

       [[320, 505]],

       [[321, 505]],

       [[322, 505]],

       [[323, 505]],

       [[324, 505]],

       [[325, 505]],

       [[326, 505]],

       [[327, 505]],

       [[328, 505]],

       [[329, 505]],

       [[330, 505]],

       [[331, 505]],

       [[332, 505]],

       [[333, 505]],

       [[334, 506]],

       [[335, 506]],

       [[336, 506]],

       [[337, 506]],

       [[338, 506]],

       [[339, 506]],

       [[340, 506]],

       [[341, 506]],

       [[342, 506]],

       [[343, 506]],

       [[344, 506]],

       [[345, 506]],

       [[346, 506]],

       [[347, 506]],

       [[347, 505]],

       [[347, 504]],

       [[347, 503]],

       [[347, 502]],

       [[347, 501]],

       [[347, 500]],

       [[347, 499]],

       [[347, 498]],

       [[347, 497]],

       [[347, 496]],

       [[347, 495]],

       [[347, 494]],

       [[347, 493]],

       [[347, 492]],

       [[347, 491]],

       [[347, 490]],

       [[347, 489]],

       [[347, 488]],

       [[347, 487]],

       [[347, 486]],

       [[347, 485]],

       [[347, 484]],

       [[347, 483]],

       [[347, 482]],

       [[347, 481]],

       [[347, 480]],

       [[347, 479]],

       [[347, 478]],

       [[347, 477]],

       [[348, 476]],

       [[348, 475]],

       [[348, 474]],

       [[348, 473]],

       [[348, 472]],

       [[348, 471]],

       [[348, 470]],

       [[348, 469]],

       [[348, 468]],

       [[348, 467]],

       [[348, 466]],

       [[348, 465]],

       [[348, 464]],

       [[348, 463]],

       [[348, 462]],

       [[348, 461]],

       [[348, 460]],

       [[348, 459]],

       [[348, 458]],

       [[348, 457]],

       [[348, 456]],

       [[348, 455]],

       [[348, 454]],

       [[348, 453]],

       [[348, 452]],

       [[348, 451]],

       [[349, 450]],

       [[349, 449]],

       [[349, 448]],

       [[349, 447]],

       [[348, 446]],

       [[349, 445]],

       [[349, 444]],

       [[349, 443]],

       [[349, 442]],

       [[349, 441]],

       [[349, 440]],

       [[349, 439]],

       [[349, 438]],

       [[349, 437]],

       [[349, 436]],

       [[349, 435]],

       [[349, 434]],

       [[349, 433]],

       [[349, 432]],

       [[348, 432]],

       [[347, 432]],

       [[346, 432]],

       [[345, 431]],

       [[344, 431]],

       [[343, 431]],

       [[342, 431]],

       [[341, 431]],

       [[340, 431]],

       [[339, 431]],

       [[338, 431]],

       [[337, 431]],

       [[336, 431]],

       [[335, 431]],

       [[334, 431]],

       [[333, 431]],

       [[332, 431]],

       [[331, 431]],

       [[330, 431]],

       [[329, 431]],

       [[328, 431]],

       [[327, 430]],

       [[326, 430]],

       [[325, 430]],

       [[324, 430]],

       [[323, 430]],

       [[322, 430]],

       [[321, 430]],

       [[320, 430]],

       [[319, 430]],

       [[318, 430]],

       [[317, 430]],

       [[316, 429]],

       [[315, 429]],

       [[314, 429]],

       [[313, 429]],

       [[312, 429]],

       [[311, 429]],

       [[310, 429]],

       [[309, 429]],

       [[308, 429]],

       [[307, 429]],

       [[306, 429]],

       [[305, 429]],

       [[304, 429]],

       [[303, 429]],

       [[302, 429]],

       [[301, 429]],

       [[300, 429]],

       [[299, 429]],

       [[298, 428]],

       [[297, 428]],

       [[296, 428]],

       [[295, 428]],

       [[294, 428]],

       [[293, 428]],

       [[292, 428]],

       [[291, 428]],

       [[290, 428]],

       [[289, 428]],

       [[288, 428]],

       [[287, 427]],

       [[286, 427]],

       [[285, 427]],

       [[284, 427]],

       [[283, 427]],

       [[282, 427]],

       [[281, 427]],

       [[280, 427]],

       [[279, 427]],

       [[278, 427]],

       [[277, 427]],

       [[276, 427]],

       [[275, 427]],

       [[274, 427]],

       [[273, 427]],

       [[272, 427]]], dtype=int32)

用于再现性的原始图像(二进制)

【问题讨论】:

  • 可能是具有最大长度的 houghlines。然后找到线的交点。
  • 首先,我建议您纠正整个图像的旋转,以便基准框更垂直和水平线。然后,一旦您使用轮廓找到正确大小的对象和/或相对于主要颜色检查器背景边界的位置,您可以裁剪它们,然后使用模板匹配或命中或未命中形态来确定它们是基准还是十字架(或者也许形状匹配就足够了,尽管你的特征太小以至于可能不起作用)
  • 感谢您的建议。旋转图像是不可能的,我想对大批量的图像进行颜色校正,有时色卡会有点旋转,或者可能旋转很大。这是plantcv之类的软件失败的地方:(pcv.transform.find_color_card)以及我试图解决的问题。
  • 如果您的图像相似,那么您应该能够从轮廓中获取色卡的轮廓,然后是其旋转的边界框(cv2.minAreaRect)。然后从旋转的边界框中,您可以获得角度并旋转图像以校正其方向。您的图片不能这样做吗?
  • 默认情况下,完整图像中有多个正方形,有时是矩形,但我认为您在这里有所了解。也许我们可以过滤出或多或少与色卡相对应的宽高比的轮廓,至少包含两三个几乎完美的正方形。但是,要找到色卡轮廓,我们需要反转图像,这意味着色卡内的完美正方形将丢失!

标签: python opencv image-processing computer-vision contour


猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-27
  • 2014-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多