使用OpenCV在图像中找到矩形的位置

15

我正在尝试使用OpenCV来“解析”来自iPhone游戏Blocked的屏幕截图。这些屏幕截图被裁剪成如下图所示:

Blocked screenshot

目前,我只是想找到每个矩形的4个点的坐标。我看过OpenCV附带的样例文件squares.c,但当我在这个图片上运行该算法时,它会生成72个矩形,包括明显不需要计入我的矩形的空白矩形区域。有更好的方法来解决这个问题吗?我尝试了一些Google搜索,但对于所有的搜索结果来说,相关可用信息非常少。


2
只需将颜色不正确的矩形扔掉。 - Robert Harvey
6个回答

16
相似的问题已经被讨论过:如何识别图像中的矩形? 至于您的数据,您要查找的矩形是唯一的黑色对象。因此,您可以尝试进行阈值二值化:黑色像素是所有三个RGB值都小于40的像素(我经验性地发现的)。这个简单的操作使您的图片看起来像这样:

二值图

之后,您可以应用Hough变换来找到线段(在我提到的主题中讨论),或者您也可以更容易地完成它。计算黑色像素对X轴和Y轴的积分投影。(对于X轴的投影是一个向量x_i - 表示第一个坐标为x_i的黑色像素数量)。因此,您可以通过在投影的峰值处获得可能的x和y值。然后查找由找到的x和y限制的所有可能的线段(如果在(x_i, y_j)和(x_i, y_k)之间有很多黑色像素,则可能存在一条线)。最后,将线段组成矩形!

我会选择这个答案,因为它非常有帮助且是解决问题的一种有趣方式。但是由于我需要区分灰色和蓝色矩形之间的差异,我仍需要进行颜色分析,即使我使用你提供的方法,因此我决定在原始方法的基础上继续改进。 - dancavallaro

8
这里是完整的Python解决方案。 主要思路是:
  • 应用金字塔均值漂移滤波 以帮助阈值的准确性
  • Otsu阈值得到二进制图像
  • 查找轮廓并使用轮廓逼近进行筛选

这是每个检测到的矩形轮廓的可视化。

enter image description here

结果

enter image description here

import cv2

image = cv2.imread('1.png')
blur = cv2.pyrMeanShiftFiltering(image, 11, 21)
gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.015 * peri, True)
    if len(approx) == 4:
        x,y,w,h = cv2.boundingRect(approx)
        cv2.rectangle(image,(x,y),(x+w,y+h),(36,255,12),2)

cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.waitKey()

7

我最终采用了原始方法并按照Robert在我的问题评论中的建议进行。得到矩形列表后,我遍历每个矩形并计算其平均颜色。我检查平均颜色的红色、绿色和蓝色成分是否分别与灰色和蓝色矩形颜色相差不超过10%,如果是,则保存该矩形,否则舍弃它。这个过程给我带来了如下结果:

screenshot

从中,我很容易获取所需信息(考虑游戏窗口为6x6网格的方向、起始点和每个矩形的长度)。


1
你的原始方法是什么样子? - Cos

3
这些块看起来像位图 - 为什么不使用简单的模板匹配,针对每个块大小/颜色/方向使用不同的模板?

2

考虑到你的问题是小矩形,我建议先将它们去除。由于这些线比矩形边框细,建议对图像应用形态学操作

使用这样一个结构元素:

 element = [ 1 1
             1 1 ]

应该删除宽度小于两个像素的线条。删除这些细小的线条后,OpenCV的矩形查找算法很可能会为您完成其余的工作。 可以通过OpenCV函数cvErode进行侵蚀操作。


0

尝试使用像哈里斯角检测器这样的许多角点检测器之一。此外,通常最好在多个分辨率下尝试,因此进行一些不同放大倍数的预处理。
如果您想要某种颜色主导的正方形,则可以通过首先使用类似于cvsplit的东西来抑制其他颜色......然后对颜色进行阈值处理......以便只有该区域保留......接着进行裁剪操作......我认为那也可能起作用....


Harris角点检测在这种完美的网格游戏中将是完全无用的,因为所有的角点都已经被知晓。 - Johan Tidén

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接