Обнаружение и измерение округлых объектов в изображении

В этом примере показано, как автоматически обнаружить круги или округлые объекты в изображении и визуализировать обнаруженные круги.

Шаг 1: Загрузка изображения

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

  1. Существуют фишки разных цветов, которые имеют разные контрасты относительно фона. На одном конце синие и красные таковые имеют сильную контрастность на этом фоне. На другом конце некоторые желтые фишки плохо контрастируют с фоном.

  2. Заметьте, как одни фишки находятся на верхнюю часть друг друга, а другие - близко друг к другу и почти касаются друг друга. Перекрываемые контуры объектов и окклюзия объектов обычно являются сложными сценариями для обнаружения объектов.

rgb = imread('coloredChips.png');
imshow(rgb)

Шаг 2: Определите область значений радиуса для ищущих кругов

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

d = drawline;

Длина линии ROI является диаметром чипа. Типичные чипы имеют диаметры в области значений от 40 до 50 пикселей.

pos = d.Position;
diffPos = diff(pos);
diameter = hypot(diffPos(1),diffPos(2))
diameter = 45.3448

Шаг 3: Начальная попытка найти круги

The imfindcircles функция ищет круги с областью значений радиусов. Поиск кругов с радиусами в области значений от 20 до 25 пикселей. Перед этим рекомендуется спросить, ярче ли объекты или темнее фона. Чтобы ответить на этот вопрос, посмотрите на полутоновую версию этого изображения.

gray_image = rgb2gray(rgb);
imshow(gray_image)

Фон довольно яркий и большинство фишек темнее фона. Но, по умолчанию, imfindcircles находит округлые объекты, которые ярче фона. Итак, установите параметр 'ObjectPolarity' на 'dark' в imfindcircles для поиска темных кругов.

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark')
centers =

     []


radii =

     []

Обратите внимание, что выходы centers и radii пусты, что означает, что круги не были найдены. Это происходит часто, потому что imfindcircles - детектор окружностей, и подобный большинству детекторов, imfindcircles имеет внутренний порог обнаружения, который определяет его чувствительность. Простыми словами, это означает, что доверие детектора в определенном (круговом) обнаружении должна быть больше, чем определенный уровень, прежде чем это считается допустимым обнаружением. imfindcircles имеет параметр 'Sensitivity', который может использоваться, чтобы контролировать этот внутренний порог, и, следовательно, чувствительность алгоритма. Более высокое значение 'Sensitivity' устанавливает порог обнаружения ниже и приводит к обнаружению большего количества кругов. Это похоже на управление чувствительностью на детекторах движения, используемых в домашних системах безопасности.

Шаг 4: Увеличение чувствительности обнаружения

Возвращаясь к чиповому изображению, возможно, что на уровне чувствительности по умолчанию все круги ниже внутреннего порога, из-за чего круги не были обнаружены. По умолчанию 'Sensitivity', которое является числом от 0 до 1, устанавливается на 0,85. Увеличьте 'Sensitivity' до 0,9.

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark', ...
    'Sensitivity',0.9)
centers = 8×2

  146.1895  198.5824
  328.8132  135.5883
  130.3134   43.8039
  175.2698  297.0583
  312.2831  192.3709
  327.1316  297.0077
  243.9893  166.4538
  271.5873  280.8920

radii = 8×1

   23.1604
   22.5710
   22.9576
   23.7356
   22.9551
   22.9995
   22.9055
   23.0298

На этот раз imfindcircles нашел некоторые круги - восемь, чтобы быть точным. centers содержит местоположения центров окружностей и radii содержит предполагаемые радиусы этих кругов.

Шаг 5: Нарисуйте круги на изображении

Функция viscircles может использоваться для рисования кругов на изображении. Выходные переменные centers и radii от imfindcircles может быть передан непосредственно в viscircles.

imshow(rgb)
h = viscircles(centers,radii);

Центры окружностей кажутся правильно расположенными, и их соответствующие радиусы, кажется, хорошо соответствуют фактическим фишкам. Но все же было пропущено довольно много фишек. Попробуйте увеличить 'Sensitivity' еще больше, до 0,92.

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark', ...
    'Sensitivity',0.92);

length(centers)
ans = 16

Поэтому увеличение «Чувствительности» принесет нам еще больше кругов. Снова постройте графики этих кругов на изображении.

delete(h)  % Delete previously drawn circles
h = viscircles(centers,radii);

