Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laser line detection opencv

Tags:

opencv

I want to detect a laser line for an autonomous system.

My work till now: 1. I split the image in rgb channels 2. use only the red channel because of using a red laser line 3. get threshold value manually 4.searching the binary image for a value != 0

I can't threshold it manually for the use case of an automous system any ideas how to solve the problem ?

And only searching of the highest peak in an image isn't good enough because of incidence of sunlight.

Maybe I can search for short peaks.. Because in the region of the laser line the brightness increase fast and then decrease fast after the laser line.

How can I realize that in opencv?

Image with laser

manual treshholded image

with an object

like image 654
Muha Avatar asked Nov 09 '22 20:11

Muha


1 Answers

Updated

Ok, I have had a look at your updated picture. My algorithm comes down to the following steps.

  • Find Brightest Column (i.e. laser line) in Image

  • Find Dark Gap in Brightest Column

  • Find Neighbouring Column That is Brightest in Gap in laser line

Step 1 - Find Brightest Column (i.e. laser line) in Image

The easiest way to do this is to squidge the image down so it is still its original width, but just one pixel high effectively averaging the pixels in each vertical column of the image. Then apply an -auto-level to contrast stretch that to the full range of 0-255 and threshold it at 95% to find all columns that are within 5% of the brightest. Then look for pixels that have thresholded out to white (#ffffff). This is one line in ImageMagick, as follows:

convert http://i.stack.imgur.com/1P1zj.jpg -colorspace gray \
    -resize x1!                                             \
    -auto-level                                             \
    -threshold 95% text: | grep -i ffffff

Output:

297,0: (255,255,255)  #FFFFFF  white
298,0: (255,255,255)  #FFFFFF  white
299,0: (255,255,255)  #FFFFFF  white

So, I now know that columns 297-299 are the the ones where the laser line is. Note that if the picture is slightly rotated, or the laser is not vertical, the bright column will be split across multiple columns. To counteract this, you could shrink the width of the image by a factor of two or three so that adjacent columns tend to get merged into one in the smaller image, then just multiply up the column by the shrink factor to find the original position.

That completes Step 1, but an alternative method follows before Step 2.

I split the image into columns 1 pixel wide with:

convert input.png -crop 1x +repage line%d.png

Now I find the brightest column (one with highest mean brightness) with:

for f in line*; do m=$(convert -format "%[fx:mean]" $f info:);echo $m:$f ;done | sort -g

which gives this

...
...
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

Step 2 - Find Dark Gap in Brightest Column

Now I take column 297 and auto-level it so the darkest part becomes zero and the lightest part becomes white, then I negate it.

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

Step 3 - Find Neighbouring Column That is Brightest in Gap in laser line

Now if I multiply this column with each of the columns either side of it, all parts of the other columns that are not in the gap in the laser line will become zero and all parts that are in the gap in the laser line will be multiplied and totalled up as I run through the columns either side of column 297.

So, I check columns 240 to 340, multiplying each column with the mask from the previous step and seeing which one is brightest in the gap in the laser line:

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

The output is as follows:

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

Then I can see that column 253 is the brightest in the area where the laser line is darkest. So the displaced line is in column 253.

I am sure this technique could be done fairly easily in opencv.

Original Answer

I can tell you a way to do it, but not give you any code for opencv as I tend to use ImageMagick. I split the image into a series of vertical images, each 1 pixel wide - i.e. single pixel columns. Then I get the average of the brightnesses in all columns and can immediately see the brightest column. It works pretty well, here is how I tested the algorithm:

Split image into single pixel columns
convert http://i.stack.imgur.com/vMiU1.jpg -crop 1x +repage line%04d.png

See what we got:

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

Yes, 640 vertical lines. Check size of one...

identify line0639.png 
line0639.png PNG 1x480 1x480+0+0 8-bit sRGB 1.33KB 0.000u 0:00.000

Yes, it's 1 pixel wide and 480 pixels high.

Now get mean brightness of all lines and sort by brightness:

for f in line*; do m=$(convert -format "%[fx:mean]" $f info:);echo $m:$f ;done | sort -g

Output

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

Columns 357 and 358 seem to be readily identifiable as your answer.

like image 176
Mark Setchell Avatar answered Nov 15 '22 12:11

Mark Setchell