Encontre robustamente N círculos com o mesmo diâmetro: alternativa ao bruteforcing Hough transform threshold

Estou desenvolvendo aplicações para rastrear pequenos animais em placas de Petri (ou outros recipientes circulares). Antes de qualquer rastreamento, os primeiros quadros são usados ​​para definir áreas. Cada prato corresponderá a uma área estática independente circular (ou seja, não será atualizada durante o rastreamento). O usuário pode solicitar que o programa tente encontrar pratos da imagem original e usá-los como áreas.

Aqui estão alguns exemplos:

Para executar essa tarefa, estou usandoHough Circle Transform. Mas, na prática, usuários diferentes terão configurações e imagens muito diferentes e eu não quero pedir ao usuário para definir manualmente os parâmetros. Não posso adivinhar todos os parâmetros também.

No entanto, tenho informações adicionais que gostaria de usar:

Eu sei o número exato de círculos a serem detectados.

Todos os círculos têm as mesmas dimensões.Os círculos não podem se sobrepor.Eu tenho uma idéia aproximada do tamanho mínimo e máximo dos círculos.Os círculos devem estar inteiramente na foto.

Por isso, posso diminuir o número de parâmetros para definir um:o limiar. Usando essas informações e considerando que eu tenho N círculos para encontrar,minha solução atual é testar muitos valores de limiar e manter os círculos entre os quais o desvio padrão é o menor (desde que todos os círculos devem ter um tamanho similar):

//at this point, minRad and maxRad were calculated from the size of the image and the number of circles to find.
//assuming circles should altogether fill more than 1/3 of the images but cannot be altogether larger than the image.
//N is the integer number of circles to find.
//img is the picture of the scene (filtered).

//the vectors containing the detected circles and the --so far-- best circles found.
std::vector<cv::Vec3f> circles, bestCircles;

//the score of the --so far-- best set of circles
double bestSsem = 0;

 for(int t=5; t<400 ; t=t+2){
//Apply Hough Circles with the threshold t
    cv::HoughCircles(img, circles, CV_HOUGH_GRADIENT, 3, minRad*2, t,3, minRad, maxRad );

    if(circles.size() >= N){
//call a routine to give a score to this set of circles according to the similarity of their radii
        double ssem = scoreSetOfCircles(circles,N);
//if no circles are recorded yet, or if the score of this set of circles is higher than the former best
        if( bestCircles.size() < N ||  ssem > bestSsem){
//this set become the temporary best set of circles
                bestCircles=circles;
                bestSsem=ssem;
        }
    }
}

Com:

 //the methods to assess how good is a set of circle (the more similar the circles are, the higher is ssem)
    double scoreSetOfCircles(std::vector<cv::Vec3f> circles, int N){
    double ssem=0, sum = 0;
        double mean;
        for(unsigned int j=0;j<N;j++){
            sum = sum + circles[j][2];
        }
        mean = sum/N;
        for(unsigned int j=0;j<N;j++){
            double em = mean - circles[j][2];
            ssem = 1/(ssem + em*em);
        }
    return ssem;

}

Cheguei a uma maior precisão executando uma segunda passagem na qual eu repeti esse algoritmo estreitando o intervalo [minRad: maxRad] usando o resultado da primeira passagem.

Por exemplo, minRad2 = 0,95 * raio médio dos melhores círculos e maxRad2 = 1,05 * raio médio dos melhores círculos.

Eu tive resultados bastante bons usando este método até agora. No entanto, é lento e bastante sujo. Minhas perguntas são:

Você pode coisa de qualquer algoritmo alternativo para resolver este problema de uma maneira mais limpa / mais rápida?Ou o que você sugeriria para melhorar este algoritmo?Você acha que eu deveria investigar a transformação generalizada de Hough?

Obrigado por suas respostas e sugestões.

questionAnswers(3)

yourAnswerToTheQuestion