Detectando bolas de billar con OpenCV

Estoy creando una aplicación de Android que toma una imagen de un juego de billar en curso y detecta las posiciones de las diferentes bolas. La imagen está tomada del teléfono de alguien, así que, por supuesto, no tengo una vista aérea perfecta de la mesa. En este momento estoy usando houghcircles para encontrar las bolas, y está haciendo un buen trabajo, pero parece fallar algunas bolas aquí y allá, y luego están los falsos positivos.

Mi mayor problema en este momento es, ¿cómo puedo reducir los falsos positivos que se encuentran fuera de la mesa? Estoy usando un ROI para cortar la parte superior de la imagen porque es en su mayoría espacio desperdiciado, pero no puedo hacerlo más pequeño o me arriesgo a cortar partes de la mesa ya que es una forma trapezoidal. Mi idea actual es superponer la guía que el usuario ve al tomar la imagen encima de la imagen, pero el problema es que no sé cuál sería la resolución de sus cámaras y, por lo tanto, la superposición podría cubrir en los lugares equivocados Idealmente, creo que me gustaría usar líneas de prueba, pero cuando lo probé, mi aplicación se bloqueó por lo que creo que era una falta de memoria. ¿Algunas ideas

Aquí hay un enlace a los resultados que obtengo:

http: //graphiquest.com/cvhoughcircles.htm

Aquí está mi código:

    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);

Respuestas a la pregunta(2)

Su respuesta a la pregunta