title: Detecting billiard balls with OpenCV
body: <p>I'm  making an android app that takes an image of a billiards game in progress and detects the positions of the various balls. The image is taken from someone's phone, so of course I don't have a perfect overhead view of the table. Right now I'm using houghcircles to find the balls, and it's doing an ok job, but it seems to miss a few balls here and there, and then there are the false positives.</p>
  
  <p>My biggest problem right now is, how do I cut down on the false positives found outside the table? I'm using an ROI to cut off the top portion of the image because it's mostly wasted space, but I can't make it any smaller or I risk cutting off portions of the table since it's a trapezoidal shape. My current idea is to overlay the guide that the user sees when taking the picture on top of the image, but the problem with that is that I don't know what the resolution of the their cameras would be, and therefore the overlay might cover up the wrong spots. Ideally I think I would want to use houghlines but when I tried it my app crashed from what I believe was a lack of memory. Any ideas?</p>
  
  <p>Here is a link to the results I'm getting:</p>
  
  <p><a href="http://graphiquest.com/cvhoughcircles.html" rel="nofollow">http://graphiquest.com/cvhoughcircles.html</a> </p>
  
  <p>Here is my code:</p>
  
  <pre><code>    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&lt;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);
  </code></pre>