Обновленный
Хорошо, я имел взгляд на обновленной картины. Мой алгоритм сводится к следующим шагам.
Найти ярчайший Column (т.е. линии лазера) в Image
Найти Dark Gap в Brightest Колонке
Найти соседний столбец, Brightest в Gap в лазерной линии
Шаг 1 - Найдите самую яркую колонку (например, лазерную линию) в изображении
Самый простой способ сделать это - сжать изображение вниз, так что оно по-прежнему является его первоначальной шириной, но всего на один пиксель, эффективно усредняющий пиксели в каждом вертикальном столбце изображения. Затем примените -auto-level
, чтобы контрастировать растягивание со всем диапазоном 0-255 и пороговым значением на 95%, чтобы найти все столбцы, которые находятся в пределах 5% от самого яркого. Затем найдите пиксели с пороговым значением до белого (#ffffff). Это одна строка в ImageMagick, следующим образом:
convert http://i.stack.imgur.com/1P1zj.jpg -colorspace gray \
-resize x1! \
-auto-level \
-threshold 95% text: | grep -i ffffff
Выход:
297,0: (255,255,255) #FFFFFF white
298,0: (255,255,255) #FFFFFF white
299,0: (255,255,255) #FFFFFF white
Итак, теперь я знаю, что столбцы 297-299 являются те, где линия лазера. Обратите внимание, что если изображение слегка повернуто или лазер не является вертикальным, яркий столбец будет разделен на несколько столбцов. Чтобы противодействовать этому, вы можете уменьшить ширину изображения в два или три раза, чтобы соседние столбцы, как правило, сливались в одну на меньшем изображении, а затем просто увеличивали столбец с помощью коэффициента сжатия, чтобы найти исходное положение.
На этом завершается шаг 1, но альтернативный метод следует перед шагом 2.
я разделить изображение на столбцы шириной 1 пиксель с:
convert input.png -crop 1x +repage line%d.png
Теперь найти самый яркий столбец (один с самым высоким средней яркости) с:
for f in line*; do m=$(convert -format "%[fx:mean]" $f info:);echo $m:$f ;done | sort -g
, который дает этот
...
...
0.559298:line180.png
0.561051:line185.png
0.561337:line306.png
0.562527:line184.png
0.562939:line183.png
0.584523:line295.png
0.590632:line299.png
0.644543:line296.png
0.671116:line298.png
0.71122:line297.png <--- brightest column = 297
Шаг 2 - Найти Dark Gap в Brightest Колонка
Теперь я беру столбец 297 и автоматический уровень его так, темная часть становится равным нулю, а светлая часть становится белым, то я отрицаю его.
convert line297.png -colorspace gray -auto-level -threshold 20% -negate txt:
...
0,100: (0,0,0) #000000 black
0,101: (0,0,0) #000000 black
0,102: (0,0,0) #000000 black
0,103: (0,0,0) #000000 black
0,104: (0,0,0) #000000 black
0,105: (0,0,0) #000000 black
0,106: (0,0,0) #000000 black
0,107: (0,0,0) #000000 black
0,108: (255,255,255) #FFFFFF white <- gap in laser line
0,109: (255,255,255) #FFFFFF white <- gap in laser line
0,110: (255,255,255) #FFFFFF white <- gap in laser line
0,111: (255,255,255) #FFFFFF white <- gap in laser line
0,112: (0,0,0) #000000 black
0,113: (0,0,0) #000000 black
...
0,478: (0,0,0) #000000 black
0,479: (0,0,0) #000000 black
Шаг 3 - Найти соседний столбец, Brightest в Gap в лазерной линии
Теперь, если я умножим эту колонку с каждым из колонн по обе стороны от него, всех частей других столбцов, не находятся в зазоре в лазерной линии, станет нулевой, и все части, находящиеся в зазоре в лазерной линии, будут умножаться и суммироваться, когда я прохожу через столбцы с каждой стороны столбца 297.
Итак, я проверяю столбцы от 240 до 340, умножая каждый столбец на маску с предыдущего шага и видя нг, какой из ярких в щели в линии лазера:
for i in {240..340} ;do n=$(convert line${i}.png mask.png -compose multiply -composite -format "%[mean]" info:);echo $n:$i ;done | sort -g
Выход выглядит следующим образом:
458.495:248
466.169:249
468.668:247
498.294:260
502.756:250
536.844:259
557.726:258
564.508:251
624.117:252
627.508:253 <--- column 253 is brightest
Тогда можно видеть, что колонка 253 является самой яркой в той области, где лазерный луч самый темный. Таким образом, смещенная линия находится в колонке 253.
Я уверен, что эту технику можно было бы сделать довольно легко в opencv
.
Оригинал ответа
Я могу сказать вам, как это сделать, но не дает вам код для opencv
, как я предпочитаю использовать ImageMagick. Я разделил изображение на ряд вертикальных изображений, каждый размером 1 пиксель, то есть одиночные пиксельные столбцы. Затем я получаю среднее значение яркости во всех столбцах и сразу вижу самый яркий столбец. Она работает довольно хорошо, вот как я тестировал алгоритм:
Split image into single pixel columns
convert http://i.stack.imgur.com/vMiU1.jpg -crop 1x +repage line%04d.png
Посмотрите, что мы получили:
ls line*
line0000.png line0128.png line0256.png line0384.png line0512.png
line0001.png line0129.png line0257.png line0385.png line0513.png
...
line0126.png line0254.png line0382.png line0510.png line0638.png
line0127.png line0255.png line0383.png line0511.png line0639.png
Да, 640 вертикальных линий. Проверьте размер одного ...
identify line0639.png
line0639.png PNG 1x480 1x480+0+0 8-bit sRGB 1.33KB 0.000u 0:00.000
Да, это 1 пиксель в ширину и 480 пикселей в высоту.
Теперь получить в виду яркость всех линий и сортировать по яркости:
for f in line*; do m=$(convert -format "%[fx:mean]" $f info:);echo $m:$f ;done | sort -g
Выход
0.5151:line0103.png
0.521621:line0104.png
0.527829:line0360.png
0.54699:line0356.png
0.567822:line0355.png
0.752827:line0358.png <--- highest brightness
0.76616:line0357.png <--- highest brightness
Столбцы 357 и 358, кажется, легко идентифицируются в качестве ответа.
Возможно, вы можете попробовать [Лапласиан] (http://docs.opencv.org/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.html). – Alto
В длинном снимке - это просто не сработает. Вы должны использовать фильтр для своей камеры, который пройдет мимо вашей длины волны лазера. Если нет, вы не сможете сегментировать свою лазерную линию из всех данных шума, которые вы получите, используя только порог R. – Amadeusz
Могу ли я использовать другие 2 канала, чтобы получить лучшее решение? – Muha