Детектирование округлостей на изображении средствами MATLAB

image
В этом топике я приведу альтернативный подход к задаче, решенной товарищем VasG тут. Как заметили в комментариях, задачу обнаружения округлостей на изображении можно было решить при помощи MATLAB Image Processing Toolbox, что я и сделал. MATLAB радует меня очень сильной документацией с большим количеством наглядных примеров; а также удобством m-языка, за счет которого сильно сокращается время реализации вычислительных решений. Конечно, есть и минусы — в частности алгоритмы работают медленно, — но для данной задачи это не существенно. Отмечу только, что из m-языка довольно просто можно получить C-код, который будет работать гораздо быстрее.

Я старался писать с нуля, исходя из формулировки задачи и не пользуясь алгоритмическими наработками VasG. Естественно, в силу простоты задачи решения очень похожи. В хелпе MATLAB'а по Image Processing Toolbox обнаружился набор демок, посвященных детектированию объектов и в частности поиску круглых форм, что мне очень помогло. Далее приводится код полученного алгоритма на m-языке:

img = imread('kkk.jpg');
grayimg = rgb2gray(img);
grayimg = imadjust(grayimg);
bw = edge(grayimg,'canny', 0.15, 2);
bw = imfill(bw,'holes');
se = strel('disk',1);
bw = imopen(bw,se);

[B,L] = bwboundaries(bw);
stats = regionprops(L,'Centroid','EquivDiameter');
figure, imshow(img)
hold on
for k = 1:length(B)
 boundary = B{k};
 radius = stats(k).EquivDiameter/2;
 xc = stats(k).Centroid(1);
 yc = stats(k).Centroid(2);
 theta = 0:0.01:2*pi;
 Xfit = radius*cos(theta) + xc;
 Yfit = radius*sin(theta) + yc;
 plot(Xfit, Yfit, 'g');
 text(boundary(1,2)-15,boundary(1,1)+15, num2str(radius,3),'Color','y',...
  'FontSize',8);
end


Заметьте, в нем всего 30 строчек. Из них половина реализует красивый вывод результата. Давайте разберем код.
img = imread('kkk.jpg'); — открываем наше изображение. Я использовал изображение из статьи VasG.
image

grayimg = rgb2gray(img); — переводим изображение в оттенки серого.
grayimg = imadjust(grayimg); — контрастируем.
image

bw = edge(grayimg,'canny', 0.15, 2); — выделяем границы методом Канни. Функция edge предлагает возможность использования алгоритмов Собеля, Робертса, Прюитта и некоторых других, но я, как и VasG, остановил свой выбор на Канни, потому что он, как мне кажется, работает лучше всего. Параметры подбирались эмпирически, чтобы выделялись границы всех объектов на изображении.
image

bw = imfill(bw,'holes'); — заливаем замкнутые области на изображении.
image

Далее необходимо избавиться от тонких линий.
se = strel('disk',1); — формируем структурный элемент, крест 3 на 3.
bw = imopen(bw,se); — морфологическое открытие, тонкие линии исчезают.
image

[B,L] = bwboundaries(bw); — данная функция выдает два результата. B — ячеечный массив размера P х 1, где P — кол-во объектов на изображении. Элементы массива B — матрицы размером Q х 2, где Q — количество пикселей, принадлежащих границе соответствующего объекта. Строки матрицы Q — координаты этих граничных пикселей. L — матрица, размер которой равен размеру изображения, содержащая неотрицательные числа, которые соответствуют замкнутым областям. Регион с номером k на матрице L обозначается элементами со значением k. Фону соответствует 0.
stats = regionprops(L,'Centroid','EquivDiameter'); — эта функция создает массив структур stats, поля элеметнов которого Centroid и EquivDiameter содержат соответственно координаты центра области и (в нашем случае) диаметр области.
Собственно задача решена. Дальше реализуется вывод результатов.
image

Результаты аналогичны тем, что были получены VasG с точностью до коэффициентов некоторых функций. Времени на реализацию было потрачено примерно столько же, сколько на оформление данной статьи, примерно около часа. VasG, насколько понятно по статье, потратил на порядок больше времени. У меня довольно большой опыт работы с MATLAB, но я считаю, даже если человек не знаком с m-языком, за рабочий день можно разобраться в системе и написать подобную реализацию. Таким образом налицо высокая скорость реализации решений прикладных задач в системе MATLAB. Советую VasG, а также другим научным сотрудникам и инженерам оценить для себя систему MATLAB в действии!