Шаг 6: Используйте второй метод (двухэтапный) для нахождения кругов

Этот результат выглядит лучше. imfindcircles имеет два разных метода нахождения кругов. До сих пор метод по умолчанию, называемый методом фазового кодирования, использовался для обнаружения кругов. Существует другой метод, в народе называемый двухэтапным методом, который доступен в imfindcircles. Используйте двухэтапный метод и отобразите результаты.

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark', ...
          'Sensitivity',0.92,'Method','twostage');

delete(h)
h = viscircles(centers,radii);

Двухэтапный метод обнаруживает больше кругов, при Чувствительности 0,92. В целом, эти два метода являются взаимодополняющими, в которых они имеют различные сильные стороны. Метод фазового кодирования обычно быстрее и немного более устойчивый к шуму, чем двухэтапный метод. Но ему также могут потребоваться более высокие уровни 'Sensitivity', чтобы получить то же количество обнаружений, что и двухэтапному методу. Для примера способ фазы кодирования также находит те же микросхемы, если уровень 'Sensitivity' повышен, скажем, до 0,95.

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark', ...
          'Sensitivity',0.95);

delete(h)
viscircles(centers,radii);

Обратите внимание, что оба метода в imfindcircles точно найти центры и радиусы частично видимых (окклюдированных) чипов.

Шаг 7: Почему некоторые круги все еще пропускаются?

Глядя на последний результат, любопытно, что imfindcircles не находит желтые фишки на изображении. Желтые фишки не имеют сильной контрастности с фоном. На самом деле они, кажется, имеют очень похожую интенсивность, как фон. Возможно ли, что желтые фишки на самом деле не «темнее» фона, как предполагалось? Чтобы подтвердить, снова отобразите полутоновую версию этого изображения.

imshow(gray_image)

Шаг 8: Найти 'Bright' круги в изображении

Желтые фишки почти такой же интенсивности, может быть, даже ярче, по сравнению с фоном. Поэтому, чтобы обнаружить желтые чипы, смените 'ObjectPolarity' на 'bright'.

[centersBright,radiiBright] = imfindcircles(rgb,[20 25], ...
    'ObjectPolarity','bright','Sensitivity',0.92);

Шаг 9: Рисуйте 'яркие' круги с другим цветом

Нарисуйте яркие круги в другом цвете, изменив параметр 'Color' в viscircles.

imshow(rgb)

hBright = viscircles(centersBright, radiiBright,'Color','b');

Обратите внимание, что три недостающих желтых фишки были найдены, но один желтый чип все еще отсутствует. Эти желтые фишки трудно найти, потому что они не так хорошо выделяются, как другие на этом фоне.

Шаг 10: Уменьшите значение 'EdgeThreshold'

Есть еще один параметр в imfindcircles который может быть полезен здесь, а именно 'EdgeThreshold'. Чтобы найти круги, imfindcircles использует только ребро пикселей в изображении. Эти краевые пиксели по существу являются пикселями с высоким значением градиента. Параметр 'EdgeThreshold' управляет тем, насколько высоким должно быть значение градиента в пикселе, прежде чем он рассматривается как краевой пиксель и включается в расчеты. Высокое значение (ближе к 1) для этого параметра позволит включать только сильные ребра (более высокие значения градиента), в то время как низкое значение (ближе к 0) является более допустимым и включает даже более слабые ребра (более низкие значения градиента) в расчете. В случае отсутствующего желтого чипа, поскольку контрастность является низкой, ожидается, что некоторые краевые пиксели (по окружности чипа) будут иметь низкие градиентные значения. Поэтому уменьшите параметр 'EdgeThreshold', чтобы убедиться, что большинство ребра пикселей для желтого чипа включены в расчет.

[centersBright,radiiBright,metricBright] = imfindcircles(rgb,[20 25], ...
    'ObjectPolarity','bright','Sensitivity',0.92,'EdgeThreshold',0.1);

delete(hBright)
hBright = viscircles(centersBright, radiiBright,'Color','b');

Шаг 11: Рисуйте 'Dark' и 'Bright' Circles вместе

Теперь imfindcircles находит все желтые таковые и зеленые тоже. Нарисуйте эти фишки синим цветом, вместе с другими фишками, которые были найдены ранее (с установленным на 'dark' значением 'ObjectPolarity'), красным цветом.

h = viscircles(centers,radii);

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

Счастливая охота за кругом!

См. также

|

Похожие темы