攝像頭測(cè)距就是計(jì)算照片中的目標(biāo)物體到相機(jī)的距離。可以使用相似三角形(triangle similarity)方法實(shí)現(xiàn),或者使用更復(fù)雜但更準(zhǔn)確的相機(jī)模型的內(nèi)參來實(shí)現(xiàn)這個(gè)功能。
使用相似三角形計(jì)算物體到相機(jī)的距離
假設(shè)物體的寬度為 W,將其放到離相機(jī)距離為 D 的位置,然后對(duì)物體進(jìn)行拍照。在照片上量出物體的像素寬度 P,于是可以得出計(jì)算相機(jī)焦距 F 的公式:
比如我在相機(jī)前 24 英寸距離(D=24 inches)的位置橫著放了一張 8.5 x 11 英寸(W=11 inches)的紙,拍照后通過圖像處理得出照片上紙的像素寬度 P=248 pixels。所以焦距 F 等于:
此時(shí)移動(dòng)相機(jī)離物體更近或者更遠(yuǎn),我們可以應(yīng)用相似三角形得到計(jì)算物體到相機(jī)的距離的公式:
原理大概就是這樣,接下來使用 OpenCV 來實(shí)現(xiàn)。
獲取目標(biāo)輪廓
# import the necessary packages from imutils import paths import numpy as np import imutils 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) cnts = imutils.grab_contours(cnts) c = max(cnts, key = cv2.contourArea) # compute the bounding box of the of the paper region and return it return cv2.minAreaRect(c)
定義一個(gè) find_marker 函數(shù),接收一個(gè)參數(shù) iamge,用來找到要計(jì)算距離的物體。這里我們用一張 8.5 x 11 英寸的紙作為目標(biāo)物體。第一個(gè)任務(wù)是在圖片中找到目標(biāo)物體。
下面這三行是先將圖片轉(zhuǎn)換為灰度圖,并進(jìn)行輕微模糊處理以去除高頻噪聲,然后進(jìn)行邊緣檢測(cè)。
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (5, 5), 0) edged = cv2.Canny(gray, 35, 125)
做了這幾步后圖片看起來是這樣的:

