用OpenCV检测台球

时间:2011-11-17 04:44:06

标签: android opencv computer-vision

我正在制作一个Android应用程序,它正在拍摄正在进行的台球游戏的图像,并检测各种球的位置。图像来自某人的手机,所以我当然没有完美的桌面俯视图。现在我正在使用houghcircles找到球,并且它做得很好,但它似乎在这里和那里错过了几个球,然后有误报。

我现在最大的问题是,如何减少在牌桌外发现的误报?我正在使用投资回报率来切断图像的顶部,因为它主要是浪费空间,但是我不能让它变得更小或者我冒着切掉桌子部分的风险,因为它是一个梯形形状。我目前的想法是覆盖用户在拍摄图像顶部时看到的指南,但问题是我不知道他们的相机的分辨率是多少,因此叠加可能会覆盖错误的地方。理想情况下,我想我会想要使用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);

2 个答案:

答案 0 :(得分:4)

您可以应用一些非常有用的约束。除了做一个感兴趣的矩形区域,你应该用池桌的实际梯形形状掩盖你的结果。使用图像的颜色信息查找池表区域。您知道台球桌是纯色。它不必是绿色的 - 你可以在HSV色彩空间中使用一些histogram技术来找到图像中最流行的颜色,也许有利于像素朝向中心。它很可能检测到台球桌的颜色。选择与此颜色匹配的像素,执行形态学操作以消除噪声,然后您可以将蒙版视为轮廓,并找到其convexHull。填充船体以移除池球产生的孔。

到目前为止我所说的应该提出一种与霍夫圈不同的方法。由于台球没有均匀照明,霍夫圈可能效果不佳。因此,找到台球的另一种方法是从其convexHull中减去池表颜色掩码。你会留下桌子上被球遮挡的区域。

答案 1 :(得分:0)

我也在考虑解决这个问题,因为我玩游泳池和斯诺克。

几点:

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

    修改 我正在阅读另一篇StackOverflow帖子并阅读本文。这篇论文将为您提供更加全面的介绍我建议过滤边缘点的技术(第8项)。

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

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

    Three Dimensional Hough Space