使用带有摄像头或传感器的 Python 检测弹孔

信息处理 Python 计算机视觉 opencv 传感器 相机
2022-02-08 03:35:43

我正在尝试建立一个系统来检测纸上的弹孔。我已经阅读了许多 StackOverflow 线程,但没有一个令我满意。我正在使用的当前方法很好,但并不完美,也不完全可靠。在现场测试时,它经常会错过几次拍摄或校准问题。

系统要求:

  • 实时检测,
  • 在纸上打洞和检测之间的输入延迟非常低,
  • 最小屏幕尺寸 - 2.5mx 1.5m,
  • 适用于 .22、9x19、5.56x45、7.62x39 等弹药,
  • 返回检测到的子弹击中的 X 和 Y 坐标。

我目前使用的是:

  • Arducam IMX477 12,3MPx HQ + usb 2.0 接口模拟网络摄像头,
  • 相机镜头- 这很糟糕:P 但我需要变焦功能,相机上的可见光过滤器和红外灯 - 独立于环境光。
  • Python检测:
    • 图像减法 - 监控变化,
    • 对来自相机的图像进行阈值处理 - 以消除噪声,
    • 检测 - OpenCV.findContours 或分析 numpy 数组以在图像的某些区域中搜索高值。

摄像头距离屏幕 4.5-5m。我通过观察这些帧之间的变化来检测出现在后续帧上的黑色区域,并在检测到一些大尖峰(比噪声大 2 倍)时找到最大值。

这是我制作的一些代码示例和漂亮的图:

import cv2
import time

video_stream = cv2.VideoCapture('C:\Projekty\HoleDetection\data\IRNEW\WIN_20220204_14_26_23_Pro_Trim.mp4')
prev_frame = None
i = 0
start = float(time.time())
while video_stream.isOpened():
    ret, frame = video_stream.read()
    if not ret:
        break
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    if prev_frame is not None:
        subtracted_frame = cv2.subtract(prev_frame, frame)
        # cv2.imshow('subtr', cv2.resize(subtracted_frame, (1280, 720)))

        ax_0_max = subtracted_frame.max(axis=0)
        ax_1_max = subtracted_frame.max(axis=1)
        curr_max = ax_1_max.max()

        if prev_max * 2 < curr_max:
            print('Detected shot')
            x = ax_0_max.argmax()
            y = ax_1_max.argmax()
            print(f'X: {x}, Y: {y}')
            # keypoints.append(cv2.KeyPoint(float(x), float(y), 10))
        prev_max = curr_max
    else:
        prev_max = frame.max()
    prev_frame = frame
    # frame = cv2.drawKeypoints(frame, keypoints, np.array([]), (0, 0, 255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
    # cv2.imshow('im', cv2.resize(frame, (1280, 720)))
    i += 1
    if cv2.waitKey(1) == ord('q'):
        break
end = float(time.time())
cv2.destroyAllWindows()

print(f'Time {end-start} for {i+1} frames. FPS: {(i+1)/(end-start)}')

整部电影分析:

整部电影

第一个弹孔出现的关键帧:

第一枪

从相机的角度来看,这就是它的样子。有点模糊和鱼眼镜头效果。这并不理想。它对 9x19 弹药几乎完美(或者可能只是很好),但在较小口径(0.22、0.223Rem、5.56x45)的情况下存在问题——由于孔较小,变化不太明显。

注意一件不幸的事情——我不能把任何东西放在屏幕后面,因为它被实弹炮击​​了。

我想听听您如何改进这个系统。也许使用某种能够检测弹孔(如果有的话)并且比当前方法更可靠的传感器,或者可能有一些更好的 python 方法可用

2个回答

我无法真正评论机器视觉部分,除了任何询问“我如何用 <some language> 执行 <some signal processing task>”的问题都相当幼稚。用任何语言完成任何信号处理任务的方法是首先学习如何用数学进行信号处理。句号。然后用你选择的语言去实现它。

所有主要的计算语言共享所有主要的数学、信号处理和机器视觉库。对于那些不这样做的人,通常有一种方法可以在您选择的库周围放置一个薄包装器并使用它。因此,如果您想在 Python 与 C++、Rust 或 Fortran 或其他任何语言中执行此操作 - 这只是一个细节。重要的部分是你首先如何做到这一点。

对于你手头的问题——我认为你只需要更多的对比度,可能还有更多的像素。调整你的镜头、相机和灯光,让弹孔更加与众不同。如果这些是 9 毫米的孔并且您想要更小,那么您需要有一个高像素数的相机,并且您需要在其上匹配光学元件。您可能希望弹孔的直径至少为 5 个像素,而且越多越好。

您可能需要重新考虑您的“无背光”规则。例如,如果您将相机设置为从左侧查看目标的前方,超出范围,那么您不能在目标后面和右侧设置灯光,因此它们直接照射到相机中但不在范围内子弹的路径?

使用红外热像仪和锁定热成像仪可以获得更好的结果。子弹的红外反射与“普通”光的可能性相比有很大不同。所以你会得到更多的细节。