opencv - 激光线检测opencv

标签 opencv

我想检测自治系统的激光线。

我目前的工作: 1.我在RGB channel 中分割图像 2. 因为使用了红色激光线,所以只使用红色 channel 3.手动获取阈值 4.在二值图像中搜索值 != 0

我无法为自动系统的用例手动设定阈值,有什么解决问题的想法吗?

并且由于阳光的入射,仅搜索图像中的最高峰是不够的。

也许我可以搜索短峰.. 因为在激光线区域亮度增加快,激光线后又快速降低。

我如何在 opencv 中实现这一点?

Image with laser

manual treshholded image

with an object

最佳答案

已更新

好的,我已经看过你更新的图片了。我的算法归结为以下步骤。

  • 在图像中找到最亮的列(即激光线)

  • 在最亮的列中找到暗间隙

  • 找到激光线间隙中最亮的相邻列

第 1 步 - 找到图像中最亮的列(即激光线)

执行此操作的最简单方法是将图像向下挤压,使其仍然是其原始宽度,但只有一个像素高,可以有效地平均图像每个垂直列中的像素。然后应用 -auto-level 将其对比度拉伸(stretch)到 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 列似乎很容易识别为您的答案。

关于opencv - 激光线检测opencv,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27817156/

相关文章:

Python Opencv结构化森林边缘检测TypeError

android - 将C++ opencv IplImage imageData和widthStep转换为android opencv Mat

opencv - 如何解决带有鱼眼相机参数的 PnP?

java - 使用多个静止图像校正 GoPro 的桶形失真?

c - 如何在 C NOT C++ 中将 Mat 转换为 IplImage

c++ - OpenCV 无法使用 imwrite 写入图像

opencv - Flann 函数 Unresolved external 问题

python - 从图像中删除背景 - Python

python - 想要将彩色图像附加到列表中并使用 OpenCV 将该列表转换为灰度

java - 检测图像中的物体(单词)