Detectando bolas de bilhar com OpenCV

Estou criando um aplicativo para Android que captura uma imagem de um jogo de bilhar em andamento e detecta as posições das várias bolas. A imagem é tirada do telefone de alguém, então é claro que não tenho uma visão aérea perfeita da mesa. No momento, estou usando círculos difíceis para encontrar as bolas, e está fazendo um bom trabalho, mas parece que falta algumas bolas aqui e ali, e então existem os falsos positivo

Meu maior problema agora é: como reduzir os falsos positivos encontrados fora da mesa? Estou usando um ROI para cortar a parte superior da imagem, porque o espaço é desperdiçado, mas não posso diminuí-la ou corro o risco de cortar partes da tabela, pois é uma forma trapezoidal. Minha idéia atual é sobrepor o guia que o usuário vê ao tirar a foto em cima da imagem, mas o problema é que não sei qual seria a resolução das câmeras e, portanto, a sobreposição pode cobrir os pontos errados. Idealmente, acho que gostaria de usar linhas diretas, mas quando tentei, meu aplicativo falhou devido ao que acredito ser falta de memória. Alguma ideia

Aqui está um link para os resultados que estou obtendo:

http: //graphiquest.com/cvhoughcircles.htm

Aqui está o meu 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);

questionAnswers(2)

yourAnswerToTheQuestion