現(xiàn)在已經(jīng)可以清晰地看到這張紙的邊緣,接下來需要做的是找出這張紙的輪廓。
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) cnts = imutils.grab_contours(cnts) c = max(cnts, key = cv2.contourArea)
用 cv2.findContours 函數(shù)找到圖片中的眾多輪廓,然后獲取其中面積最大的輪廓,并假設(shè)這是目標(biāo)物體的輪廓。
這種假設(shè)只適用于我們這個(gè)場(chǎng)景,在實(shí)際使用時(shí),在圖片中找出目標(biāo)物體的方法與應(yīng)用場(chǎng)景有很大關(guān)系。
我們這個(gè)場(chǎng)景用簡單的邊緣檢測(cè)并找出最大的輪廓就可以了。當(dāng)然為了使程序更具有魯棒性,也可以用輪廓近似,并剔除不是四個(gè)點(diǎn)的輪廓(紙張是一個(gè)有四個(gè)點(diǎn)的矩形),然后再找出面積最大,具有四個(gè)點(diǎn)的輪廓。
注意: 關(guān)于這個(gè)方法,詳情可以查看這篇文章,用于構(gòu)建一個(gè)移動(dòng)文本掃描工具。
我們也可以根據(jù)顏色特征在圖片中找到目標(biāo)物體,因?yàn)槟繕?biāo)物體和背景的顏色有著很明顯的不同。還可以應(yīng)用關(guān)鍵點(diǎn)檢測(cè)(keypoint detection),局部不變性描述子(local invariant descriptors)和關(guān)鍵點(diǎn)匹配(keypoint matching)來尋找目標(biāo)。但是這些方法不在本文的討論范圍內(nèi),而且高度依賴具體場(chǎng)景。
我們現(xiàn)在得到目標(biāo)物體的輪廓了,find_marker 函數(shù)最后返回的是包含輪廓 (x, y) 坐標(biāo)、像素長度和像素寬度的邊框,
計(jì)算距離
接下來該使用相似三角形計(jì)算目標(biāo)到相機(jī)的距離。
def distance_to_camera(knownWidth, focalLength, perWidth):
# compute and return the distance from the maker to the camera
return (knownWidth * focalLength) / perWidth
distance_to_camera 函數(shù)傳入目標(biāo)的實(shí)際寬度,計(jì)算得到的焦距和圖片上目標(biāo)的像素寬度,就可以通過相似三角形公式計(jì)算目標(biāo)到相機(jī)的距離了。
下面是調(diào)用 distance_to_camera 函數(shù)之前的準(zhǔn)備:
# 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 12 inches wide KNOWN_WIDTH = 11.0 # 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("images/2ft.jpg") marker = find_marker(image) focalLength = (marker[1][0] * KNOWN_DISTANCE) / KNOWN_WIDTH
首先是測(cè)量目標(biāo)物體的寬度,和目標(biāo)物體到相機(jī)的距離,并根據(jù)上面介紹的方法計(jì)算相機(jī)的焦距。其實(shí)這些并不是真正的攝像機(jī)標(biāo)定。真正的攝像機(jī)標(biāo)定包括攝像機(jī)的內(nèi)參,相關(guān)知識(shí)可以可以查看這里。
使用 cv2.imread 函數(shù)從磁盤加載圖片,然后通過 find_marker 函數(shù)得到圖片中目標(biāo)物體的坐標(biāo)和長寬信息,最后根據(jù)相似三角形計(jì)算出相機(jī)的焦距。
現(xiàn)在有了相機(jī)的焦距,就可以計(jì)算目標(biāo)物體到相機(jī)的距離了。
# loop over the images
for imagePath in sorted(paths.list_images("images")):
# load the image, find the marker in the image, then compute the
# distance to the marker from the camera
image = cv2.imread(imagePath)
marker = find_marker(image)
inches = distance_to_camera(KNOWN_WIDTH, focalLength, marker[1][0])
# draw a bounding box around the image and display it
box = cv2.cv.BoxPoints(marker) if imutils.is_cv2() else cv2.boxPoints(marker)
box = np.int0(box)
cv2.drawContours(image, [box], -1, (0, 255, 0), 2)
cv2.putText(image, "%.2fft" % (inches / 12),
(image.shape[1] - 200, image.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX,
2.0, (0, 255, 0), 3)
cv2.imshow("image", image)
cv2.waitKey(0)
使用 for 循環(huán)遍歷每個(gè)圖片,計(jì)算每張圖片中目標(biāo)對(duì)象到相機(jī)的距離。在結(jié)果中,我們根據(jù)得到的輪廓信息將方框畫了出來,并顯示出了距離。下面是得到的幾個(gè)結(jié)果圖:


總結(jié)
通過這篇文章,我們學(xué)會(huì)了使用相似三角形計(jì)算圖片中一個(gè)已知物體到相機(jī)的距離。
需要先測(cè)量出目標(biāo)物體的實(shí)際寬度和目標(biāo)物體到相機(jī)的距離,然后使用圖像處理的方法自動(dòng)計(jì)算圖片中目標(biāo)物體的像素寬度,并使用相似三角形計(jì)算出相機(jī)的焦距。
根據(jù)相機(jī)的焦距就可以計(jì)算圖片中的目標(biāo)物體到相機(jī)的距離。
原文作者Adrian Rosebrock博士 在此特別鳴謝
-
機(jī)器視覺
+關(guān)注
關(guān)注
165文章
4798瀏覽量
126045 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4417瀏覽量
67502 -
OpenCV
+關(guān)注
關(guān)注
33文章
652瀏覽量
44786 -
python
+關(guān)注
關(guān)注
57文章
4876瀏覽量
90025
原文標(biāo)題:使用OpenCV實(shí)現(xiàn)攝像頭測(cè)距
文章出處:【微信號(hào):vision263com,微信公眾號(hào):新機(jī)器視覺】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
沒有專利的opencv-python 版本
【芯靈思A83T試用申請(qǐng)】嵌入式視覺--遠(yuǎn)距離物體跟蹤與定位
LabVIEW+Python+openCV
如何使用Python中的OpenCV模塊檢測(cè)顏色
OpenCV-Python-Toturial-中文版
在Python下使用OpenCV的技巧教程與典型應(yīng)用案例
python圖像處理opencv步驟是怎么樣的
簡述我們?cè)撊绾问褂?b class='flag-5'>OpenCV測(cè)量圖像中物體之間的距離
如何用Python和OpenCV來測(cè)量相機(jī)到目標(biāo)的距離
Linux Debian與Python、Flask和OpenCV識(shí)別面部
使用opencv和python進(jìn)行智能火災(zāi)檢測(cè)
使用OpenCV實(shí)現(xiàn)目標(biāo)物體到相機(jī)的距離測(cè)量
用于距離測(cè)量和物體檢測(cè)的飛行時(shí)間系統(tǒng)
使用Python和OpenCV查找從相機(jī)到物體/標(biāo)記的距離
評(píng)論