使用Python-OpenCV实时测量物体的尺寸大小(仅供参考)
目錄
- 前言
- 一、開發(fā)前準備
- 二、需要的庫
- 三、程序主體
- 3.0 mian()
- 3.1設置被調用的攝像頭類型
- 3.2調用相機
- 3.3圖像處理(輪廓端點查找)
- 3.4邊框繪制(數(shù)據(jù)計算)
- 3.5比率計算
- 3.6參照物選取(拍照)
- 3.7實時測量
- 四、成果展示
前言
注意:不講實現(xiàn)原理,也沒有做UI,精度就玩玩的級別,記得打(盡量柔和的)光。
博主是一名機械設計制造及其自動化專業(yè)的學生,以前在車間上課時總需要挑選特定尺寸的毛坯作為被加工工件,奈何本人較懶,所以就有了碼這么一個py文件出來助我偷懶的想法。
完整的文件(某U加速“學術資源”可以訪問):
- https://github.com/Yjie0929/object-size-measurement-based-on-OpenCV.git
一、開發(fā)前準備
喜歡用Pycharm還是Anaconda或其它都可以,沒有關系。
因為攝像頭使用的只是普通的家用攝像頭(某夕夕個位數(shù)包郵),所以在碼程序之前需要準備一個尺寸精度較高(盡量高)的參照物來獲取歐氏距離和真實長度的比率。
窮得只能3D打印的屑博主:10mm3,20mm3,30mm3
二、需要的庫
from scipy.spatial.distance import euclidean # 用來計算端點之間的歐氏距離 import numpy as np import imutils import time import cv2三、程序主體
3.0 mian()
if __name__ == '__main__':camera_type = set_camera_type() # 設置相機類型filter_area, reference_points = reference_processing() # 創(chuàng)建被過濾面積值rate = rate_calculation() # 計算歐氏距離與實際距離的比率real_time_processing() # 實現(xiàn)實時測量3.1設置被調用的攝像頭類型
這段函數(shù)是為了方便程序能夠在內置相機或外置相機之間來回切換工作。如果確定僅使用外置相機的情況下可以忽略這一步。
def set_camera_type():while True:try:set_type = int(input('攝像頭調用(輸入數(shù)字代號:0.內置,1.外置):'))except ValueError:delay('輸入參數(shù)類型錯誤')continueelse:if (set_type < 0) or (set_type > 1):delay('輸出參數(shù)不在范圍內')continueelif set_type == 0:print('選擇:內置攝像頭')else:print('選擇:外置攝像頭')breakreturn set_type3.2調用相機
如確認僅使用外置相機時將camera_type設置為‘1’,cv2.CAP_DSHOW為可選參數(shù),在相機調用過程中出現(xiàn)不知名報錯時試著加入。關于第二個if,是防止遇到窗口關閉了但又沒有完全關閉的情況而導致的堵塞。
def call_camera():camera = cv2.VideoCapture(camera_type, cv2.CAP_DSHOW)if camera.isOpened() is False:print('攝像頭調用失敗')raise AssertionErrorelse:while True:frame = camera.read()[1] # 返回捕獲到的RGBimage = cv2.flip(frame, 1, dst=None)cv2.imshow('Camera', image) if (cv2.waitKey(1) > -1) or (cv2.getWindowProperty('Camera', cv2.WND_PROP_VISIBLE) < 1.0): # 設置關閉條件cv2.destroyWindow('Camera') breakreturn image3.3圖像處理(輪廓端點查找)
cv2.Canny中的min_val與max_val參數(shù)值的大小可以判斷是否為邊,且值越小,拾取到的邊緣信息就越多。
- cv2.findContours有2個返回值,分別是contours和hierarchy,前者是被檢測到的輪廓信息,后者意義不明。
- imutils.grab_contours用來獲取cv2.findContours的contours,contours才是需要被用于計算的數(shù)據(jù)。
3.4邊框繪制(數(shù)據(jù)計算)
這一部分程序的用處主要是繪制框架與數(shù)據(jù)計算。程序前期在對參照物對象拍照時需要繪制框架呈現(xiàn)出被選中的對像,在程序后期除了要繪制框架外,還要通過比率計算真實長度、面積,最后在繪制框架的同時把計算結果也顯示出來。
def draw_frame(image, points, tag):if tag == 0:for point in points:min_area = cv2.minAreaRect(point)min_area_point = cv2.boxPoints(min_area) # 獲取最小外接矩陣的四個端點int_point = [min_area_point.astype('int')]cv2.drawContours(image, int_point, -1, (0, 0, 255), 1)return min_area_pointelse:for point in points:min_area = cv2.minAreaRect(point) min_area_point = cv2.boxPoints(min_area)left_point, right_point = min_area_point[0], min_area_point[1]X = left_point[0] + int(abs(right_point[0] - left_point[0]) / 2) # 獲取頂部中點X坐標Y = left_point[1] + int(abs(right_point[1] - left_point[1]) / 2) # 獲取頂部中點Y坐標int_point = [min_area_point.astype('int')]cv2.drawContours(image, int_point, -1, (0, 0, 255), 1) # 繪制邊框radius = (euclidean(left_point, right_point) / 2) / rate # 獲取半徑area = int((3.1415926 * pow(radius, 2))) # 展示面積信息cv2.putText(image, '{}'.format(area), (int(X), int(Y)), cv2.FONT_HERSHEY_SIMPLEX, 5, (0, 0, 255), 5)我的檢測對象一般以圓形為主,所以只需要取出最左、最右的兩個點坐標就能夠用于計算了
min_area_point = cv2.boxPoints(min_area) # 獲取最小外接矩陣的四個端點 left_point, right_point = min_area_point[0], min_area_point[1] # 獲取兩處端點的信息3.5比率計算
比率是參照物兩點在度量空間內兩點距離和真實距離的比值,本項目后期所有的計算尺寸均由歐氏距離比上比率得出。
def rate_calculation():delay('計算比率')left_point, right_point = reference_points[0], reference_points[1]length_euclidean = euclidean(left_point, right_point) # 計算歐氏距離while True:try:length_reference = int(input('輸入參照物長度(mm):'))except ValueError:delay('輸入參數(shù)類型錯誤')continueelse:if length_reference <= 0:delay('參數(shù)不可小于或等于0')continueelse:breakrate = length_euclidean / length_reference # 比率計算print('(參照物)歐氏長度:{}mm'.format(length_euclidean))print('(參照物)實際長度:{}mm'.format(length_reference))print('長度比率:{}'.format(rate))return rate3.6參照物選取(拍照)
在調試過程中有多次遇到過拍照后參照物選取不正確,為了防止這一情況的出現(xiàn)就設置了while循環(huán),只有在手動確認參照物被正常框選的情況下才能進入下一步。
值得關注的是selected_points 的篩選方式是采用了將篩選面積不斷加一,直到只剩下參照物對象的方式,即len(selected_points) = 1。
3.7實時測量
這段就不多說了,和前面基本一樣的原理。
def real_time_processing():print('進入實時測量,按下回車鍵結束程序')camera = cv2.VideoCapture(camera_type, cv2.CAP_DSHOW)while True:frame = camera.read()[1]image = cv2.flip(frame, 1, dst=None)points = get_points(image) # 獲取所有參照物的端點selected_points = [][selected_points.append(i) for i in points if cv2.contourArea(i) > filter_area] # 篩選后的端點draw_frame(image, selected_points, 1) # 繪制邊框cv2.imshow('Camera', image) if (cv2.waitKey(1) > -1) or (cv2.getWindowProperty('Camera', cv2.WND_PROP_VISIBLE) < 1.0):cv2.destroyWindow('Camera') break四、成果展示
參照物拍照:(指方為圓)
實時測量:(指方為圓),這里攝像頭高度發(fā)生了變化,拍攝角度也出現(xiàn)誤差,可以采用只存儲最小值數(shù)據(jù)盡量保證精度。
驗證:(高度發(fā)生變化出現(xiàn)的誤差為-4)
總結
以上是生活随笔為你收集整理的使用Python-OpenCV实时测量物体的尺寸大小(仅供参考)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PPASR流式与非流式语音识别
- 下一篇: 某马python day03