gpt4 book ai didi

python - 使用 OpenCV 检测图像中已知形状/对象的方法

转载 作者:行者123 更新时间:2023-12-01 12:45:53 26 4
gpt4 key购买 nike

我的任务是使用 OpenCV 检测给定图像中的对象(我不在乎它是 Python 还是 C++ 实现)。下面的三个示例中显示的对象是一个黑色矩形,其中包含五个白色矩形。所有维度都是已知的。

enter image description here

但是,图像的旋转、比例、距离、透视、照明条件、相机焦距/镜头和背景是未知的。黑色矩形的边缘不能保证完全可见,但是在五个白色矩形之前不会有任何东西 - 它们将始终完全可见。最终目标是能够检测图像中该对象的存在,并旋转、缩放和裁剪以显示移除透视的对象。鉴于它的四个角,我相当有信心我可以调整图像以仅裁剪对象。但是,我不太有信心能够可靠地找到这四个角。在模棱两可的情况下,与将图像的某些其他特征误识别为对象相比,没有找到对象更可取。

使用 OpenCV 我想出了以下方法,但是我觉得我可能会遗漏一些明显的东西。是否有更多方法可用,或者其中一种是最佳解决方案?

基于边缘的轮廓

第一个想法是寻找物体的外边缘。

使用 Canny 边缘检测(在缩放到已知大小、灰度和高斯模糊之后),找到与对象外部形状最匹配的轮廓。
这可以解决透视、颜色、大小问题,但如果背景复杂,或者图像中其他地方有与对象形状相似的东西,则会失败。也许这可以通过一组更好的规则来改进以找到正确的轮廓 - 可能涉及五个白色矩形以及外边缘。

enter image description here
enter image description here

特征检测

下一个想法是使用特征检测匹配已知模板。

使用 ORB 特征检测、描述符匹配和单应性 (from this tutorial) 失败,我相信是因为它检测到的特征与对象内的其他特征非常相似(很多核心是四分之一白和四分之三黑) .但是,我确实喜欢匹配已知模板的想法 - 这个想法对我来说很有意义。我想虽然因为对象在几何上非常基本,所以在特征匹配步骤中可能会发现很多误报。

enter image description here

平行线

使用 Houghlines 或 HoughLinesP,寻找间隔均匀的平行线。刚刚开始走这条路,所以需要研究阈值等的最佳方法。虽然对于具有复杂背景的图像来说看起来很困惑,但我认为它可能工作得很好,因为我可以依靠黑色对象中的白色矩形应该始终对比度高,可以很好地指示线条的位置。

enter image description here

'条码扫描'

我的最终想法是逐行扫描图像,寻找白色到黑色的图案。

我还没有开始使用这种方法,但我的想法是取一条图像(在某个角度),转换为 HSV 颜色空间,并在 Value 列中查找按顺序出现五次的常规黑白图案。这个想法对我来说听起来很有希望,因为我认为它应该忽略许多未知变量。

想法

我查看了许多 OpenCV 教程,以及诸如 this one 之类的 SO 问题。 ,但是因为我的对象在几何上非常简单,所以我在实现给定的想法时遇到了问题。

我觉得这是一个可以实现的任务,但我的挣扎是不知道进一步追求哪种方法。我对前两个想法进行了相当多的试验,虽然我没有取得任何非常可靠的成果,但也许我遗漏了一些东西。是否有一种我没有想到的标准方法来完成这项任务,或者我建议的方法之一是最明智的?

编辑 :一旦使用上述方法之一(或其他方法)找到角落,我正在考虑使用 Hu Moments 或 OpenCV 的 matchShapes() 函数来消除任何误报。

编辑2 :根据@Timo 的要求添加了更多输入图像示例

  • Orig1
  • Orig2
  • Orig3
  • Extra image 1
  • Extra image 2
  • Extra image 3
  • Extra image 4
  • 最佳答案

    我花了一些时间研究这个问题并制作了一个小 python 脚本。我正在检测您的形状内的白色矩形。将代码粘贴到 .py 文件中,并将所有输入图像复制到输入子文件夹中。图像的最终结果只是一个虚拟的自动取款机,脚本尚未完成。我会在接下来的几天里继续努力。该脚本将创建一个调试子文件夹,其中将保存一些显示当前检测状态的图像。

    import numpy as np
    import cv2
    import os

    INPUT_DIR = 'input'
    DEBUG_DIR = 'debug'
    OUTPUT_DIR = 'output'
    IMG_TARGET_SIZE = 1000

    # each algorithm must return a rotated rect and a confidence value [0..1]: (((x, y), (w, h), angle), confidence)

    def main():
    # a list of all used algorithms
    algorithms = [rectangle_detection]

    # load and prepare images
    files = list(os.listdir(INPUT_DIR))
    images = [cv2.imread(os.path.join(INPUT_DIR, f), cv2.IMREAD_GRAYSCALE) for f in files]
    images = [scale_image(img) for img in images]

    for img, filename in zip(images, files):
    results = [alg(img, filename) for alg in algorithms]
    roi, confidence = merge_results(results)

    display = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    display = cv2.drawContours(display, [cv2.boxPoints(roi).astype('int32')], -1, (0, 230, 0))
    cv2.imshow('img', display)
    cv2.waitKey()


    def merge_results(results):
    '''Merges all results into a single result.'''
    return max(results, key=lambda x: x[1])

    def scale_image(img):
    '''Scales the image so that the biggest side is IMG_TARGET_SIZE.'''
    scale = IMG_TARGET_SIZE / np.max(img.shape)
    return cv2.resize(img, (0,0), fx=scale, fy=scale)


    def rectangle_detection(img, filename):
    debug_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    _, binarized = cv2.threshold(img, 50, 255, cv2.THRESH_BINARY)
    contours, _ = cv2.findContours(binarized, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

    # detect all rectangles
    rois = []
    for contour in contours:
    if len(contour) < 4:
    continue
    cont_area = cv2.contourArea(contour)
    if not 1000 < cont_area < 15000: # roughly filter by the volume of the detected rectangles
    continue
    cont_perimeter = cv2.arcLength(contour, True)
    (x, y), (w, h), angle = rect = cv2.minAreaRect(contour)
    rect_area = w * h
    if cont_area / rect_area < 0.8: # check the 'rectangularity'
    continue
    rois.append(rect)

    # save intermediate results in the debug folder
    rois_img = cv2.drawContours(debug_img, contours, -1, (0, 0, 230))
    rois_img = cv2.drawContours(rois_img, [cv2.boxPoints(rect).astype('int32') for rect in rois], -1, (0, 230, 0))
    save_dbg_img(rois_img, 'rectangle_detection', filename, 1)

    # todo: detect pattern

    return rois[0], 1.0 # dummy values


    def save_dbg_img(img, folder, filename, index=0):
    '''Writes the given image to DEBUG_DIR/folder/filename_index.png.'''
    folder = os.path.join(DEBUG_DIR, folder)
    if not os.path.exists(folder):
    os.makedirs(folder)
    cv2.imwrite(os.path.join(folder, '{}_{:02}.png'.format(os.path.splitext(filename)[0], index)), img)


    if __name__ == "__main__":
    main()

    这是当前 WIP 的示例图像

    1

    下一步是检测多个矩形之间的模式/关系。当我取得进展时,我会更新这个答案。

    关于python - 使用 OpenCV 检测图像中已知形状/对象的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60867638/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com