Измерение средней толщины следов на изображении - PullRequest
19 голосов
/ 17 сентября 2010

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

Первое изображение - размер: 711 x 643 px

711 x 643 example image

Второе изображение - размер: 930 x 951 px

alt text

Мне нужно измерить среднюю толщину (в пикселях) следов на изображениях. Фактически, средняя толщина следов на изображении является несколько субъективной мерой. Итак, мне нужна мера, которая имеет некоторую корреляцию с радиусом трассы, как показано на рисунке ниже:

alt text

Примечания

  • Поскольку мера не должна быть очень точной, я готов обменять точность на скорость. Другими словами, скорость является важным фактором для решения этой проблемы.

  • В трассах могут быть пересечения.

  • Толщина следа может быть не постоянной, но средний показатель в порядке (даже максимальная толщина следа приемлема).

  • Трасса всегда будет намного длиннее, чем широкая.

Ответы [ 7 ]

19 голосов
/ 17 сентября 2010

Я бы предложил этот алгоритм:

  1. Применить преобразование расстояния к изображению, чтобы все пиксели фона были установлены в 0, а все пиксели переднего плана установлены на расстоянии от фона
  2. Найти локальные максимумы в преобразованном расстоянии изображения.Это точки в середине линий.Поместите их значения пикселей (т.е. расстояния от фона) изображения в список
  3. Рассчитать медиану или среднее значение этого списка
8 голосов
/ 18 сентября 2010

Я был впечатлен ответом @ nikie и попробовал ...

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

Программа на Mathematica:

m = Import["http://imgur.com/3Zs7m.png"]   (* Get image from web*)
s = Abs[ImageData[m] - 1];                 (* Invert colors to detect background *)
k = DistanceTransform[Image[s]]            (* White Pxs converted to distance to black*)
k // ImageAdjust                           (* Show the image *)
Max[ImageData[k]]                          (* Get the max stroke width *)

Сгенерированный результат:

alt text

Подходит числовое значение (28,46 px X 2)очень хорошо мое измерение 56 пикселей (хотя ваше значение 100px: *)

Редактировать - реализован полный алгоритм

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

