用相似三角形計算物體或者目標到相機的距離
我們將使用相似三角形來計算相機到一個已知的物體或者目標的距離。
相似三角形就是這么一回事:假設我們有一個寬度為 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
為了更具體,我們再舉個例子,假設我將相機移到距離目標 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 the necessary packages import numpy as np import cv2 # 找到目標函數 def find_marker(image): # convert the image to grayscale, blur it, and detect edges gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (5, 5), 0) edged = cv2.Canny(gray, 35, 125) # find the contours in the edged image and keep the largest one; # we'll assume that this is our piece of paper in the image (cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) # 求最大面積 c = max(cnts, key = cv2.contourArea) # compute the bounding box of the of the paper region and return it # cv2.minAreaRect() c代表點集,返回rect[0]是最小外接矩形中心點坐標, # rect[1][0]是width,rect[1][1]是height,rect[2]是角度 return cv2.minAreaRect(c) # 距離計算函數 def distance_to_camera(knownWidth, focalLength, perWidth): # compute and return the distance from the maker to the camera return (knownWidth * focalLength) / perWidth # initialize the known distance from the camera to the object, which # in this case is 24 inches KNOWN_DISTANCE = 24.0 # initialize the known object width, which in this case, the piece of # paper is 11 inches wide # A4紙的長和寬(單位:inches) KNOWN_WIDTH = 11.69 KNOWN_HEIGHT = 8.27 # initialize the list of images that we'll be using IMAGE_PATHS = ["Picture1.jpg", "Picture2.jpg", "Picture3.jpg"] # load the furst image that contains an object that is KNOWN TO BE 2 feet # from our camera, then find the paper marker in the image, and initialize # the focal length #讀入第一張圖,通過已知距離計算相機焦距 image = cv2.imread(IMAGE_PATHS[0]) marker = find_marker(image) focalLength = (marker[1][0] * KNOWN_DISTANCE) / KNOWN_WIDTH #通過攝像頭標定獲取的像素焦距 #focalLength = 811.82 print('focalLength = ',focalLength) #打開攝像頭 camera = cv2.VideoCapture(0) while camera.isOpened(): # get a frame (grabbed, frame) = camera.read() marker = find_marker(frame) if marker == 0: print(marker) continue inches = distance_to_camera(KNOWN_WIDTH, focalLength, marker[1][0]) # draw a bounding box around the image and display it box = np.int0(cv2.cv.BoxPoints(marker)) cv2.drawContours(frame, [box], -1, (0, 255, 0), 2) # inches 轉換為 cm cv2.putText(frame, "%.2fcm" % (inches *30.48/ 12), (frame.shape[1] - 200, frame.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX, 2.0, (0, 255, 0), 3) # show a frame cv2.imshow("capture", frame) if cv2.waitKey(1) & 0xFF == ord('q'): break camera.release() cv2.destroyAllWindows()
使用相機計算人到相機的距離
在第一部分中我們已經計算出了A4紙距離相機的距離,在具體應用中,我需要計算的是人距離相機的距離,來實現機器人對目標人距離的判斷,應用與對目標人的跟隨。在這里主要的思路是先通過opencv中的HOG方法檢測到人,再根據人的預估身高和攝像頭焦距計算人到攝像機的距離。在這里選擇身高的原因在於人的身高在不同方向上變化較小,而且我們的攝像頭高度是固定的,所以選擇身高。
首先要使用opencv進行行人檢測:
# import the necessary packages from __future__ import print_function from imutils.object_detection import non_max_suppression from imutils import paths import numpy as np import argparse import imutils import cv2 cap = cv2.VideoCapture(0) # initialize the HOG descriptor/person detector hog = cv2.HOGDescriptor() # 使用opencv默認的SVM分類器 hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector()) while(1): # get a frame ret, frame = cap.read() frame = imutils.resize(frame, width=min(400, frame.shape[1])) # detect people in the image (rects, weights) = hog.detectMultiScale(frame, winStride=(4, 4), padding=(8, 8), scale=1.05) rects = np.array([[x, y, x + w, y + h] for (x, y, w, h) in rects]) # 非極大抑制 消除多余的框 找到最佳人體 pick = non_max_suppression(rects, probs=None, overlapThresh=0.65) # 畫出邊框 for (xA, yA, xB, yB) in pick: cv2.rectangle(frame, (xA, yA), (xB, yB), (0, 255, 0), 2) # show a frame cv2.imshow("capture", frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()
#將行人檢測與測距代碼結合 while camera.isOpened(): # get a frame (grabbed, frame) = camera.read() # 如果不能抓取到一幀,說明我們到了視頻的結尾 if not grabbed: break frame = imutils.resize(frame, width=min(400, frame.shape[1])) #marker = find_marker(frame) marker = find_person(frame) #inches = distance_to_camera(KNOWN_WIDTH, focalLength, marker[1][0]) for (xA, yA, xB, yB) in marker: cv2.rectangle(frame, (xA, yA), (xB, yB), (0, 255, 0), 2) ya_max = yA yb_max = yB pix_person_height = yb_max - ya_max if pix_person_height == 0: #pix_person_height = 1 continue print (pix_person_height) #print (pix_person_height) inches = distance_to_camera(KNOW_PERSON_HEIGHT, focalLength, pix_person_height) print("%.2fcm" % (inches *30.48/ 12)) # draw a bounding box around the image and display it #box = np.int0(cv2.cv.BoxPoints(marker)) #cv2.drawContours(frame, [box], -1, (0, 255, 0), 2) cv2.putText(frame, "%.2fcm" % (inches *30.48/ 12), (frame.shape[1] - 200, frame.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX, 2.0, (0, 255, 0), 3) # show a frame cv2.imshow("capture", frame) if cv2.waitKey(1) & 0xFF == ord('q'): break
原文鏈接:https://blog.csdn.net/m0_37811342/article/details/80394935