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.