m = Import["http://imgur.com/3Zs7m.png"];   (*Get image from web*)
s = Abs[ImageData[m] - 1];         (*Invert colors to detect background*)
k = DistanceTransform[Image[s]];   (*White Pxs converted to distance to black*)
Print["Distance to Background*"]
k // ImageAdjust                   (*Show the image*)
Print["Local Maxima"]
weights = 
    Binarize[FixedPoint[ImageAdjust@DistanceTransform[Image[#], .4] &,s]]  
Print["Stroke Width =", 
     2 Mean[Select[Flatten[ImageData[k]] Flatten[ImageData[weights]], # != 0 &]]]

alt text

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

4 голосов
/ 17 сентября 2010

С Здесь . Простой метод!

3,1 Оценка ширины пера

Толщина пера может быть легко оценена по площади A и длине L периметра переднего плана

T = A/(L/2)

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

Хотя точность не является серьезной проблемой, нам нужно учитывать предвзятость и особенности.

Поэтому мы должны рассчитать площадь A и длину L периметра, используя функции, которые учитывают «округлость». В MATLAB

A = bwarea(.)  
L = bwarea(bwperim(.; 8))

Поскольку у меня нет MATLAB под рукой, я создал небольшую программу в Mathematica:

m = Binarize[Import["http://imgur.com/3Zs7m.png"]] (* Get Image *)
k = Binarize[MorphologicalPerimeter[m]]            (* Get Perimeter *)
p = N[2 Count[ImageData[m], Except[1], 2]/ 
    Count[ImageData[k], Except[0], 2]]             (* Calculate *)

Выход составляет 36 Px ...

Изображение периметра следует

alt text

НТН!

2 голосов
/ 02 апреля 2014

Прошло 3 года с тех пор, как был задан вопрос :) Следуя процедуре @nikie, вот реализация Matlab ширины штриха.

 clc;
 clear;
 close all;


I = imread('3Zs7m.png');
X = im2bw(I,0.8);

subplottight(2,2,1);
imshow(X);

Dist=bwdist(X);

subplottight(2,2,2);
imshow(Dist,[]);

RegionMax=imregionalmax(Dist);

[x, y] = find(RegionMax ~= 0);
subplottight(2,2,3);
imshow(RegionMax);

List(1:size(x))=0;
for i = 1:size(x) 
List(i)=Dist(x(i),y(i));
end

fprintf('Stroke Width = %u \n',mean(List));
1 голос
/ 18 сентября 2010

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

Основная идея: попробуйте вписать круг в черные области изображения.Если можете, попробуйте с большим кружком.

Алгоритм:

  • установить фоновое изображение = 0 и трассировку = 1
  • инициализировать результат массива []
  • установка минимального ожидаемого значения ширины
  • установка w = минимального ожидаемого размера
  • цикл
    • установка счетчика = 0
    • создание матрицы нулей размера wxw
    • в круге диаметра w в этой матрице, поместите единицы
    • вычислите площадь круга (= PI * w)
    • цикл по всем пикселям изображения
      • оптимизация: если текущий пиксель имеет цвет фона -> продолжить цикл
      • , умножьте матрицу на изображение в каждом пикселе (например, отфильтровав изображение с этой матрицей) (вы можете сделать этос использованием текущей позиции x и y и двойного цикла for от 0 до w)
      • берут сумму результата каждого умножения
      • , если сумма равна вычисленной площади круга, счетчик приращений увеличивается наодин
    • сохранить в результате [w - minimalExpectedWidth]
    • приращение w на одну
    • оптимизация: сюда включается алгоритм ниже
  • , когда счетчик больше нуля

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

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

Алгоритм:

  • установить максимум = 0
  • установить widthFound = 0
  • установить минимальную ожидаемую ширину, как указано выше
  • установить предыдущее значение = результат [0]
  • установить индекс = 1
  • установить prevFirstDerivative= результат [1] - превалирование
  • цикл до тех пор, пока индекс не станет больше длина результата
    • firstDerivative = результат [индекс] - превалирование
    • set secondDerivative = firstDerivative - prevFirstDerivative
    • if secondDerivative> Maximum или secondDerivative <максимум * -1 <ul>
    • максимум = secondDerivative
    • widthFound = index + minimalExpectedWidth
  • prevFirstDerivative = firstDerivative
  • prevvalue = результат [индекс]
  • индекс приращения на единицу
return widthFound

Теперь widthFound - ширина трассыдля которого (по отношению к ширине + 1) было найдено гораздо больше совпадений.

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

1 голос
/ 17 сентября 2010

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

Я предполагаю, что ошибка составляет до 25%.

Сначала используйте детектор кромок, который дает нам информацию, гдекрай и в каком направлении (с шагом 45 ° или PI / 4) он имеет.Это делается путем фильтрации по 4 различным матрицам 3х3 ( Пример ).
Обычно я бы сказал, что достаточно отсканировать изображение по горизонтали, хотя вы также можете сканировать по вертикали или диагонали.- при строчном (горизонтальном) сканировании, как только мы находим ребро, мы проверяем, является ли это повышением (переход от фона к цвету трассировки) или падением (к фону).Если направление кромки перпендикулярно направлению сканирования, пропустите его.
Если вы обнаружили один подъем и одно падение с правильными направлениями и без каких-либо помех между ними, измерьте расстояние от подъема до падения.Если направление диагональное, умножьте на квадратное корень из 2. Сохраните эту меру вместе с данными координат.

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

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

Пожалуйста, прокомментируйте, если есть еще вопросы.: -)

0 голосов
/ 18 сентября 2010

У меня есть интересное решение:

  1. Обнаружение края, для выделения пикселей края.
  2. Проводить физическое моделирование - рассматривать краевые пиксели как положительно заряженные частицы.
  3. Теперь поместите некоторое количество свободных положительно заряженных частиц в область удара.
  4. Рассчитать уравнения электрической силы для определения движения этих свободных частиц.
  5. Имитирует движение частиц в течение некоторого времени, пока частицы не достигнут положения равновесия. (Так как через некоторое время они будут отталкиваться от обоих краев горловины, они будут оставаться в средней линии горловины)
  6. Теперь толщина хода / 2 будет
    average distance from edge particle to nearest free particle.
...