【问题标题】:Detecting billiard balls with OpenCV使用 OpenCV 检测台球
【发布时间】:2011-11-17 04:44:06
【问题描述】:

我正在制作一个 android 应用程序,它会拍摄正在进行的台球游戏的图像并检测各种球的位置。这张图片是从某人的手机上拍摄的,所以我当然没有一张完美的桌子俯视图。现在我正在使用 houghcircles 来寻找球,它的工作还不错,但它似乎在这里和那里错过了一些球,然后是误报。

我现在最大的问题是,如何减少在表外发现的误报?我使用 ROI 来切掉图像的顶部,因为它主要是浪费空间,但我不能让它变得更小,或者我冒着切掉桌子的一部分的风险,因为它是一个梯形形状。我目前的想法是将用户在拍照时看到的指南覆盖在图像之上,但问题是我不知道他们相机的分辨率是多少,因此覆盖可能会覆盖错误的地方。理想情况下,我想我会想使用 houghlines,但是当我尝试它时,我的应用程序因我认为内存不足而崩溃。有什么想法吗?

这是我得到的结果的链接:

http://graphiquest.com/cvhoughcircles.html

这是我的代码:

    IplImage img = cvLoadImage("/sdcard/DCIM/test/picture"+i+".jpg",1);
    IplImage gray = opencv_core.cvCreateImage( opencv_core.cvSize( img.width(), img.height() ), opencv_core.IPL_DEPTH_8U, 1);

    cvCvtColor(img, gray, opencv_imgproc.CV_RGB2GRAY );
    cvSetImageROI(gray, cvRect(0, (int)(img.height()*.15), (int)img.width(), (int)(img.height()-(img.height()*.20))));


    cvSmooth(gray,gray,opencv_imgproc.CV_GAUSSIAN,9,9,2,2);

    Pointer circles = CvMemStorage.create();        
    CvSeq seq = cvHoughCircles(gray, circles, CV_HOUGH_GRADIENT, 2.5d, (double)gray.height()/30, 70d, 100d, 0, 80);

    for(int j=0; j<seq.total(); j++){
        CvPoint3D32f point = new CvPoint3D32f(cvGetSeqElem(seq, j));

        float xyr[] = {point.x(),point.y(),point.z()};
        CvPoint center = new CvPoint(Math.round(xyr[0]), Math.round(xyr[1]));

        int radius = Math.round(xyr[2]);
        cvCircle(gray, center, 3, CvScalar.GREEN, -1, 8, 0);
        cvCircle(gray, center, radius, CvScalar.BLUE, 3, 8, 0);
    }
    String path = "/sdcard/DCIM/test/";
    File photo=new File(path, "picture"+i+"_2.jpg");

    if (photo.exists()) 
    {
        photo.delete();
    }
   cvSaveImage("/sdcard/DCIM/test/picture"+i+"_2.jpg", gray);

【问题讨论】:

  • 嘿vince88。你曾经完成过这个项目吗?你开源代码了吗?我自己也差不多要开始做类似的了。

标签: android opencv computer-vision


【解决方案1】:

您可以应用一些非常有用的限制条件。除了做一个感兴趣的矩形区域之外,您还应该使用台球桌的实际梯形形状来掩盖您的结果。使用图像的颜色信息来查找台球桌区域。你知道台球桌是纯色的。它不必一定是绿色 - 您可以在 HSV 颜色空间中使用一些 histogram 技术来找到图像中最流行的颜色,可能偏向于中心的像素。它很可能检测到台球桌的颜色。选择匹配这个颜色的像素,进行形态学运算去噪,然后就可以把mask当成一个轮廓,找到它的convexHull。填充船体以去除由台球产生的孔。

到目前为止,我所说的应该是一种不同于霍夫圆的方法。由于台球的照明不均匀,霍夫圆可能效果不佳。因此,找到台球的另一种方法是从它的凸包中减去台球桌颜色蒙版。您将留下被球遮挡的桌子区域。

