目錄
1.簡(jiǎn)介
2.基于單目相機(jī)的2D測(cè)量
2.1 想法:
2.2 代碼思路
2.2 主函數(shù)部分
1.簡(jiǎn)介
基于單目相機(jī)的2D測(cè)量技術(shù)在許多領(lǐng)域中具有重要的背景和意義。
-
工業(yè)制造:在工業(yè)制造過(guò)程中,精確測(cè)量是確保產(chǎn)品質(zhì)量和一致性的關(guān)鍵?;趩文肯鄼C(jī)的2D測(cè)量技術(shù)可以用于檢測(cè)和測(cè)量零件尺寸、位置、形狀等參數(shù),進(jìn)而實(shí)現(xiàn)自動(dòng)化生產(chǎn)和質(zhì)量控制。通過(guò)實(shí)時(shí)監(jiān)測(cè)并反饋測(cè)量結(jié)果,可以快速發(fā)現(xiàn)和糾正生產(chǎn)中的偏差,提高產(chǎn)品的一致性和合格率。
-
計(jì)算機(jī)視覺(jué):?jiǎn)文肯鄼C(jī)作為計(jì)算機(jī)視覺(jué)的傳感器之一,能夠捕捉并記錄場(chǎng)景中的圖像信息?;趩文肯鄼C(jī)的2D測(cè)量技術(shù)可以通過(guò)對(duì)圖像進(jìn)行處理和分析來(lái)提取目標(biāo)物體的特征和參數(shù)。這種技術(shù)在目標(biāo)檢測(cè)、物體跟蹤、姿態(tài)估計(jì)等計(jì)算機(jī)視覺(jué)任務(wù)中起著至關(guān)重要的作用。
-
地理測(cè)繪和導(dǎo)航:基于單目相機(jī)的2D測(cè)量技術(shù)可以應(yīng)用于地理測(cè)繪和導(dǎo)航領(lǐng)域。通過(guò)獲取地面或航空?qǐng)D像,并利用圖像處理和計(jì)算機(jī)視覺(jué)算法,可以實(shí)現(xiàn)地表特征的提取、地形建模、數(shù)字地圖的生成等工作。這對(duì)于城市規(guī)劃、農(nóng)業(yè)管理、導(dǎo)航系統(tǒng)等方面具有重要的應(yīng)用價(jià)值。
-
醫(yī)學(xué)影像:在醫(yī)學(xué)領(lǐng)域,基于單目相機(jī)的2D測(cè)量技術(shù)可以用于醫(yī)學(xué)影像的分析和測(cè)量。通過(guò)對(duì)醫(yī)學(xué)圖像進(jìn)行處理和分析,可以提取器官、病灶的形狀、大小、位置等信息,輔助醫(yī)生進(jìn)行診斷和治療決策。這種技術(shù)在影像學(xué)、放射學(xué)、眼科等醫(yī)學(xué)專(zhuān)業(yè)中得到廣泛應(yīng)用。
綜上所述,基于單目相機(jī)的2D測(cè)量技術(shù)在工業(yè)制造、計(jì)算機(jī)視覺(jué)、地理測(cè)繪和導(dǎo)航、醫(yī)學(xué)影像等領(lǐng)域都有著重要的背景和意義。它可以提高生產(chǎn)效率、產(chǎn)品質(zhì)量,推動(dòng)科學(xué)研究和醫(yī)學(xué)進(jìn)步,為各個(gè)領(lǐng)域帶來(lái)更多的機(jī)遇和挑戰(zhàn)。
2.基于單目相機(jī)的2D測(cè)量
2.1 想法:
因?yàn)槭庆o態(tài)測(cè)量,所以核心測(cè)量算法使用仿射變換。
首先拿到參照物區(qū)域,進(jìn)行真實(shí)距離和像素距離的尺寸換算
在參照物區(qū)域找到物體輪廓,進(jìn)行多邊形擬合,對(duì)擬合到的物體進(jìn)行測(cè)量
2.2 代碼思路
代碼思路的簡(jiǎn)要描述:
-
導(dǎo)入所需的庫(kù),包括
cv2
和自定義的utlis
。 -
初始化一些變量,如是否使用網(wǎng)絡(luò)攝像機(jī) (
webcam
)、圖像路徑 (path
)、捕獲對(duì)象 (cap
)、圖像縮放比例 (scale
)、紙張寬度和高度 (wP
和hP
) 以及上一幀時(shí)間 (pTime
)。 -
進(jìn)入主循環(huán)。在每次循環(huán)中,如果使用網(wǎng)絡(luò)攝像機(jī),則讀取圖像幀;否則,從指定路徑讀取圖像。
-
對(duì)圖像進(jìn)行輪廓檢測(cè),獲取所有檢測(cè)到的輪廓 (
conts
) 和最大輪廓 (biggest
)。 -
使用最大輪廓對(duì)圖像進(jìn)行透視變換 (
warpImg
),得到紙張的鳥(niǎo)瞰圖 (imgWarp
)。 -
對(duì)紙張鳥(niǎo)瞰圖進(jìn)行輪廓檢測(cè),獲取所有檢測(cè)到的輪廓 (
conts2
)。 -
遍歷每個(gè)輪廓對(duì)象,繪制輪廓線和箭頭,并計(jì)算測(cè)量結(jié)果 (紙張寬度
nW
和高度nH
)。 -
在圖像上繪制測(cè)量結(jié)果和幀率信息。
-
顯示原始圖像和處理后的圖像。
-
等待按鍵,繼續(xù)下一次循環(huán)。
以上是代碼的簡(jiǎn)要思路,具體實(shí)現(xiàn)和功能可以參考代碼中的注釋。
關(guān)于復(fù)現(xiàn),你可以準(zhǔn)備一張A4紙,一張小卡片,或者邊緣信息明顯的其他物件,按照?qǐng)D片中方式擺放即可。
像素與真實(shí)距離換算為
3像素=1mm
檢測(cè)幀率可達(dá)30幀,誤差在2%(誤差取決相機(jī)分辨率),缺點(diǎn)是無(wú)法檢測(cè)輪廓不清晰的物件以及復(fù)雜物體。
下一篇介紹如何測(cè)量復(fù)雜形狀的物體
2.2 主函數(shù)部分
import cv2
import utlis
import time
###################################
webcam = True # 網(wǎng)絡(luò)攝像機(jī)一開(kāi)始為FALSE
path = '1.jpg'
cap = cv2.VideoCapture(0) # 使用捕獲和cv定義相機(jī)-點(diǎn)點(diǎn)視頻捕獲,,我們將定義id,因此在這種情況下為0
cap.set(10, 160) # 設(shè)置參數(shù),寬度,高度,亮度,為他們中的每一根寫(xiě)入間隙點(diǎn)集,具有不同的亮度id,有十個(gè),所以將其保持為160,然后在寬度和高度上,寬度為3,1920
cap.set(3, 1920)
cap.set(4, 1080)
scale = 3
wP = 270 * scale
hP = 370 * scale
###################################
pTime = 0
while True:
if webcam:
success, img = cap.read()
else:
img = cv2.imread(path)
imgContours, conts = utlis.getContours(img, minArea=50000, filter=4)
if len(conts) != 0:
biggest = conts[0][2]
# print(biggest)
imgWarp = utlis.warpImg(img, biggest, wP, hP)
imgContours2, conts2 = utlis.getContours(imgWarp,
minArea=2000, filter=4,
cThr=[50, 50], draw=False)
if len(conts) != 0:
for obj in conts2:
cv2.polylines(imgContours2, [obj[2]], True, (0, 255, 0), 2)
nPoints = utlis.reorder(obj[2])
nW = round((utlis.findDis(nPoints[0][0] // scale, nPoints[1][0] // scale) / 10), 1)
nH = round((utlis.findDis(nPoints[0][0] // scale, nPoints[2][0] // scale) / 10), 1)
cv2.arrowedLine(imgContours2, (nPoints[0][0][0], nPoints[0][0][1]),
(nPoints[1][0][0], nPoints[1][0][1]),
(255, 0, 255), 3, 8, 0, 0.05)
cv2.arrowedLine(imgContours2, (nPoints[0][0][0], nPoints[0][0][1]),
(nPoints[2][0][0], nPoints[2][0][1]),
(255, 0, 255), 3, 8, 0, 0.05)
x, y, w, h = obj[3]
cv2.putText(imgContours2, '{}cm'.format(nW), (x + 30, y - 10), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1.5,
(255, 0, 255), 2)
cv2.putText(imgContours2, '{}cm'.format(nH), (x - 70, y + h // 2), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1.5,
(255, 0, 255), 2)
cTime = time.time()
fps = 1 / (cTime - pTime)
pTime = cTime
cv2.putText(imgContours2, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3,
(255, 0, 255), 3)
# 圖像預(yù)處理及邊緣檢測(cè)
cv2.imshow('A4', imgContours2)
img = cv2.resize(img, (0, 0), None, 0.5, 0.5)
cv2.imshow('Original', img)
cv2.waitKey(1)
utlis模塊代碼
import cv2
import numpy as np
import math
import time
def getContours(img, cThr=[100, 100], showCanny=False, minArea=5000, filter=0, draw=False):
# 將輸入圖像轉(zhuǎn)換為灰度圖像
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 對(duì)灰度圖像進(jìn)行高斯模糊
imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1)
# 使用Canny邊緣檢測(cè)算法得到邊緣圖像
imgCanny = cv2.Canny(imgBlur, cThr[0], cThr[1])
# 對(duì)Canny邊緣圖像進(jìn)行膨脹操作
kernel = np.ones((5, 5))
imgDial = cv2.dilate(imgCanny, kernel, iterations=3)
# 對(duì)膨脹后的圖像進(jìn)行腐蝕操作
imgThre = cv2.erode(imgDial, kernel, iterations=1)
# gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# kernal = np.ones((5, 5), np.uint8)
# blurred = cv2.erode(blurred, kernal) # 腐蝕
# blurred = cv2.erode(blurred, kernal)
# edges = cv2.Canny(blurred, 50, 150)
# 尋找圖像中的輪廓
contours, hierarchy = cv2.findContours(imgThre, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
finalContours = []
for i in contours:
area = cv2.contourArea(i)
# 僅保留面積大于minArea的輪廓
if area > minArea:
peri = cv2.arcLength(i, True)
approx = cv2.approxPolyDP(i, 0.02 * peri, True)
bbox = cv2.boundingRect(approx)
if filter > 0:
# 如果指定了過(guò)濾條件,僅保留滿足條件的輪廓
if len(approx) == filter:
finalContours.append([len(approx), area, approx, bbox, i])
else:
finalContours.append([len(approx), area, approx, bbox, i])
# 根據(jù)面積對(duì)輪廓進(jìn)行排序
finalContours = sorted(finalContours, key=lambda x: x[1], reverse=True)
if draw:
# 將保留的輪廓在原始圖像上繪制出來(lái)
for con in finalContours:
cv2.drawContours(img, con[4], -1, (0, 0, 255), 3)
return img, finalContours
def dectshow(org_img, boxs):
img = org_img.copy()
for box in boxs:
cv2.rectangle(img, (int(box[0]), int(box[1])), (int(box[2]), int(box[3])), (0, 255, 0), 2)
x1 = box[0]
y1 = box[1]
x2 = box[2]
y2 = box[3]
cv2.circle(img, (x1, y1), 5, (0, 0, 255), -1) # 紅色圓點(diǎn)
cv2.circle(img, (x2, y1), 5, (0, 255, 0), -1) # 綠色圓點(diǎn)
cv2.circle(img, (x2, y2), 5, (255, 0, 0), -1) # 藍(lán)色圓點(diǎn)
point1 = [x1, y1]
point2 = [x2, y1]
point3 = [x2, y2]
width = math.sqrt((point2[0] - point1[0]) ** 2 + (point2[1] - point1[1]) ** 2)
height = math.sqrt((point3[0] - point2[0]) ** 2 + (point3[1] - point2[1]) ** 2)
width = width/3
height = height/3
# cv2.imshow('1', img)
# 計(jì)算兩點(diǎn)之間的距離
print("寬 is:", width, "m")
print("長(zhǎng) is:", height, "m")
cv2.putText(img, f'W: {str(width)[:4] }mm H: {str(height)[:4]}mm', (int(box[0]), int(box[1]) - 40), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
(0, 255, 0), 2)
cv2.imshow('dec_img', img)
return img
# 對(duì)角點(diǎn)排序函數(shù)
def reorder(myPoints):
myPointsNew = np.zeros_like(myPoints)
myPoints = myPoints.reshape((4, 2))
add = myPoints.sum(1)
myPointsNew[0] = myPoints[np.argmin(add)]
myPointsNew[3] = myPoints[np.argmax(add)]
diff = np.diff(myPoints, axis=1)
myPointsNew[1] = myPoints[np.argmin(diff)]
myPointsNew[2] = myPoints[np.argmax(diff)]
return myPointsNew
# 透視變換函數(shù)
def warpImg(img, points, w, h, pad=20):
points = reorder(points)
pts1 = np.float32(points)
pts2 = np.float32([[0, 0], [w, 0], [0, h], [w, h]])
matrix = cv2.getPerspectiveTransform(pts1, pts2)
imgWarp = cv2.warpPerspective(img, matrix, (w, h))
imgWarp = imgWarp[pad:imgWarp.shape[0] - pad, pad:imgWarp.shape[1] - pad]
return imgWarp
# 計(jì)算兩點(diǎn)之間的距離
def findDis(pts1, pts2):
return ((pts2[0] - pts1[0]) ** 2 + (pts2[1] - pts1[1]) ** 2) ** 0.5
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-739617.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-739617.html
到了這里,關(guān)于基于單目相機(jī)的2D測(cè)量(工件尺寸和物體尺寸)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!