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()