计算机c9硕士算法工程师

计算机c9硕士算法工程师

深度学习目标检测中的_单目测距原理与实现 关键点及改进建议

深度学习目标检测中的_单目测距原理与实现 关键点及改进建议-LMLPHP

一、前言
单目视觉测距:网上有很多关于单目测距的文章,主要借鉴的是OpenCV学习笔记(二十一)——简单的单目视觉测距尝试和单目摄像机测距(python+opencv)两篇文章,在这里特别作出说明。
工作环境:Ubuntu16.04 + Opencv3.4.0 +Pycharm
单目相机:DFK AFUX236-M12

二、单目测距原理
单目相机测距常用或者说实用的方法就是相似三角形法,为了让大家更好地理解程序,这里简单说一下相似三角形法。

相似三角形:假设我们有一个宽度为 W 的目标或者物体。然后我们将这个目标放在距离我们的相机为 D 的位置。我们用相机对物体进行拍照并且测量物体的像素宽度 P 。这样我们就得出了相机焦距的公式:

深度学习目标检测中的_单目测距原理与实现 关键点及改进建议-LMLPHP

F = (P x D) / W

举个例子,假设我在离相机距离 D = 24 英寸的地方放一张标准的 8.5 x 11 英寸的 A4 纸(横着放;W = 11)并且拍下一张照片。我测量出照片中 A4 纸的像素宽度为 P = 249 像素。

因此我的焦距 F 是:

F = (248px x 24in) / 11in = 543.45

当我继续将我的相机移动靠近或者离远物体或者目标时,我可以用相似三角形来计算出物体离相机的距离:

D’ = (W x F) / P

为了更具体,我们再举个例子,假设我将相机移到距离目标 3 英尺(或者说 36 英寸)的地方并且拍下上述的 A4 纸。通过自动的图形处理我可以获得图片中 A4 纸的像素距离为 170 像素。将这个代入公式得:

D’ = (11in x 543.45) / 170 = 35 英寸

或者约 36 英寸,合 3 英尺。

从以上的解释中,我们可以看到,要想得到距离,我们就要知道摄像头的焦距和目标物体的尺寸大小,这两个已知条件根据公式:

D’ = (W x F) / P

得出目标到摄像机的距离D,其中P是指像素距离,W是A4纸的宽度,F是摄像机焦距。
三、实现代码:
import cv2
import numpy as np

win_width = 1920
win_height = 1200
mid_width = int(win_width / 2)
mid_height = int(win_height / 2)

foc = 2810.0
real_wid = 11.69
font = cv2.FONT_HERSHEY_SIMPLEX
w_ok = 1

capture = cv2.VideoCapture(1)
capture.set(3, win_width)
capture.set(4, win_height)

while(True):
ret, frame = capture.read()
# frame = cv2.flip(frame, 1)
if ret == False:
break

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
ret, binary = cv2.threshold(gray, 127, 255, 0)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
binary = cv2.dilate(binary, kernel, iterations=2) # 形态学膨胀
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# cv2.drawContours(frame, contours, -1, (0, 255, 0), 2)
for c in contours:
    if cv2.contourArea(c) < 2000: # 对于矩形区域,只显示大于给定阈值的轮廓,所以一些微小的变化不会显示。对于光照不变和噪声低的摄像头可不设定轮廓最小尺寸的阈值
        continue

    x, y, w, h = cv2.boundingRect(c) # 该函数计算矩形的边界框
    
    if x > mid_width or y > mid_height:
        continue
    if (x + w) < mid_width or (y + h) < mid_height:
        continue
    if h > w:
        continue
    if x == 0 or y == 0:
        continue
    if x == win_width or y == win_height:
        continue

    w_ok = w
    cv2.rectangle(frame, (x + 1, y + 1), (x + w_ok - 1, y + h - 1), (0, 255, 0), 2)

dis_inch = (real_wid * foc) / (w_ok - 2)
dis_cm = dis_inch * 2.54
# os.system("cls")
# print("Distance : ", dis_cm, "cm")
frame = cv2.putText(frame, "%.2fcm" % (dis_cm), (5, 25), font, 0.8, (0, 255, 0), 2)
frame = cv2.putText(frame, "+", (mid_width, mid_height), font, 1.0, (0, 255, 0), 2)

cv2.namedWindow('res', 0)
cv2.namedWindow('gray', 0)
cv2.resizeWindow('res', win_width, win_height)
cv2.resizeWindow('gray', win_width, win_height)
cv2.imshow('res', frame)
cv2.imshow('gray', binary)

c = cv2.waitKey(40)
if c ==27:
    break

cv2.destroyAllWindows
程序效果图如下:
深度学习目标检测中的_单目测距原理与实现 关键点及改进建议-LMLPHP

效果图
深度学习目标检测中的_单目测距原理与实现 关键点及改进建议-LMLPHP
单目测距是一种利用单一摄像头来估算物体与相机之间距离的技术。该技术基于相似三角形原理,通过已知的物理尺寸和像素尺寸计算出目标物体的距离。包括一些关键点的详细解释以及可能的改进建议。

单目测距的进一步解释

1. 焦距的确定
  • 焦距的重要性:在公式 (F = \frac{P \times D}{W}) 中,焦距 (F) 是一个非常重要的参数,它决定了测量的准确性。通常情况下,焦距需要通过校准过程获得,例如使用标准尺寸的物体(如A4纸)放置在已知距离处进行拍照,并据此计算得到。
  • 动态调整焦距:在实际应用中,如果环境或镜头条件发生变化,建议重新校准以更新焦距值。
2. 物体宽度 (W) 的获取
  • 精确度要求:为了提高测量精度,必须准确知道目标物体的实际宽度 (W)。对于非标准化的物体,这可能需要额外的测量步骤。
  • 多物体支持:若需对不同大小的物体进行测距,则可以预先存储多种物体的尺寸信息,根据识别结果选择合适的 (W) 值。
3. 图像处理技巧
  • 边缘检测与轮廓提取:除了你代码中使用的二值化和形态学操作外,还可以尝试Canny边缘检测等方法来增强物体边界识别的效果。
  • 滤波器的选择:根据具体的应用场景调整高斯模糊的核大小,以减少噪声的影响同时保持边缘清晰。
4. 提高性能的建议
  • 适应性更强的阈值设定:当前代码中的阈值(如 cv2.threshold(gray, 127, 255, 0))是固定的,但在不同的光照条件下,这个值可能需要动态调整。可以考虑自适应阈值方法。
  • 优化轮廓筛选条件:目前的代码中有一些硬编码的条件(如 if h > w: continue),这些条件可能不适用于所有类型的物体。可以根据实际情况灵活调整这些筛选条件。
5. 实现代码中的注释添加
# 计算距离并转换为厘米
dis_inch = (real_wid * foc) / (w_ok - 2)  # 使用相似三角形法计算英寸单位下的距离
dis_cm = dis_inch * 2.54  # 将距离从英寸转换为厘米

# 在图像上显示计算出的距离
frame = cv2.putText(frame, "%.2fcm" % (dis_cm), (5, 25), font, 0.8, (0, 255, 0), 2)
01-30 20:16