我正在尝试建立一个系统来检测纸上的弹孔。我已经阅读了许多 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 方法可用