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

Posted

技术标签:

【中文标题】使用 OpenCV 进行矩形检测/跟踪【英文标题】:Rectangle detection / tracking using OpenCV 【发布时间】:2017-11-15 06:17:49 【问题描述】:

我需要什么

我目前正在开发一款类似于增强现实的游戏。游戏使用的控制器(这里我说的是物理输入设备)是一张单色的长方形纸片。我必须在相机的捕获流中检测该矩形的位置、旋转和大小。检测应在尺度上保持不变,沿 X 轴和 Y 轴旋转保持不变。

如果用户将纸张移离或移向相机,则需要比例不变性。我不需要知道矩形的距离,因此比例不变性转化为大小不变性。

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

我做了什么

一开始有一个校准步骤。一个窗口显示了摄像头,用户必须点击矩形。单击时,鼠标指向的像素的颜色将作为参考颜色。将帧转换为 HSV 颜色空间以改善颜色区分。我有 6 个滑块可以调整每个通道的上限和下限阈值。这些阈值用于对图像进行二值化(使用 opencv 的 inRange 函数)。 之后,我将侵蚀和膨胀二进制图像以去除噪声并合并 ​​nerby 块(使用 opencv 的 erodedilate 函数)。 下一步是在二值图像中寻找轮廓(使用 opencv 的findContours 函数)。这些轮廓用于检测最小的定向矩形(使用 opencv 的minAreaRect 函数)。作为最终结果,我使用了面积最大的矩形。

程序的简短结论:

    拿一个框架 将该帧转换为 HSV 二值化(使用用户选择的颜色和滑块的阈值) 应用变形操作(腐蚀和扩张) 寻找轮廓 获取每个轮廓的最小定向边界框 取最大的边界框作为结果

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

我也考虑过使用opencv的跟踪算法。但是有三个原因阻止我使用它们:

    比例不变性:据我了解的一些算法,有些不支持对象的不同比例。 运动预测:一些算法使用运动预测来获得更好的性能,但我正在跟踪的对象完全随机移动,因此无法预测。 简单:我只是在图像中寻找一个单色矩形,没有什么比汽车或人跟踪更花哨的了。

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

这是一个坏的

问题

我如何总体上改进检测,尤其是更好地抵抗光照变化?

更新

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

您不能只使用较厚的材料吗? 是的,我可以而且我已经这样做了(不幸的是,我目前无法访问这些作品)。但是,问题仍然存在。即使我使用像纸板这样的材料。它不像纸那样容易弯曲,但仍然可以弯曲。

如何获取矩形的大小、旋转和位置? opencv 的minAreaRect 函数返回一个RotatedRect 对象。该对象包含我需要的所有数据。

注意 因为矩形是单色的,所以无法区分上下或左右。这意味着旋转始终在[0, 180] 范围内,这对我的目的来说非常好。矩形两侧的比例始终为w:h > 2:1。如果矩形是正方形,则旋转范围将变为[0, 90],但这在这里可以认为无关紧要。

按照 cmets 中的建议,我将尝试使用直方图均衡化来减少亮度问题,并查看 ORB、SURF 和 SIFT。

我会更新进度。

【问题讨论】:

也许你可以尝试像this 做一个直方图均衡以获得更均匀的亮度 如果您总是有相同的矩形框,为什么不保存该框的 2d 模板图像 并运行 ORB/SURF/SIFT 来找到它? 模板图像 也可以使颜色对光照变化具有鲁棒性。您可以将所有检测到的颜色映射到一种颜色。当然,这在很大程度上取决于您的检测。 就目前而言,您采用的方法存在一些问题,而不是矩形检测。从图片来看,您使用的是一张容易弯曲的薄纸,而最后一张图片中的矩形不再是真正的矩形。鉴于您正确识别其区域,您将如何计算轴?考虑要求使用一块硬纸板。可能会证明,虽然没有弯曲,但照明也没有区别。 请附上一些原始输入帧,没有蓝色标记?您还可以将标记更改为所有 6 个面上都有颜色的东西,例如量规立方体吗?这将有助于确定旋转轴。 我已更新问题以回答大部分问题。 @ZdaR “所有 6 面”是什么意思? 【参考方案1】:

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

根据上述信息,我做了以下工作。

    进入HSV空间,拆分H通道,阈值化,归一化。 应用变形操作(打开) 查找轮廓,按某些属性(宽度、高度、面积、比率等)过滤。

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

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,open):

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

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

由于源图片中的蓝色矩形标签,卡片被分成了两侧。但是干净的图像没有问题。

【讨论】:

【参考方案2】:

我知道我问这个问题已经有一段时间了。我最近继续讨论这个话题并解决了我的问题(虽然不是通过矩形检测)。

变化

使用木头来加强我的控制器(“矩形”),如下所示。 在每个控制器上放置了 2 个 ArUco 标记。

工作原理

将帧转换为灰度, 对其进行下采样(以提高检测期间的性能), 使用cv::equalizeHist均衡直方图, 使用cv::aruco::detectMarkers查找标记, 关联标记(如果有多个控制器), 分析标记(位置和旋转), 计算结果并应用一些错误纠正。

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

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

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

在较暗的环境中:

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

失败

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

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

【讨论】:

以上是关于使用 OpenCV 进行矩形检测/跟踪的主要内容,如果未能解决你的问题,请参考以下文章

矩形感兴趣区域超出范围时出错 - opencv

急!!!opencv做目标跟踪的时候,怎样把目标用矩形圈出来

在 OpenCV 中绘制有角度的矩形

使用霍夫变换opencv android进行矩形文档检测

opencv 目标跟踪一定要把被跟踪的物体圈出来吗?

dlib库包的介绍与使用,opencv+dlib检测人脸框opencv+dlib进行人脸68关键点检测,opencv+dlib实现人脸识别,dlib进行人脸特征聚类dlib视频目标跟踪