【问题标题】:How to detect a laser line in an image using Python如何使用 Python 检测图像中的激光线
【发布时间】:2016-01-17 06:13:54
【问题描述】:

使用 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

这让我得到了这些图片:

接下来,我尝试通过使用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')

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

如您所见,估计值非常接近,但仍有一些噪点,主要位于图像左侧,激光线被哑光黑色饰面吸收。

我可以做些什么来提高我的准确性和/或速度?我正在尝试在 Raspberry Pi 等 ARM 平台上运行它,所以我担心我的代码可能效率太低而无法正常运行。

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

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

【问题讨论】:

  • 也许最后,你可以把y坐标不在25%~75%分位数的点全部去掉。然后可以得到更好的结果,然后使用 locf..etc 补上缺失的值
  • @B.Mr.W.,你说对了一部分。由于激光器安装在相机下方并与其焦平面平行,因此所有激光点都应位于中间行下方,这意味着上面的所有点都是噪声。谢谢。

标签: python image numpy image-processing


【解决方案1】:

首先,您可以在从正片中减去负片图像之前重新调整负片图像的强度,以消除更多噪点。例如,也许通过平均强度的比率重新缩放可能是一个很好的第一次尝试?

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

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

【讨论】:

    【解决方案2】:

    首先输入激光的颜色,只留下红色(在这种情况下)。然后应用相同的效果并检查结果。

    在这种情况下,您将获得更少污染的结果。 Result

    分析门上的红色时遇到问题,已丢失。

    【讨论】:

    • 我不知道激光的颜色,除了它大致是红色的。我不能简单地假设所有红色都是激光,因为场景中可能有红色物体。这个解决方案必须是自动化的,所以我不能在每张图像中手动指示激光颜色。
    • 然后使用您的图像,滚动图表。可能最大的方法将是找到一条激光线。图形入口处将是具有两个黑色和两个白色像素相邻像素的任何像素。
    【解决方案3】:

    我试着做点什么。我不认为它完全强大。但是在您的示例中,它的效果相对较好。

    我使用精明的边缘检测来检测“差异”图像中的边缘。然后像this tutorial 一样应用霍夫线变换。 所以我从你处理过的图像开始(在代码中我称之为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)
    

    在处理后的图像上检测到绿线。 (您可以将其添加到原始图像以获得更好的效果)

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-30
      • 2020-05-13
      相关资源
      最近更新 更多