OpenCV測量物體的尺寸技能 get~
點(diǎn)擊上方“小白學(xué)視覺”,選擇加"星標(biāo)"或“置頂”
重磅干貨,第一時間送達(dá)


測距原理
性質(zhì)1:參考物尺寸
性質(zhì)2:易于識別
我們應(yīng)該能夠很容易地在圖片中找到參照物體,無論是基于物體的位置(例如,參考物體總是放在圖片的左上角)還是通過外觀(例如,獨(dú)特的顏色或形狀,不同與圖片中的其他物體)。無論是哪種情況,我們的參照物都應(yīng)該以某種方式具有唯一的可識別性。
在下面的例子中,我們將使用美國硬幣作為我們的參考對象,在所有的示例中,確保它始終是圖片中的最左側(cè)的對象。

通過確保硬幣是最左邊的物體,我們可以從左到右對物體輪廓進(jìn)行排序,獲取硬幣(始終是排序列表中的第一個輪廓),并使用它定義每個單位的像素數(shù),我們將其定義為:
已知硬幣的寬度為0.955英寸。現(xiàn)在假設(shè),物體的寬為150像素(基于其關(guān)聯(lián)的邊界框)。
pixels_per_metric可得:
pixels_per_metric=150px/0.955in = 157px/in
因此,在圖片中應(yīng)用每英寸所占的像素點(diǎn)為157個。使用這個比率,我們可以計算圖片中物體的大小。
利用計算機(jī)視覺測量物體的大小
現(xiàn)在我們理解了pixels_per_metric比率的含義,我們可以應(yīng)用python運(yùn)行代碼來測量圖片中的物體大小。
打開一個文件,命名為 object_size.py,并插入以下代碼:
# 導(dǎo)入必要的包from scipy.spatial import distance as distfrom imutils import perspectivefrom imutils import contoursimport numpy as npimport argparseimport imutilsimport cv2def midpoint(ptA, ptB):return ((ptA[0]+ptB[0])*0.5, (ptA[1]+ptB[1])*0.5)# 構(gòu)造解析參數(shù)ap = argparse.ArugmentParser()ap.add_argument("-i", "--image", required=True,help="path to the input image")ap.add_argument("-w", "--width", required=True,help="width of the left-most object in the image(in inches)")args = vars(ap.parse_args()
pip3 install imutils除此之外,如果你安裝了imutils,請確保你安裝了最新版本的,本例中imutils的版本為“0.5.2”
pip3 install --upgrade imutils第10-11行定義個midpoint的輔助函數(shù),從它的名字可知,該函數(shù)是用于計算兩組(x,y)坐標(biāo)的中點(diǎn)。
在第14-19行構(gòu)造解析參數(shù)。我們需要兩個參數(shù),--image,我們需要測量的物體圖片的路徑,--width,參考物體的寬(單位in),假定它是我們圖片中的最左邊的對象。
# 導(dǎo)入圖片轉(zhuǎn)換為灰度圖,并進(jìn)行輕微的模糊image = cv2.imread(args["image"])gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)gray = cv2.GaussianBlur(gray, (7, 7), 0)# 執(zhí)行邊緣檢測# 然后在物體之間的邊緣執(zhí)行膨脹+腐蝕操作使其縫隙閉合edged = cv2.Canny(gray, 50, 100)edged = cv2.dilate(edged, None, iterations=1)edged = cv2.erode(edged, None, iterations=1)# 在邊緣圖中查找輪廓cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cnts = imutils.grab_contours(cnts)# 從左往右對輪廓進(jìn)行排序# 初始化'pixels per metric' 校準(zhǔn)變量(cnts, _) = contours.sort_contours(cnts)pixelsPerMetric = None
2-4行 從磁盤中導(dǎo)入圖片,轉(zhuǎn)換為灰度圖,然后用高斯濾波進(jìn)行平滑。
然后,我們執(zhí)行邊緣檢測和膨脹+腐蝕操作以閉合邊緣圖片中所有邊緣之間的間隙。
13-15行在我們的邊緣圖片中找相應(yīng)物體的輪廓。
19行將這些輪廓從左往右排序。初始化'pixels per metric' 的值
下一步就是去檢測每個輪廓:
for c in cnts:if cv2.contourArea(c)<100:continueorig = image.copy()box = cv2.minAreaRect(c)box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)box = np.array(box, dtype="int")box = perspective.order_points(box)cv2.drawContours(orig, [box.astype("int")], -1, (0,255,0), 2)for (x, y) in box:cv2.circle(orig, (int(x), int(y)), 5, (0,0,255), -1)
2行開始遍歷每個單獨(dú)的輪廓。
如果輪廓不夠大,則會丟棄該區(qū)域,認(rèn)為該區(qū)域是邊緣檢測過程中留下的噪聲(4-5行)。
如果輪廓區(qū)域足夠大,在第9-11行計算圖中的選擇邊界框,特別注意OpenCV2使用的是cv2.cv.BoxPoints函數(shù),OpenCV3使用的是cv2.boxPoints函數(shù)。
然后,我們按照左上、右上、右下和左下的順序排列旋轉(zhuǎn)的邊界框坐標(biāo)。
最后,第16-20行用綠色的線畫出物體的輪廓,然后用紅色的小圓圈繪制出邊界框矩形的頂點(diǎn)。
現(xiàn)在我們已經(jīng)對邊界框進(jìn)行了排序,我們可以計算一系列的中點(diǎn):
# 打開有序的邊界框,然后計算左上和右上坐標(biāo)之間的中點(diǎn),# 再計算左下和右下坐標(biāo)之間的中點(diǎn)(tl, tr, br, bl) = box(tltrX, tltrY) = midpoint(tl, tr)(blbrX, blbrY) = midpoint(bl, br)# 計算左上點(diǎn)和右上點(diǎn)之間的中點(diǎn)# 然后是右上角和右下角之間的中點(diǎn)(tlblX, tlblY) = midpoint(tl, bl)(trbrX, trbrY) = midpoint(tr, br)# 在圖中畫出中點(diǎn)cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)# 在中點(diǎn)之間繪制線cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),(255, 0, 255), 2)cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),(255, 0, 255), 2)
第3-5行取出有序的邊界框,然后計算左上和右上點(diǎn)之間的中點(diǎn),再計算左下和右下點(diǎn)之間的中點(diǎn)。
我們還將分別計算左上+左下和右上+右下之間的中點(diǎn)。
第13-16行在圖中畫出藍(lán)色的中點(diǎn),然后用紫色線連接中點(diǎn)。
接下來,我們通過分析參考物體來初始化pixelsPerMetric值
# 計算中點(diǎn)間的歐式距離dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))# 如果pixels per metric還未初始化,# 則將其計算為像素與提供的度量的比率(本例中為英寸)if pixelsPerMetric is None:pixelsPerMetric = dB / args["width"]
第2-3行計算集合中的中點(diǎn)的歐式距離。
dA保存的是高度距離,dB保存的是寬度距離。
然后,我在第7行進(jìn)行檢測pixelsPerMetric是否被初始化了,如果未被初始化,我們通過用dB出于--width提供的值,得到我們需要每英寸的像素數(shù)。
現(xiàn)在pixelsPerMetric的值已經(jīng)被定義,我們可以測量圖片中物體的大小
dimA = dA / pixelsPerMetricdimB = dB / pixelsPerMetriccv2.putText(orig, "{:.1f}in".format(dimA),(int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,0.65, (255, 255, 255), 2)cv2.putText(orig, "{:.1f}in".format(dimB),(int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,0.65, (255, 255, 255), 2)cv2.imshow("Image", orig)cv2.waitKey(0)
第2-3行通過對應(yīng)的歐式距離除以pixelsPerMetric計算得到物體的尺寸。
第6-11行在圖中畫出物體的尺寸,而第14-15行為顯示輸出結(jié)果的圖片。
物體尺寸測量結(jié)果
在命令行中輸入
python3 object_size.py --image images/example_01.png --width 0.955輸出結(jié)果如下圖所示:

如上圖所示,我們已經(jīng)成功的計算出圖片中每個物體的尺寸。
然而,并非所有的結(jié)果都是完美的。
可能的原因
1、拍攝的角度并非是一個完美的90°俯視。如果不是90°拍攝,物體的尺寸可能會出現(xiàn)扭曲。
2、沒有使用相機(jī)內(nèi)在和外在參數(shù)來校準(zhǔn)。當(dāng)無法確定這些參數(shù)時,照片很容易發(fā)生徑向和切向的透鏡變形。執(zhí)行額外的校準(zhǔn)步驟來找到這些參數(shù)可以消除圖片中的失真并得到更好的物體大小的近似值。

總結(jié)
在本文中,我們學(xué)習(xí)了如何通過使用python和OpenCV來測量圖片中的物體的大小。
我們需要確定pixels per metric比率(單位尺寸像素數(shù)),即在給定的度量(如英寸、毫米、米等)下,像素的數(shù)量。
為了計算這個比率,我們需要一個參考物體,它需要兩點(diǎn)重要的性質(zhì):
1、參考物體需要有含測量單位(英寸、毫米等等)的尺寸
2、無論從物體的位置還是形狀,參考物體都需要容易被找到。
加入上面的性質(zhì)都能滿足,你可以使用參考物體計算pixels per metric比率,并根據(jù)這個計算圖片中物體的大小。

英文原文:
https://www.pyimagesearch.com/2016/03/28/measuring-size-of-objects-in-an-image-with-opencv/
其他參考項目:https://github.com/snsharma1311/object-size

詳細(xì)代碼鏈接:https://github.com/DWCTOD/AI_study/tree/master/%E5%90%88%E6%A0%BC%E7%9A%84CV%E5%B7%A5%E7%A8%8B%E5%B8%88/%E5%AE%9E%E6%88%98%E7%AF%87/opencv/%EF%BC%88%E5%85%AD%EF%BC%89%E5%88%A9%E7%94%A8python%E5%92%8COpenCV%E6%B5%8B%E9%87%8F%E7%89%A9%E4%BD%93%E7%9A%84%E5%A4%A7%E5%B0%8F
好消息!
小白學(xué)視覺知識星球
開始面向外開放啦??????
下載1:OpenCV-Contrib擴(kuò)展模塊中文版教程 在「小白學(xué)視覺」公眾號后臺回復(fù):擴(kuò)展模塊中文教程,即可下載全網(wǎng)第一份OpenCV擴(kuò)展模塊教程中文版,涵蓋擴(kuò)展模塊安裝、SFM算法、立體視覺、目標(biāo)跟蹤、生物視覺、超分辨率處理等二十多章內(nèi)容。 下載2:Python視覺實戰(zhàn)項目52講 在「小白學(xué)視覺」公眾號后臺回復(fù):Python視覺實戰(zhàn)項目,即可下載包括圖像分割、口罩檢測、車道線檢測、車輛計數(shù)、添加眼線、車牌識別、字符識別、情緒檢測、文本內(nèi)容提取、面部識別等31個視覺實戰(zhàn)項目,助力快速學(xué)校計算機(jī)視覺。 下載3:OpenCV實戰(zhàn)項目20講 在「小白學(xué)視覺」公眾號后臺回復(fù):OpenCV實戰(zhàn)項目20講,即可下載含有20個基于OpenCV實現(xiàn)20個實戰(zhàn)項目,實現(xiàn)OpenCV學(xué)習(xí)進(jìn)階。 交流群
歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器、自動駕駛、計算攝影、檢測、分割、識別、醫(yī)學(xué)影像、GAN、算法競賽等微信群(以后會逐漸細(xì)分),請掃描下面微信號加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會根據(jù)研究方向邀請進(jìn)入相關(guān)微信群。請勿在群內(nèi)發(fā)送廣告,否則會請出群,謝謝理解~

