首页 文章

使用OpenCV进行矩形检测/跟踪

提问于
浏览
9

我需要什么

我目前正致力于增强现实游戏 . 游戏使用的控制器(我在这里谈论物理输入设备)是单色的,长方形的纸片 . 我必须在摄像机的捕获流中检测该矩形的位置,旋转和大小 . 检测应在尺度上不变,并且在沿X和Y轴旋转时不变 .

在用户将纸张移开或朝向相机移动的情况下,需要比例不变性 . 我不需要知道矩形的距离,因此尺度不变性转换为尺寸不变性 .

如果用户沿其局部X和/或Y轴倾斜矩形,则需要旋转不变性 . 这种旋转将纸张的形状从矩形变为梯形 . 在这种情况下,面向对象的边界框可用于测量纸张的尺寸 .

我做了什么

开始时有一个校准步骤 . 一个窗口显示摄像机源,用户必须单击矩形 . 单击时,鼠标指向的像素颜色将作为参考颜色 . 帧被转换为HSV颜色空间以改善颜色区分 . 我有6个滑块可以调整每个通道的上限和下限 . 这些阈值用于二值化图像(使用opencv的 inRange 函数) .
之后我'm eroding and dilating the binary image to remove noise and unite nerby chunks (using opencv' s erodedilate 函数) .
下一步是在二进制图像中查找轮廓(使用opencv的 findContours 函数) . 这些轮廓用于检测最小的方向矩形(使用opencv的 minAreaRect 函数) . 作为最终结果,我使用了面积最大的矩形 .

该程序的简短结论:

  • grab 一个框架

  • 将该帧转换为HSV

  • 二进制化(使用用户选择的颜色和滑块的阈值)

  • 应用变形操作(侵蚀和扩张)

  • 查找轮廓

  • 获取每个轮廓的最小定向的bouding box

  • 取结果中最大的边界框

您可能已经注意到,我没有利用有关纸张实际形状的知识,仅仅因为我不知道如何正确使用这些信息 .

我也考虑过使用opencv的跟踪算法 . 但有三个原因使我无法使用它们:

  • 比例不变性:据我读到的一些算法,有些不支持对象的不同比例 .

  • 运动预测:一些算法使用运动预测来获得更好的性能,但我跟踪的对象完全随机移动,因此无法预测 .

  • 简单:我只是在图像中寻找单色矩形,没有像汽车或人物跟踪那样的奇特 .

这是一个 - 相对 - 好的捕获(侵蚀和扩张后的二进制图像)
ok

这是一个糟糕的
bad

问题

如何提高检测效果,尤其是更能抵抗照明变化?

更新

Here是一些用于测试的原始图像 .

Can't you just use thicker material?
是的,我可以,而且我已经做过了(不幸的是,我可以像纸一样容易弯曲,但仍然可以弯曲它 .

How do you get the size, rotation and position of the rectangle?
opencv的 minAreaRect 函数返回 RotatedRect 对象 . 该对象包含我需要的所有数据 .

Note
因为矩形是单色的,所以不可能区分顶部和底部或左右 . 这意味着旋转始终在 [0, 180] 范围内,这对我来说完全没问题 . rect的两边的比例总是 w:h > 2:1 . 如果矩形是方形,则旋转范围将变为 [0, 90] ,但这可以认为是无关紧要的 .

正如评论中所建议的,我将尝试直方图均衡以减少亮度问题,并查看ORB,SURF和SIFT .

我会更新进展情况 .

2 回答

  • 2

    HSV空间中的H通道是Hue,它对光线变化不敏感 . 红色范围约为[150,180] .

    根据提到的信息,我做了以下工作 .

    • 切换到HSV空间,拆分H通道,阈值并将其标准化 .

    • 应用变形操作(打开)

    • 查找轮廓,按某些属性(宽度,高度,面积,比率等)进行过滤 .

    PS . 由于NETWORK,我无法获取您在Dropbox上传的图像 . 所以,我只使用crop the right side of your second image作为输入 .

    enter image description here

    imgname = "src.png"
    img = cv2.imread(imgname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    ## Split the H channel in HSV, and get the red range
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    h,s,v = cv2.split(hsv)
    h[h<150]=0
    h[h>180]=0
    
    ## normalize, do the open-morp-op
    normed = cv2.normalize(h, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8UC1)
    kernel = cv2.getStructuringElement(shape=cv2.MORPH_ELLIPSE, ksize=(3,3))
    opened = cv2.morphologyEx(normed, cv2.MORPH_OPEN, kernel)
    res = np.hstack((h, normed, opened))
    cv2.imwrite("tmp1.png", res)
    

    现在,我们得到结果(h,normed,打开):

    enter image description here

    然后找到轮廓并过滤它们 .

    contours = cv2.findContours(opened, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    print(len(contours))[-2]
    
    bboxes = []
    rboxes = []
    cnts = []
    dst = img.copy()
    for cnt in contours:
        ## Get the stright bounding rect
        bbox = cv2.boundingRect(cnt)
        x,y,w,h = bbox
        if w<30 or h < 30 or w*h < 2000 or w > 500:
            continue
    
        ## Draw rect
        cv2.rectangle(dst, (x,y), (x+w,y+h), (255,0,0), 1, 16)
    
        ## Get the rotated rect
        rbox = cv2.minAreaRect(cnt)
        (cx,cy), (w,h), rot_angle = rbox
        print("rot_angle:", rot_angle)  
    
        ## backup 
        bboxes.append(bbox)
        rboxes.append(rbox)
        cnts.append(cnt)
    

    结果是这样的:

    rot_angle: -2.4540319442749023
    rot_angle: -1.8476102352142334
    

    enter image description here

    因为源图像中的蓝色矩形标签,卡被分成两侧 . 但是干净的图像没有问题 .

  • 1

    我知道自从我提出问题以来已经有一段时间了 . 我最近继续讨论这个主题并解决了我的问题(虽然不是通过矩形检测) .

    更改

    • 使用木材强化我的控制器("rectangles"),如下所示 .

    • 在每个控制器上放置2个ArUco标记 .

    Controller

    它是如何工作的

    • 将帧转换为灰度,

    • 下采样(以提高检测期间的性能),

    • 使用 cv::equalizeHist 均衡直方图,

    • 使用 cv::aruco::detectMarkers 查找标记,

    • 关联标记(如果有多个控制器),

    • 分析标记(位置和旋转),

    • 计算结果并应用一些错误纠正 .

    事实证明,标记检测对于光照变化和不同的视角非常稳健,这使我可以跳过任何校准步骤 .

    我在每个控制器上放置了2个标记,以进一步提高检测稳健性 . 两个标记只需要检测一次(以测量它们的相关性) . 之后,每个控制器只能找到一个标记就足够了,因为另一个标记可以从先前计算的相关性中推断出来 .

    这是在明亮环境中的检测结果:

    Detection in a bright environment

    在较暗的环境中:

    Detection in a dark environment

    当隐藏其中一个标记时(蓝点表示外推标记后):

    Detection of missing markers

    失败

    我实施的初始形状检测效果不佳 . 照明变化非常脆弱 . 此外,它需要初始校准步骤 .

    在形状检测方法之后,我尝试将SIFT和ORB与蛮力和knn匹配器结合使用来提取和定位框架中的特征 . 事实证明,单色物体并没有提供太多的关键点(令人惊讶的是) . 无论如何,SIFT的表现都很糟糕(大约10 fps @ 540p) . 我在控制器上绘制了一些线条和其他形状,从而产生了更多的关键点 . 然而,这并没有带来巨大的改善 .

相关问题