如何使用Python检测图像中的激光线

Cer*_*rin 10 python numpy image image-processing

使用Python检测图像中大致水平的红色激光线的最快可靠方法是什么?我正在开展一个与3D激光扫描有关的小项目,我需要能够在图像中检测激光,以便计算距其失真的距离.

首先,我有两个图像,一个已知不包含激光线的参考图像A,以及一个肯定包含可能失真的激光线的图像B. 例如

示例图片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
Run Code Online (Sandbox Code Playgroud)

这让我看到了这些图片:

在此输入图像描述

在此输入图像描述

接下来,我尝试通过使用这两个图像的差异来消除更多噪声PIL.ImageChops.difference().理想情况下,两个图像之间的曝光是相同的,导致差异除了激光线之外什么都不包含.不幸的是,由于激光增加了光线,每个图像的曝光和整体亮度明显不同,导致差异仍然具有相当大的噪音.例如

在此输入图像描述

我的最后一步是对线的位置进行"最佳猜测".因为我知道线条大致水平,激光线应该是图像中最亮的线条,所以我扫描每一列并找到最亮像素的行,我认为这是激光线.这个代码是:

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')
Run Code Online (Sandbox Code Playgroud)

所有我真正需要执行的距离计算都是col_max值数组,但这laser-line.png有助于我想象成功,看起来像:

在此输入图像描述

正如你所看到的,估计非常接近,但它仍然有一些噪音,主要是在图像的左侧,激光线被哑光黑色表面吸收.

我该怎么做才能提高我的准确性和/或速度?我试图在像Raspberry Pi这样的ARM平台上运行它,所以我担心我的代码可能效率太低而无法正常运行.

我对Numpy的矩阵函数并不完全熟悉,所以我不得不采用缓慢的for循环来扫描每一列,而不是更有效率.有没有一种快速的方法可以在Numpy中找到每列最亮像素的行?

另外,有没有一种可靠的方法在执行差异之前均衡图像而不会使激光线变暗?

Jul*_*ien 1

首先,您可以重新调整负片图像的强度,然后从正片中减去它,以消除更多噪音。例如,也许按平均强度的比率重新调整可能是一个很好的第一次尝试?

您还可以尝试设置一个阈值:如果您的最大值低于任何好的值,那么它可能不是您的激光,而是一个嘈杂的点......

然后,是的,numpy 可以使用 argmax 函数找到最佳的行/列。