使用Python检测图像中大致水平的红色激光线的最快可靠方法是什么?我正在开展一个与三维激光扫描相关的小项目,我需要能够在图像中检测激光,以便计算距其失真的距离。
首先,我有两个图像,一个已知不包含激光线的参考图像A,以及一个肯定包含可能失真的激光线的图像B. e.g。
示例图片A:
示例图像B:
由于这些是RGB,但是激光是红色的,我通过使用此功能剥离蓝色和绿色通道来消除一些噪音:
from PIL import Image
import numpy as np
def only_red(im):
"""
Strips out everything except red.
"""
data = np.array(im)
red, green, blue, alpha = data.T
im2 = Image.fromarray(red.T)
return im2
这让我看到了这些图片:
接下来,我尝试通过使用PIL.ImageChops.difference()
获取这两个图像的差异来消除更多噪点。理想情况下,两个图像之间的曝光是相同的,导致差异除了激光线之外什么都不包含。不幸的是,由于激光增加了光线,每个图像的曝光和整体亮度明显不同,导致差异仍然具有相当大的噪音。 e.g。
我的最后一步是做出最好的猜测"至于线的位置。因为我知道线条大致水平,激光线应该是图像中最亮的线条,所以我扫描每一列并找到最亮像素的行,我认为这是激光线。代码是:
import os
from PIL import Image, ImageOps
import numpy as np
x = Image.open('laser-diff.png', 'r')
x = x.convert('L')
out = Image.new("L", x.size, "black")
pix = out.load()
y = np.asarray(x.getdata(), dtype=np.float64).reshape((x.size[1], x.size[0]))
print y.shape
for col_i in xrange(y.shape[1]):
col_max = max([(y[row_i][col_i], row_i) for row_i in xrange(y.shape[0])])
col_max_brightness, col_max_row = col_max
print col_i, col_max
pix[col_i, col_max_row] = 255
out.save('laser-line.png')
我真正需要执行的距离计算是col_max
值的数组,但laser-line.png
帮助我想象成功,看起来像:
正如你所看到的,估计非常接近,但它仍有一些噪音,主要是在图像的左侧,激光线被哑光黑色表面吸收。
我可以做些什么来提高我的准确性和/或速度?我试图在像Raspberry Pi这样的ARM平台上运行它,所以我担心我的代码可能效率太低而无法正常运行。
我并不完全熟悉Numpy的矩阵函数,所以我不得不采用缓慢的for循环来扫描每一列,而不是更有效率。有没有一种快速的方法可以在Numpy中找到每列最亮像素的行?
此外,有没有一种可靠的方法在执行差异之前均衡图像而不会使激光线变暗?
答案 0 :(得分:2)
答案 1 :(得分:1)
首先,您可以重新调整负片图像的强度,然后再从正片中减去它,以消除更多噪点。例如,通过平均整数的比率重新缩放可能是一个很好的第一次尝试?
你也可以尝试设置一个阈值:如果你的最大值低于任何好的值,那么它可能不是你的激光而是一个嘈杂的点......
然后是numpy可以找到argmax函数的最佳行/列。
答案 2 :(得分:1)
我试着做点什么。我不认为它是完全健壮的。但就你的例子而言,它的效果相对较好。
我使用精确边缘检测来检测“差异”图像中的边缘。然后在this tutorial中应用Hough线变换。
所以我开始使用您处理过的图片(我在代码中调用lineDetection.jpg
)。
这是最终的脚本
import cv2
import numpy as np
img = cv2.imread('lineDetection.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,10,100)
minLineLength = 50
maxLineGap = 20
lines = cv2.HoughLinesP(edges,0.05,np.pi/5000,10,minLineLength,maxLineGap)
print(len(lines))
for i in range(len(lines)):
x1,y1,x2,y2 = lines[i][0]
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv2.imwrite('houghlines5.jpg',img)
在处理过的图像上检测到绿线。 (您可以将其添加到原始图像以获得更好的效果)
希望它有所帮助。