我想检测一个自动系统的激光线。
我的工作到现在为止: 我在rgb频道中分割图像 2.由于使用红色激光线,仅使用红色通道 3.手动获取阈值 4.搜索二进制图像的值!= 0
我不能手动为自动系统的用例设置门槛任何想法如何解决问题?
由于阳光的照射,仅搜索图像中的最高峰是不够的。
也许我可以搜索短峰.. 因为在激光线的区域内,亮度在激光线之后快速增加然后快速下降。
如何在opencv中实现?
答案 0 :(得分:1)
<强>更新强>
好的,我已经看过你的最新照片了。我的算法归结为以下步骤。
在Image
找出最亮的栏目中的黑暗差距
查找激光线中间隙最亮的相邻列
步骤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步 - 找出最亮列中的暗差
现在我采用第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步 - 查找激光线间隙最亮的相邻列
现在,如果我将此列与其两侧的每列相乘,则不在激光线间隙中的其他列的所有部分将变为零,并且激光线中间隙中的所有部分当我通过第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栏似乎很容易识别出你的答案。