Search code examples
c++imageopencvlinedetection

Extracting a laser line in an image (using OpenCV)


i have a picture from a laser line and i would like to extract that line out of the image.

enter image description here

As the laser line is red, i take the red channel of the image and then searching for the highest intensity in every row:

enter image description here

The problem now is, that there are also some points which doesnt belong to the laser line (if you zoom into the second picture, you can see these points).

Does anyone have an idea for the next steps (to remove the single points and also to extract the lines)?

That was another approach to detect the line: First i blurred out that "black-white" line with a kernel, then i thinned(skeleton) that blurred line to a thin line, then i applied an OpenCV function to detect the line.. the result is in the below image:enter image description here

NEW:

Now i have another harder situation. I have to extract a green laser light.
The problem here is that the colour range of the laser line is wider and changing.
On some parts of the laser line the pixel just have high green component, while on other parts the pixel have high blue component as well. enter image description here


Solution

  • I'm really sorry for the short answer without any code, but I suggest you take contours and process them.

    I dont know exact what you need, so here are two approaches for you:

    • just collect as much as possible contours on single line (use centers and try find straight line with smallest mean)

    • as first way, but trying heuristically combine separated lines.... it's much harder, but this may give you almost full laser line from image.

    --

    Some example for yours picture:

    import cv2
    import numpy as np
    import math
    
    img = cv2.imread('image.png')
    hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
    # filtering red area of hue
    redHueArea = 15
    redRange = ((hsv[:, :, 0] + 360 + redHueArea) % 360) 
    hsv[np.where((2 * redHueArea) > redRange)] = [0, 0, 0] 
    # filtering by saturation
    hsv[np.where(hsv[:, :, 1] < 95)] = [0, 0, 0]
    # convert to rgb
    rgb = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB)
    # select only red grayscaled channel with low threshold  
    gray = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY)
    gray = cv2.threshold(gray, 15, 255, cv2.THRESH_BINARY)[1]
    # contours processing
    (_, contours, _) = cv2.findContours(gray.copy(), cv2.RETR_LIST, 1)
    for c in contours:
        area = cv2.contourArea(c)
        if area < 8: continue
        epsilon = 0.1 * cv2.arcLength(c, True) # tricky smoothing to a single line
        approx = cv2.approxPolyDP(c, epsilon, True)
        cv2.drawContours(img, [approx], -1, [255, 255, 255], -1)
    
    cv2.imshow('result', img)
    cv2.waitKey(0)
    

    In your case it's work perfectly, but, as i already said, you will need to do much more work with contours.

    enter image description here