Надёжно найдите N кругов с одинаковым диаметром: альтернатива грубой силе порога преобразования Hough - программирование
Подтвердить что ты не робот

Надёжно найдите N кругов с одинаковым диаметром: альтернатива грубой силе порога преобразования Hough

Я разрабатываю приложение для отслеживания мелких животных в чашках Петри (или других круговых контейнерах). Прежде чем будет выполнено отслеживание, первые несколько кадров используются для определения областей. Каждое блюдо будет соответствовать круговой независимой статической области (т.е. Не будет обновляться во время отслеживания). Пользователь может запросить программу, чтобы попытаться найти блюда из исходного изображения и использовать их в качестве областей.

Вот примеры: enter image description hereenter image description here

Чтобы выполнить эту задачу, я использую Преобразование Hough Circle. Но на практике у разных пользователей будут очень разные настройки и изображения, и я не хочу просить пользователя вручную определять параметры. Я не могу просто угадать все параметры.

Однако у меня есть дополнительная информация, которую я хотел бы использовать:

Я знаю точное количество обнаруженных кругов.

  • Все круги имеют почти одинаковые размеры.
  • Круги не могут перекрываться.
  • У меня есть приблизительное представление о минимальном и максимальном размере кругов.
  • Кружки должны быть полностью на картинке.

Поэтому я могу сузить число параметров, чтобы определить один: порог. Используя эту информацию и учитывая, что у меня есть N кругов, чтобы найти, мое текущее решение проверьте множество значений порога и сохраните круги, между которыми стандартное отклонение является наименьшим (так как все круги должны иметь одинаковый размер):

//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;
        }
    }
}

С

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

}

Я достиг более высокой точности, выполнив второй проход, в котором я повторил этот алгоритм, сужая интервал [minRad: maxRad], используя результат первого прохода.

Например, minRad2 = 0,95 * средний радиус лучших кругов и maxRad2 = 1.05 * средний радиус лучших кругов.

У меня были довольно хорошие результаты, используя этот метод. Однако он медленный и довольно грязный. Мои вопросы:

  • Вы можете использовать любой альтернативный алгоритм для решения этой проблемы более чистым/быстрым способом?
  • Или что вы предложите улучшить этот алгоритм?
  • Как вы думаете, я должен исследовать обобщенное преобразование Хафа?

Спасибо за ваши ответы и предложения.

4b9b3361

Ответ 1

Следующий подход должен хорошо работать для вашего случая:

  • Сделайте бинаризацию изображения (вам может потребоваться сделать это на нескольких уровнях порога, чтобы сделать алгоритм независимым от условий освещения)
  • Найти контуры
  • Для каждого контура вычисляют моменты
  • Отфильтруйте их по области, чтобы удалить слишком маленькие контуры.
  • Контуры фильтра по округлости:

    double area = moms.m00;
    double perimeter = arcLength(Mat(contours[contourIdx]), true);
    double ratio = 4 * CV_PI * area / (perimeter * perimeter);
    

    ratio рядом с 1 даст вам круги.

  • Рассчитать радиус и центр каждой окружности

    center = Point2d(moms.m10 / moms.m00, moms.m01 / moms.m00);
    

И вы можете добавить больше фильтров для повышения надежности.

На самом деле вы можете найти реализацию всей процедуры в OpenCV. Посмотрите, как реализованы функции SimpleBlobDetector и findCirclesGrid.

Ответ 2

В текущем алгоритме самая большая вещь, которая торчит, - это цикл for(int t=5; t<400; t=t+2). Попытка записать значения оценки для некоторых тестовых изображений. График score(t) по сравнению с t. Если повезет, он предложит меньший диапазон для t или будет гладкой кривой с одним максимумом. В последнем случае вы можете изменить цикл по всем значениям t в более интеллектуальный поиск, используя методы Hill Climbing.

Даже если он довольно шумный, вы можете сначала перебрать несколько кратных, скажем, 30, а для лучших 1 или 2 из этих циклов по соседним кратным 2.

Кроме того, в вашей функции оценки вы должны дисквалифицировать любые результаты с перекрывающимися кругами и, возможно, наказывать чрезмерно разнесенные круги.

Ответ 3

Вы не объясняете, почему используете черный фон. Если вы не используете телецентрическую линзу (что кажется маловероятным, учитывая видимое поле зрения) и игнорируя радиальное искажение на данный момент, изображения блюд будут эллипсами, поэтому их оценка в виде кругов может привести к значительным ошибкам.

Все и все, мне не кажется, что вы следуете хорошему подходу. Если целью является просто удалить фон, чтобы вы могли отслеживать ошибки внутри блюд, тогда ваша цель должна быть такой: найдите, какие пиксели являются фоном и отметьте их. Самый простой способ сделать это - сделать снимок фона без посуды под тем же освещением и камерой, а также напрямую обнаружить различия с изображением с изображениями. Для этого предпочтительнее цветной фон, при этом цвет вряд ли появится в посуде (например, зеленый или синий бархат). Таким образом, вы бы уменьшили проблему до bluescreening (или цветной манипуляции), классической техники в машинном зрении применительно к визуальным эффектам. Сделайте поиск в Google для "предположения о матовом нефтяном влахе", чтобы найти классические алгоритмы для решения этой проблемы.