OpenCV圖像識(shí)別之相機(jī)校準(zhǔn)Camera?Calibration學(xué)習(xí)
目標(biāo)
在本節(jié)中,將學(xué)習(xí)
- 由相機(jī)引起的失真類型
- 如何找到相機(jī)的固有和非固有特性
- 如何基于這些特性使圖像不失真
基礎(chǔ)
一些針孔相機(jī)會(huì)給圖像帶來明顯的失真。兩種主要的變形:
- 徑向變形( radial distortion)
- 切向變形( tangential distortion)
徑向變形
徑向變形會(huì)導(dǎo)致直線出現(xiàn)彎曲。距圖像中心越遠(yuǎn),徑向畸變?cè)酱?。例如,下面顯示一個(gè)圖像,其中棋盤的兩個(gè)邊緣用紅線標(biāo)記。但是,會(huì)看到棋盤的邊框不是直線,并且與紅線不匹配。所有預(yù)期的直線都凸出。
徑向變形的變形量可以用下面的式子表示:
除此之外,還需要其他一些信息,相機(jī)的內(nèi)在和外在參數(shù).
- 外在參數(shù)對(duì)應(yīng)于旋轉(zhuǎn)和平移矢量,其將3D點(diǎn)的坐標(biāo)平移為坐標(biāo)系。
對(duì)于3D應(yīng)用,首先需要糾正這些失真,就要找到這些參數(shù)。以國(guó)際象棋棋盤為示例圖像,找到一些已經(jīng)知道其相對(duì)位置的特定點(diǎn)(例如棋盤上的四角)。假設(shè)知道了現(xiàn)實(shí)世界空間中這些點(diǎn)的坐標(biāo),也知道圖像中的坐標(biāo),就可以求解失真系數(shù)了。
代碼
如上所述,相機(jī)校準(zhǔn)至少需要10個(gè)測(cè)試圖案。OpenCV項(xiàng)目中附帶了一些國(guó)際象棋棋盤的圖像,因此將利用這些圖像進(jìn)行講解。假設(shè)給定一張棋盤圖像,相機(jī)校準(zhǔn)所需的重要輸入數(shù)據(jù)是3D真實(shí)點(diǎn)集以及圖像中這些點(diǎn)的相應(yīng)2D坐標(biāo)。2D圖像點(diǎn)可以從圖像中輕松找到點(diǎn)(這些圖像點(diǎn)是國(guó)際象棋棋盤中兩個(gè)黑色正方形相互接觸的位置)。
真實(shí)3D點(diǎn)如何處理?這些圖像是從靜態(tài)相機(jī)拍攝的,而國(guó)際象棋棋盤放置在不同的位置和方向。因此,需要知道(X,Y,Z)(X, Y, Z)(X,Y,Z)值。但是為簡(jiǎn)單起見,可以說棋盤在XYXYXY平面上保持靜止(因此Z始終為0),并且照相機(jī)也相應(yīng)地移動(dòng)了。這種考慮有助于僅找到X,Y值?,F(xiàn)在對(duì)于X,Y值,可以簡(jiǎn)單地將點(diǎn)傳遞為(0,0),(1,0),(2,0),…,這表示點(diǎn)的位置。在這種情況下,得到的結(jié)果將是棋盤正方形的大小比例。但是,當(dāng)我們知道正方形大?。ɡ?0毫米),則可以將值傳遞為(0,0),(30,0),(60,0),…。因此,得到的結(jié)果以毫米為單位。(在這種情況下,我們不知道正方形的大小,因?yàn)槲覀儧]有拍攝那些圖像,因此我們以正方形的大小進(jìn)行傳遞)。
3D點(diǎn)稱為對(duì)象點(diǎn),而2D圖像點(diǎn)稱為圖像點(diǎn)。
開始
為了在國(guó)際象棋棋盤圖像中查找圖案,可以使用函數(shù)cv2.findChessboardCorners()
。該函數(shù)需要傳遞所需的圖案,例如8x8網(wǎng)格,5x5網(wǎng)格等。在此示例中使用7x6網(wǎng)格。(通常,棋盤有8x8的正方形和7x7的內(nèi)部角)。它返回角點(diǎn)和返回值,如果獲得圖案,則返回值為True。這些角將按順序放置(從左到右,從上到下)
此函數(shù)可能無法在所有圖像中找到所需的圖案。因此一個(gè)不錯(cuò)的選擇是編寫代碼,使它啟動(dòng)相機(jī)并檢查每幀所需的圖案。獲得圖案后,找到角并將其存儲(chǔ)在列表中。另外,在讀下一幀之前請(qǐng)?jiān)O(shè)置一些時(shí)間間隔,以便可以在不同方向上調(diào)整棋盤。繼續(xù)此過程,直到獲得所需數(shù)量的良好圖案為止。即使在此處提供的示例中,也不確定給出的14張圖像中有多少?gòu)埵呛玫?。因此,必須閱讀所有圖像并僅保存好的團(tuán)。 除了棋盤之外,還可以使用圓形網(wǎng)格。 在這種情況下,必須使用函數(shù)cv2.findCirclesGrid()
來找到模式。 較少的圖像足以使用圓形網(wǎng)格執(zhí)行相機(jī)校準(zhǔn)。
一旦找到拐角,就可以使用cv2.cornerSubPix()
來提高其精度。還可以使用cv2.drawChessboardCorners()
繪制圖案。所有這些步驟都包含在以下代碼中:
# termination criteria criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) # prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0) objp = np.zeros((6*7,3), np.float32) objp[:, :2] = np.mgrid[0:7,0:6].T.reshape(-1,2) # # Arrays to store object points and image points from all the images. objpoints = [] # 3d point in real world space imgpoints = [] # 2d points in image plane. images = glob.glob(r'right*.jpg') for fname in images: img = cv2.imread(fname) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # find the chess board corners ret, corners = cv2.findChessboardCorners(gray, (7,6), None) if ret: objpoints.append(objp) corners2 = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria) imgpoints.append(corners) # draw and display the corners cv2.drawChessboardCorners(img, (7, 6), corners2, ret) cv2.imshow('img', img) cv2.waitKey(0) cv2.destroyAllWindows()
校準(zhǔn)
有了目標(biāo)點(diǎn)和圖像點(diǎn),就可以進(jìn)行校準(zhǔn)??梢允褂煤瘮?shù)cv2.calibrateCamera()
返回相機(jī)矩陣,失真系數(shù),旋轉(zhuǎn)和平移矢量等。
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
不畸變
現(xiàn)在,可以對(duì)拍攝圖像進(jìn)行不畸變處理。OpenCV提供了兩種方法來執(zhí)行此操作。但首先,可以使用cv2.getOptimalNewCameraMatrix()
基于自由縮放參數(shù)來優(yōu)化相機(jī)矩陣。如果縮放參數(shù)alpha = 0
,則返回具有最少不需要像素的未失真圖像。因此,它甚至可能會(huì)刪除圖像角落的一些像素。如果alpha = 1,則所有像素都保留有一些額外的黑色圖像。此函數(shù)還返回可用于裁剪結(jié)果的圖像ROI。
實(shí)例:
img = cv2.imread('right12.jpg') h, w, _ = img.shape newcameratx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))
1使用cv2.undistort
只需調(diào)用該函數(shù)并使用上面獲得的ROI裁剪結(jié)果即可。
# undistort dst = cv2.undistort(img, mtx, dist, None, newcameratx) # copy the image x, y, w, h = roi dst = dst[y:y+h, x:x+w] cv2.imshow('calibresult.png', dst) cv2.waitKey(0) cv2.destroyAllWindows()
2. 使用remapping
該方式有點(diǎn)困難。首先,找到從扭曲圖像到未扭曲圖像的映射函數(shù)。然后使用重映射函數(shù)。
盡管如此,兩種方法都給出相同的結(jié)果??吹较旅娴慕Y(jié)果:
# undistort mapx, mapy = cv2.initUndistortRectifyMap(mtx, dist, None, newcameratx, (w, h), 5) dst = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR) # crop the image x, y, w, h = roi dst = dst[y:y+h, x:x+w] cv2.imshow('calibresult.png', dst) cv2.waitKey(0) cv2.destroyAllWindows()
可以看到所有邊緣都是筆直的。 另外,可以使用NumPy中的寫入功能(np.savez,np.savetxt
等)存儲(chǔ)相機(jī)矩陣和失真系數(shù),以備將來使用。
重投影誤差|Re-projection Error
重投影誤差可以很好地估計(jì)找到的參數(shù)的精確程度。重投影誤差越接近零,表明發(fā)現(xiàn)的參數(shù)越準(zhǔn)
確。給定固有,失真,旋轉(zhuǎn)和平移矩陣,必須首先使用cv2.projectPoints()
將對(duì)象點(diǎn)轉(zhuǎn)換為
圖像點(diǎn)。然后,可以計(jì)算出通過變換得到的絕對(duì)值和拐角發(fā)現(xiàn)算法之間的絕對(duì)值范數(shù)。為了
找到平均誤差,計(jì)算為所有校準(zhǔn)圖像計(jì)算的誤差的算術(shù)平均值。
# re projection error mean_error = 0 for i in range(len(objpoints)): imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist) error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2)/len(imgpoints2) mean_error += error print( "total error: {}".format(mean_error/len(objpoints)) )
total error: 0.025365426097625716
保存相機(jī)矩陣和失真系數(shù)與加載 可以以json或者pickle等方式保存相機(jī)矩陣和失真系數(shù)
import pickle # save data cam_calib = {"cam_matrix": mtx, "dist_coeffs": dist} with open("cam_calib.p", "wb") as f: pickle.dump(cam_calib, f) # load previously save data with open(r"cam_calib.p", "rb") as f: data = pickle.load(f) mtx = data['cam_matrix'] dist = data['dist_coeffs']
附加資源
以上就是OpenCV圖像識(shí)別之相機(jī)校準(zhǔn)Camera Calibration學(xué)習(xí)的詳細(xì)內(nèi)容,更多關(guān)于OpenCV圖像識(shí)別相機(jī)校準(zhǔn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python利用xlwings實(shí)現(xiàn)考勤表制作
這篇文章主要為大家詳細(xì)介紹了Python如何利用xlwings庫(kù)操作excel實(shí)現(xiàn)考勤表的制作,文中的實(shí)現(xiàn)步驟講解詳細(xì),感興趣的可以嘗試一下2023-04-04使用Python操作Redis所有數(shù)據(jù)類型的方法
當(dāng)今互聯(lián)網(wǎng)時(shí)代,數(shù)據(jù)處理已經(jīng)成為了一個(gè)非常重要的任務(wù),而Redis作為一款高性能的NoSQL數(shù)據(jù)庫(kù),越來越受到了廣大開發(fā)者的喜愛,本篇博客將介紹如何使用Python操作Redis的所有類型,以及一些高級(jí)用法,需要的朋友可以參考下2023-11-11python實(shí)現(xiàn)網(wǎng)頁(yè)鏈接提取的方法分享
這篇文章主要介紹了python實(shí)現(xiàn)的網(wǎng)頁(yè)鏈接提取的方法,需要的朋友可以參考下2014-02-02Python字典fromkeys()方法使用代碼實(shí)例
這篇文章主要介紹了Python字典fromkeys()方法使用代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07關(guān)于Torch?torchvision?Python版本對(duì)應(yīng)關(guān)系說明
這篇文章主要介紹了關(guān)于Torch?torchvision?Python版本對(duì)應(yīng)關(guān)系說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05Pandas的數(shù)據(jù)過濾實(shí)現(xiàn)
這篇文章主要介紹了Pandas的數(shù)據(jù)過濾實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01Python unittest discover批量執(zhí)行代碼實(shí)例
這篇文章主要介紹了Python unittest discover批量執(zhí)行代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09