upd. Заменил пару imerode+imdilate на imopen. Спасибо ScayTrase.

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 46

    +2
    Класс! Решение буквально в 10 строк, демонстрирующее всю мощь данного математического пакета, на мой взгляд, незаменимого для науки инструмента.

    P.S.: И спасибо, что напомнили недалекое прошлое, когда используя матлаб для расчётов и построения графиков, я написал нехилый диплом и поступил в аспирантуру. Прям руки зачесались поставить его вновь и применить его для решения одной старенькой, для меня, задачи.
      0
      Не за что! Если я правильно понимаю, вы давно не открывали MATLAB — в таком случае он может удивить вас новыми вкусными плюшками, которые добавляются с каждой новой версией — они сейчас выходят два раза в год.
        0
        Ну, не то, чтобы давно: где-то года 3 назад. Как раз поставил, сейчас буду удивляться.
        +1
        вы видимо с IDL не знакомы, раз говорите о незаменимости матлаба в научных делах:)
        0
        Вот это уже TRUE. Я и рассчитывал увидеть алгоритмы цифры и прочее, а там были игры в фотошоп какие-то. Спасибо
          +1
          Агррр.
            +1
            Ну будет Вам, я же любя)
          0
          Решение прекрасное. Есть мелкий баг — иногда детектится внешний контур, иногда внутренний; т.е. всегда есть ошибка в радиусе либо +delta, либо -delta.
          Но вообще — супер.

          Про bwboundaries я не знал.
              +2
              Хорошая задачка, вообще. Я бы (наверное) после нахождения контуров пробежался бы по всей картинке спец. фильтром для поиска окружностей, ну или более обще — эллипсов. Для него разрывы в контуре не проблемы.
              А потом искал бы пары вложенных окружностей с примерно общим центром и небольшим зазором, и усреднял бы их радиусы и центры.

              Другой вариант — искать не границы хребтов вокруг кратеров, а выделять сами хребты (т.е. трансформация IM -> (IM- Lowpass::Im).) И тогда можно искать самую высокую точку на хребте и т.п.

              Понятно, что можно построить совершенно устойчивое решение. Но для этого надо все-таки неделю-две повозиться.
                +1
                Примерно над этим я сейчас, честно говоря, и работаю. Есть уже определённые положительные результаты, и я скоро собираюсь ими поделиться на Хабрахабре. Заодно покажу пару картинок, к которым подобные преобразоания неприменимы, т.к. объекты либо имеют слегка неправильную форму, либо нечеткие границы.
                Вот, к примеру, изображение, на котором выбранный алгоритм преобразования работает не совсем так, как хотелось бы.
                (картинкой вставить не даёт, поэтому ссылки...)
                Исходное изображение. Результат.
                Как можно заметить, часть форм не обнаруживается. Большая часть мелких частиц обнаруживается, но большие — нет. Т.к. важно статистическое распределение, то это критично. Вот пытаюсь сейчас разрешить эту проблемку…
                  +1
                  Мда… попробуйте создать базу данных из 100 наиболее типчных колечек разных диамтеров, и посчитайте корреляцию с каждым из них по всей картинке.
                  Получится 100 картинок, отражающих вероятность что именно это колечко здесь расположено, в данной точке (x,y).
                  Threshold уровни должны быть разные у больших и маленьких колечек.
                  Во время свертки учитывайте только пиксели на границе и внутри колец, т.е. ядро свертки должно быть круглым а не квадратным.
                    0
                    Перед этим, конечно, pre-processing:
                    1) convert to greyscale
                    2) убрать фоновый уровень
                    3) выровнять локальную контрастность (убрать градиент освещения и т.п.)
                      +1
                      И это, как я понимаю, изначально полагалось вручную обрабатывать? Жесть!

                      Еще подход — без перехода к оттенкам серого. Как нетрудно заметить, изображение состоит по сути из трех цветов — белого (внутри объектов), черного (границы объектов) и фиолетового (фон). Переводим изображение в цветовое простанство HSV — тон, насыщенность, яркость. Яркость нам не нужна, используем только информацию о цвете. Кластеризуем точки изображения в координатах Тон-Насыщенность методом К-средних по метрике Евклида, вот что получается.

                      Видны косяки, связанные с градиентом освещения — внизу изображение слишком светлое, а сверху-слева слишком темное. Но освещение, я так понимаю, можно настроить… Белым — наши объекты, заметьте даже очень мелкие выделились.

                      Такой метод можно использовать наравне с остальными и затем объединить результаты.
                        0
                        Насчет того, что яркость нам не нужна — это Вы, я думаю, погорячились! :)
                        А белый цвет там результат overexposure, к сожалению. Так что никакой значимой информации он не добавляет.
                        Жалко, конечно. Признаюсь, я вначале тоже об этом думал…
                          0
                          На самом деле яркость я отбросил, чтобы избавиться от градиента освящения, но что-то не очень получилось.

                          Хм, засветка есть, и правда… Только почему белый цвет не несет информации? Это блики от объектов — фон ведь не бликует. Соответственно, кмк, по бликам их вполне можно определять.
                        • UFO just landed and posted this here
                      0
                      Расскажите пожалуйста о каком спец фильтре идет речь? для поиска окружностей? Решаю такую же задачу, только в круге есть текстура. Контура из за этого слегка рвутся. И таким образом задачка не решается. Дилатация конечно соединяет рваные контуры, но контур становится толстым, и его сложно трассировать. Сейчас есть алгоритм трассировки контура когда у каждой точки контура не более двух соседей, если контур толще — то не ясно как его трассировать. Говорят есть алгоритм Suzuki85 для этого однако описания нормального в научной литературе не нашел.
                      • UFO just landed and posted this here
                          0
                          Снаружи — есть текстура, все что угодно, у меня тестовые примеры на столе, а стол весь из дерева с характерным рисунком. Детектор Канни первым этапом предполагает применение фильтра гаусса, текстура внутри очень сложная, может на самом деле все что угодно. В общем буду допытываться до автора предыдущей статьи, там мне больше идея с заливкой понравилась.
                          • UFO just landed and posted this here
                          0
                          Толстые контуры можно скелетизировать алгоритмом Зонга-Суня (Zhang-Suen), или пустить по контуру «волну» и отслеживать её центр (где-то видел описание такого алгоритма, сейчас с ходу не вспомню, но могу найти).
                        • UFO just landed and posted this here
                            0
                            См. мою статью, указанную в начале этой :)
                            • UFO just landed and posted this here
                    • UFO just landed and posted this here
                        0
                        Да, к сожалению стоимость высока… Но есть опенсорсный аналог — SciLab, работал в нем не очень много, поэтому сравнивать по функционалу не могу.
                          0
                          Когда нужно было делать семестровки по численным методам, делал в octave, тоже опенсорсный аналог. Про функционал тоже не знаю — на семестровки хватало (и потом успешно запускалось в MATLAB), а более серьезных вещей не делал.
                        0
                        Лучшая реклама матлаба и антиреклама велосипедов.

                        >имперически
                        эмпирически, наверно.
                          +4
                          Велосипеды тоже нужны. Все нужно.
                          Матлаб — сильное оружие, но если не понимать в точности, как каждая его функция работает, то далеко не уедешь. А если понимать, то по большому счету не важно в какой среде писать.
                          Хотя для разработки алгоритмов matlab супер удобный.
                            0
                            Спасибо, поправил.
                              0
                              Велосипед хорошо, катаюсь когда тепло.
                              0
                              > диляция
                              Вроде как «дилатация» будет правильней.

                              И, да, почему именно Канни? Тоже эмпирически?
                                0
                                Судя по английской вики, диляция и дилатация — одно и то же. Я привык к термину 'диляция'.

                                Канни — эмпирически, время на исследование эффективности различных методов не тратил.
                                  +1
                                  В Гонсалесе-Вудсе перевели как «дилатация». Хотя, возможно, дело вкуса.
                                0
                                Хорошая демонстрация возможностей Матлаба.
                                Интересно, на каких-нибудь opensource аналогах, том же SciLab или Octave, например, можно добиться такого же быстрого решения?
                                  +1
                                  В OpenCV можно сделать то же самое, примерно в то же количество строк.
                                • UFO just landed and posted this here
                                    0
                                    Спасибо! Почему то даже и не вспомнил об imopen. Внес исправление.
                                    • UFO just landed and posted this here
                                    0
                                    LabVIEW Vision же есть :)
                                      +1
                                      Здорово! Спасибо, что не поленились написать! Я всерьез задумался об использовании MATLAB'a… Я действительно потратил на порядок больше времени, но в него входило изучение нового языка и т.п.
                                      Ещё раз спасибо!
                                        +1
                                        Вам спасибо за вдохновение! :)
                                        –2
                                          0
                                          Одна из актуальных и прикладных задач, которую я к сожалению лет 10 назад профакапил — определение «правильной круглости» колец Ньютона для тестирования зеркал лазерной сварки. Используются в автомобильной промышленности. Получалось что зеркала Российского производства выгодно дешевле, но немцев не убедило — главное для них было качество (что и надо было обеспечить) и высокая цена была заложена в стоимость мерседесов, бмв и прочих ауди.
                                            +3
                                            Если знаешь как, то это можно сделать во многих математических пакетах. Например, в Mathematica:
                                            SetDirectory[NotebookDirectory[]];
                                            img = Import["kkk.jpg", "Graphics"];
                                            grayimg = ImageAdjust[ColorConvert[img, "Grayscale"]] ;
                                            bw = FillingTransform[EdgeDetect[grayimg, Method -> "Canny"]];
                                            bw = Binarize[Blur[bw, 4]];
                                            components = {#[[2, 2]], #[[2, 1]]} & /@ ComponentMeasurements[bw, {"EquivalentDiskRadius", "Centroid"}];
                                            ImageDimensions[img]
                                            Show[
                                                img,
                                                Graphics[{Red, Circle @@ #} & /@ components],
                                                Graphics[Text[Style[NumberForm[#2, 3], 15, Yellow], #1 - (#2/Sqrt[2] + 6)] & @@ # & /@ components]
                                            ]

                                            Only users with full accounts can post comments. Log in, please.