使用OpenCV检测停车位

9
我正在尝试使用OpenCV自动查找和定位空停车场中的所有停车位。
目前,我有一个代码,可以对图像进行阈值处理,应用Canny边缘检测,然后使用概率霍夫线性变换找到标记每个停车位的线条。
程序会绘制出这些线条和构成它们的点。
以下是代码:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>

using namespace cv;
using namespace std;

int threshold_value = 150;
int threshold_type = 0;;
int const max_value = 255;
int const max_type = 4;
int const max_BINARY_value = 255;

int houghthresh = 50;

char* trackbar_value = "Value";

char* window_name = "Find Lines";

int main(int argc, char** argv)
{
 const char* filename = argc >= 2 ? argv[1] : "pic1.jpg";
 VideoCapture cap(0);
 Mat src, dst, cdst, tdst, bgrdst;
 namedWindow( window_name, CV_WINDOW_AUTOSIZE );

 createTrackbar( trackbar_value,
          window_name, &threshold_value,
          max_value);

while(1)
{
 cap >> src;
 cvtColor(src, dst, CV_RGB2GRAY);
 threshold( dst, tdst, threshold_value, max_BINARY_value,threshold_type );
 Canny(tdst, cdst, 50, 200, 3);
 cvtColor(tdst, bgrdst, CV_GRAY2BGR);

  vector<Vec4i> lines;
  HoughLinesP(cdst, lines, 1, CV_PI/180, houghthresh, 50, 10 );
  for( size_t i = 0; i < lines.size(); i++ )
  {
    Vec4i l = lines[i];
    line( bgrdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,255,0), 2, CV_AA);
    circle( bgrdst,
         Point(l[0], l[1]),
         5,
         Scalar( 0, 0, 255 ),
         -1,
         8 );
    circle( bgrdst,
         Point(l[2], l[3]),
         5,
         Scalar( 0, 0, 255 ),
         -1,
         8 );
  }

 imshow("source", src);
 imshow(window_name, bgrdst);

 waitKey(1);
}
 return 0;
}

目前,我的主要问题是如何通过推断线数据来找到每个停车位的位置。我的目标是让opencv找到停车位并在每个停车位上绘制矩形,并用数字标记每个停车位。

我认为我当前使用的方法存在一些重大问题,因为如输出图像所示,opencv检测到线上除了2个端点以外的多个点。这可能会使使用opencv连接两个相邻端点非常困难。

我读到了关于使用凸包的内容,但我不确定它是什么以及如何工作。

任何帮助都将不胜感激。以下是我的程序输出的图像:

http://imageshack.us/photo/my-images/22/test1hl.png/ http://imageshack.us/photo/my-images/822/test2lw.png/

你能将输入内容包含在内而不进行任何处理吗?对于检测出比你想要的更多的线条/点的问题,RANSAC可能比依靠Hough更好地解决这个问题。 - mmgp
我脑海中浮现的一个想法是首先对图像进行膨胀,使得线条看起来更细。然后或许OpenCV只会检测到每条线的两个端点。 - Tom Knapen
@TomKnapen 你混淆了膨胀和腐蚀。在这些例子中,线条非常明亮,所以膨胀会使它们变大。因此,让我们将你的建议替换为腐蚀。现在你可以断开细线。但实际上这一切都不相关,因为他正在使用Canny算法,该算法生成一厚度的边缘线。 - mmgp
@mmgp 右侧窗口是输入。这是从我的网络摄像头拍摄的停车场图像。我将研究一下 RANSAC,并看看如何实现它。目前,我正在使用 Canny,但我认为可能有更好的方法来完成这项工作,因为标记停车位的相邻四边形可以共享一个边缘。我应该使用腐蚀使线条变细,以便在 canny 中只检测到一条线吗? - tincan
@TianYao,也许我在我的请求中没有表达清楚,我只是要求您将图像包含在其中而不进行任何处理。您在此处包含的图像是屏幕截图,我的建议是包含一些实际帧(而不是它们的屏幕截图或其他任何内容)。为了使线条变细,正确的方法需要使用细化算法,可以使用hit-or-miss变换来实现(opencv中不可用),但也有其他方法可以实现。但是,为了提供更准确的建议(而不仅仅是猜测),我们需要您正在处理的实际数据。 - mmgp
这是原始图像:http://www.photographersgallery.com/i/full/parking_lot_markings.jpg 这是我的网络摄像头记录的mpeg4编码avi文件(使用opencv viderwriter录制): https://www.dropbox.com/s/ysokrddv88wi01k/test.avi - tincan
1个回答

3
考虑将二进制图像变薄,然后检测端点和分支点。以下是基于提供的图像得出的结果;红色表示端点,蓝色表示分支点。
现在,您可以找到停车位的位置。一对蓝点始终由单个边连接。每个蓝点都与两个或三个红点相连。然后有几种方法可以找到由两个蓝点和两个红点形成的停车位,其中最简单的方法是沿着线条:找到与特定蓝点相连的一个点和另一个红点相连的另一个红点中最接近的一对红点。此步骤还可以通过检查所考虑的边缘有多接近平行线来补充。

好的,非常感谢。你使用腐蚀来使二值化图像变细了吗?我明天早上会尝试一下,并查看结果如何。 - tincan
原则上是的,可以参考http://en.wikipedia.org/wiki/Morphological_skeleton了解经典的二进制形态骨架构建方法。 - mmgp
我目前卡在获取二进制图像的骨架上。基本上,我正在使用这里优化的代码:http://felix.abecassis.me/2011/09/opencv-morphological-skeleton/ ,除了不是使用腐蚀和膨胀,而是使用morphologyEx进行开运算形态学。最后,我将skel转移到全局Mat中,用于Canny边缘检测。问题是当我运行它时程序会挂起。窗口出现了,但没有显示图像。我已经将问题隔离到do while循环中,但我不确定具体是什么原因导致的。 - tincan
经过一些测试,我注意到countNonZero永远不会变成0,这意味着do while循环将无限进行下去。我将尝试在每个阶段输出图像,以查看是否发生了任何更改。 - tincan
哎呀,算了。我意识到在循环结束时我把数据复制到了错误的Mat中,这意味着它一直在处理同一张图片。然而,最终的骨架图像非常嘈杂。但我不认为这会成为问题。 - tincan

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