【讨论】:

  • 感谢您的建议,这很有意义。不过,总的来说,我对 OpenCV 和图像处理真的很陌生,所以我必须做更多的研究。你建议什么样的形态学操作?类似高斯模糊的东西?另外,桌子照明不均匀有关系吗?
  • 我刚刚意识到这种方法会使检测聚集在一起的球的位置变得更加困难。它们会变成一个大块,对吧?
  • 是的,这就是为什么我不建议完全放弃霍夫圆。也许您可以结合使用这些方法。您可以尝试一些基本的分割技术来分离集群。
【解决方案2】:

自从我打台球和斯诺克以来,我也考虑过解决这个问题。

几点:

  1. 从霍夫圆拟合来看,您似乎没有过滤边缘点,或者您的边缘强度阈值不够高。您是简单地对边缘点使用二进制指示符,还是根据边缘强度选择边缘点?
  2. 您可以在 RGB 空间中工作吗?这有助于检测台床、导轨以及识别球。桌上的蓝色斑点可能是 2 号球、10 号球或一大块粉笔。
  3. 在您的参数空间中,您应该能够限制搜索半径非常有限的圆。如果...
  4. 检测台面和导轨。笔画宽度变换可以帮助您找到轨道,尤其是当您在轨道具有高对比度的颜色平面(绿色)中进行搜索时。您还可以使用六个口袋(或至少三个口袋)来帮助识别桌子的姿势(位置和方向)。
  5. 检测到轨道后,您可以使用仿射变换来校正透视失真。无论如何,您都需要这样做才能以任何准确度放置球,特别是如果您希望球的放置能够满足认真的台球玩家,例如玩 One Pocket 或 Straight Pool 的人。完成仿射变换后,您可以在 Hough 参数空间中为半径设置相当严格的容差。
  6. 检测到台床后,您可以执行初始分割(即区域标记或斑点查找)并仅搜索具有特定面积和圆度的斑点。
  7. 强烈、均匀、漫射的顶灯有助于消除阴影。
  8. 您可以通过接受(或至少偏爱)具有指向具有平行梯度的其他边缘点的梯度的边缘点来帮助过滤边缘点。如果边缘点对的局部集合通过它们的边缘梯度相互“指向”,那么它们是很好的检测候选者。
  9. 检测到候选球后,执行进一步处理以接受/拒绝。球应该是相对均匀的色调(母球,1 - 8,或从适当角度观察的条纹),或者它应该具有可检测的彩色条纹和白色。球面不会像桌子的木纹那样有高质感。
  10. 可以选择让用户从稍微不同的角度拍摄两张照片。然后你有两次找到球的机会,并且可以想象解决两个图像中的桌子和球匹配的对应问题,以帮助在桌床的二维空间中定位球。
  11. 考虑使用第二种算法,例如归一化互相关(简单模板匹配),以帮助识别球或至少可能的球位置。
  12. 坚持图像的中心点位于桌床内的某个位置。这可以帮助您识别导轨的位置,因为您可以径向向外搜索导轨的边缘,一旦找到四个(甚至三个)导轨,您就可以拒绝超出它们径向距离的边缘点。

祝你好运!这是一个有趣的问题。

编辑: 我正在阅读另一篇 StackOverflow 帖子并阅读了这篇论文。这篇论文将更全面地介绍我建议的过滤边缘点的技术(第 8 项)。

Rad、Faez 和 Qaragozlou 的“使用梯度对向量的快速圆检测” http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.121.9956

我自己还没有实现他们的算法,但看起来很有希望。这是提到该论文的帖子:

Three Dimensional Hough Space

【讨论】:

    猜你喜欢
    • 2014-03-13
    • 1970-01-01
    • 2017-04-04
    • 2014-10-17
    • 1970-01-01
    • 1970-01-01
    • 2017-08-08
    • 2016-12-28
    • 2021-03-11
    相关资源
    最近更新 更多