1. 简介:
/*******************************************************************
本项目是使用单目摄像头实现距离的测量,首先单目摄像头与kinect等深度摄像头最大
的区别是无法有效获取深度信息,那就首先从这方面入手,尝试通过图像获取摄像头与人的距
离。
在网上看了几天关于摄像头标定和摄像头焦距等原理的文章,然后通过这篇文章真正启发
了我:用python和opencv来测量目标到相机的距离 主要的测距的原理是利用相似三角形计
算物体到相机的距离。
https://blog.csdn.net/m0_37811342/article/details/80394935
http://python.jobbole.com/84378/
********************************************************************/
2. 单目测距原理
/*********************************************************************
我们将使用相似三角形来计算相机到一个已知的物体或者目标的距离。 相似三角形就是
这么一回事:假设我们有一个宽度为 W 的目标或者物体。然后我们将这个目标放在距离我们
的相机为 D 的位置。我们用相机对物体进行拍照并且测量物体的像素宽度 P 。这样我们就得
出了相机焦距的公式: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
从以上的解释中,我们可以看到,要想得到距离,我们就要知道摄像头的焦距和目标物体的大小,
这两个已知条件根据公式:D’ = (W x F) / P
得出目标到摄像机的距离D,其中P是指像素距离,W是A4纸的宽度,F是摄像机焦距。
********************************************************************/
3.单目测距Python代码(带注释)
1 import numpy as np
2 import cv2
3 # 找到目标函数
4 def find_marker(image):
5 # convert the image to grayscale, blur it, and detect edges
6 #将图像转换成灰度、模糊和检测边缘
7 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
8 gray = cv2.GaussianBlur(gray, (5, 5), 0)
9 edged = cv2.Canny(gray, 35, 125)
10
11 # find the contours in the edged image and keep the largest one;
12 #在边缘图像中找到轮廓并保持最大的轮廓
13 # we'll assume that this is our piece of paper in the image
14 #我们假设这是我们在图像中的一张纸
15 (_, cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
16 # 求最大面积
17 c = max(cnts, key = cv2.contourArea)
18
19 # compute the bounding box of the of the paper region and return it
20 #计算纸张区域的边界框并返回它
21 # cv2.minAreaRect() c代表点集,返回rect[0]是最小外接矩形中心点坐标,
22 # rect[1][0]是width,rect[1][1]是height,rect[2]是角度
23 return cv2.minAreaRect(c)
24
25 # 距离计算函数
26 def distance_to_camera(knownWidth, focalLength, perWidth):
27 # compute and return the distance from the maker to the camera
28 #计算并返回从目标到相机的距离
29 return (knownWidth * focalLength) / perWidth
30
31 # initialize the known distance from the camera to the object, which
32 # in this case is 24 inches
33 #初始化已知距离从相机到对象,在这种情况下是24英寸
34 KNOWN_DISTANCE = 24.0
35
36 # initialize the known object width, which in this case, the piece of
37 # paper is 11 inches wide
38 #初始化已知的物体宽度,在这种情况下,纸是11英寸宽。
39 # A4纸的长和宽(单位:inches)
40 KNOWN_WIDTH = 11.69
41 KNOWN_HEIGHT = 8.27
42
43 # initialize the list of images that we'll be using
44 #初始化我们将要使用的图像列表
45 IMAGE_PATHS = ["Picture1.jpg", "Picture2.jpg", "Picture3.jpg"]
46
47 # load the furst image that contains an object that is KNOWN TO BE 2 feet
48 # from our camera, then find the paper marker in the image, and initialize
49 # the focal length
50 #加载包含一个距离我们相机2英尺的物体的第一张图像,然后找到图像中的纸张标记,并初始化焦距
51 #读入第一张图,通过已知距离计算相机焦距
52 image = cv2.imread("E:\\lena.jpg") #应使用摄像头拍的图
53 marker = find_marker(image)
54 focalLength = (marker[1][0] * KNOWN_DISTANCE) / KNOWN_WIDTH # D’ = (W x F) / P
55
56 #通过摄像头标定获取的像素焦距
57 #focalLength = 811.82
58 print('focalLength = ',focalLength)
59
60 #打开摄像头
61 camera = cv2.VideoCapture(0)
62
63 while camera.isOpened():
64 # get a frame
65 (grabbed, frame) = camera.read()
66 marker = find_marker(frame)
67 if marker == 0:
68 print(marker)
69 continue
70 inches = distance_to_camera(KNOWN_WIDTH, focalLength, marker[1][0])
71
72 # draw a bounding box around the image and display it
73 #在图像周围绘制一个边界框并显示它
74 box = cv2.boxPoints(marker)
75 box = np.int0(box)
76 cv2.drawContours(frame, [box], -1, (0, 255, 0), 2)
77
78 # inches 转换为 cm
79 cv2.putText(frame, "%.2fcm" % (inches *30.48/ 12),
80 (frame.shape[1] - 200, frame.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX,
81 2.0, (0, 255, 0), 3)
82
83 # show a frame
84 cv2.imshow("capture", frame)
85 if cv2.waitKey(1) & 0xFF == ord('q'):
86 break
87 camera.release()
88 cv2.destroyAllWindows()
4.单目测距Python代码(纯代码)
1 import numpy as np
2 import cv2
3 def find_marker(image):
4 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
5 gray = cv2.GaussianBlur(gray, (5, 5), 0)
6 edged = cv2.Canny(gray, 35, 125)
7
8 (_, cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
9 c = max(cnts, key = cv2.contourArea)
10 return cv2.minAreaRect(c)
11
12 def distance_to_camera(knownWidth, focalLength, perWidth):
13 return (knownWidth * focalLength) / perWidth
14
15 KNOWN_DISTANCE = 24.0
16 KNOWN_WIDTH = 11.69
17 KNOWN_HEIGHT = 8.27
18 IMAGE_PATHS = ["Picture1.jpg", "Picture2.jpg", "Picture3.jpg"]
19 image = cv2.imread("E:\\lena.jpg")
20 marker = find_marker(image)
21 focalLength = (marker[1][0] * KNOWN_DISTANCE) / KNOWN_WIDTH
22
23 print('focalLength = ',focalLength)
24 camera = cv2.VideoCapture(0)
25 while camera.isOpened():
26 (grabbed, frame) = camera.read()
27 marker = find_marker(frame)
28 if marker == 0:
29 print(marker)
30 continue
31 inches = distance_to_camera(KNOWN_WIDTH, focalLength, marker[1][0])
32 box = cv2.boxPoints(marker)
33 box = np.int0(box)
34 cv2.drawContours(frame, [box], -1, (0, 255, 0), 2)
35 cv2.putText(frame, "%.2fcm" % (inches *30.48/ 12),
36 (frame.shape[1] - 200, frame.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX,
37 2.0, (0, 255, 0), 3)
38 cv2.imshow("capture", frame)
39 if cv2.waitKey(1) & 0xFF == ord('q'):
40 break
41 camera.release()
42 cv2.destroyAllWindows()
5.单目测距Python代码运行结果