Extracting a laser line into an image (using OpenCV)

I have a laser line image, and I would like to extract this line from the image.

enter image description here

When the laser line is red, I take the red channel of the image, and then look through the highest intensity in each line:

enter image description here

The problem is that there are also some points that do not belong to the laser line (if you enlarge the image in the second image, you can see these points).

Does anyone have an idea for the next steps (delete individual points as well as extract lines)?

This was another approach to detecting the line: First, I blurred this “black and white” line with the core, then I diluted (skeleton), which blurred the line to a thin line, then I used the OpenCV function to detect the line. The result is in the following image: enter image description here

NEW:

Now I have another difficult situation. I have to extract the green laser beam.
The problem here is that the color range of the laser line is wider and changes.
In some parts of the laser line, the pixel simply has a high green component, and in other parts, the pixel also has a high blue component. enter image description here

+5
source share
2 answers

I am very sorry for the short answer without code, but I suggest you take the paths and process them.

I don’t know exactly what you need, so here are two approaches for you:

  • just collect as many contours on one line as possible (use the centers and try to find a straight line with the lowest value)

  • as the first way, but trying to heuristically combine split lines ... it's a lot harder, but it can give you an almost complete laser line from the image.

-

Example for your image:

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, this works fine, but, as I said, you will need to do a lot more work with the contours.

enter image description here

+1
source

Getting the highest value in each row always displays the value instead of ignoring it when the value is not large enough. Also consider using a threshold so that you can drop those that are not high enough.

However, this is not a very effective way to do this at all. It would be much better and easier to use the OpenCV inRange() function; define the lower and upper borders of red in all three channels, and this will return a binary image with white pixels, where the image intensity is within this BGR range.

This is in python, but it does the job, it should be easy to see how to use this function:

 import cv2 import numpy as np img = cv2.imread('image.png') lowerb = np.array([0, 0, 120]) upperb = np.array([100, 100, 255]) red_line = cv2.inRange(img, lowerb, upperb) cv2.imshow('red', red_line) cv2.waitKey(0) 

This gives the result: Red line binary iamge

This can be further processed by searching for outlines or other methods to turn points into a good curve.

+3
source

Source: https://habr.com/ru/post/1268591/


All Articles