在图像中提取激光线(使用OpenCV)

在图像中提取激光线(使用OpenCV)

问题描述:

我有一张激光线的照片,我想从图像中提取该线。现在在图像中提取激光线(使用OpenCV)

enter image description here

的问题是,即:

enter image description here

作为激光线是红色的,我走图像的红色通道,然后在每一行中搜索的最高强度还有一些点不属于激光线(如果放大第二张图片,则可以看到这些点)。

有没有人有下一步的想法(去除单点,也提取线)?

这是另一种检测线条的方法: 首先我模糊了带有内核的“黑白”线,然后将细线(骨架)细化为细线,然后将OpenCV函数应用于检测线..结果是如下图像中:enter image description here

NEW:

现在我有另一个困难的情况。 我必须提取绿色激光。
这里存在的问题是激光线的颜色范围更宽和更改。
在激光线的某些部分,像素只有很高的绿色分量,而在其他部分,像素也有很高的蓝色分量。 enter image description here

+0

问题是你采取每一行中最高的那个。所以你总是会得到每行一个点。也许你可以基于该值设置阈值(例如,如果Red分量大于100)。您仍然可以获得其他红色物体或指向图像。你也应该考虑蓝色和绿色组件的值,例如,白色是(255,255,255),所以它们都是高的。你应该把那些红色高和其他频道相当低的值。此外,您可以使用线条检测算法来过滤其他斑点 – api55

+0

我确实已经做到了这一点(以红色为高,但绿色和蓝色相当低的像素) – Mirnyy

+0

您也可以尝试扩张和侵蚀,因为线条点相当一起,并且噪音点不是。或者尝试[Hough line transform](http://docs.opencv.org/2.4/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.html)以仅获取线条,但我不确定曲线将被检测到。 – api55

我真的很抱歉没有任何代码的简短答案,但我建议你采取轮廓和处理它们。

我不知道你需要确切的东西,所以这里为大家介绍两种方法:

  • 只是收集尽可能多的为上一行可能轮廓(利用中心,并尝试找到最小的平均直线)

  • 作为第一种方式,但试图启发式地组合分离的线....这是很难,但这可能会给你几乎完整的激光线从图像。

-

一些示例为你的图片:

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) 

在你的情况下,它的工作完美,但是,正如我已经说过,你需要做的轮廓,更多的工作。

enter image description here

+0

我也已经试过..你可以看到我现在张贴的新形象的结果.. – Mirnyy

+0

首先非常感谢! 我刚刚在C++中实现了你的代码,它的工作非常可靠...... 但是对于我来说,提取那个*弧*线并不仅仅是一条近似的直线更重要(因为我们想要使用该线来进行三角测量法测量到物体/地面的距离)... 你有一个想法如何扩展它来提取该曲线而不是一条直线? – Mirnyy

+1

请参阅https://*.com/questions/44406469/draw-a-curve-line-going-through-through-the-blobs-in-opencv/44410748#44410748这也许对您有所帮助。 –

获取每一行中的最高值总是输出值,而不是当值不够高忽视。考虑使用一个门槛,以便你可以丢弃那些不够高的门槛。

但是,这根本不是一种非常有效的方法。更好更容易的解决方案是使用OpenCV功能inRange();在所有三个通道中定义红色的下限和上限,并且这将返回具有白色像素的二值图像,其中图像强度在该BGR范围内。

这是蟒蛇,但它的工作,应该很容易看到如何使用功能:

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) 

这将产生输出: Red line binary iamge

这可以通过寻找进一步处理轮廓或其他方法将点变成一条好曲线。

+0

首先非常感谢您的努力! 直到这一步当然非常清楚.. 但主要问题是检测您张贴的图像上这些点的线/曲线.. 如果我例如尝试连接最近的点在一起,我得到很不幸的是,“zig-zag”线... – Mirnyy

+0

你*可以*使用多项式拟合方法,但是否则,你想要对线/曲线做什么?你需要它作为一个二进制图像的行是一个像素宽吗? –

+0

是的,确切! 我想得到理想情况下为1像素宽的曲线/曲线。 – Mirnyy