日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

相机校准

發布時間:2025/3/15 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 相机校准 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

學習內容:

  • 由相機引起的失真類型,
  • 如何找到相機的固有和非固有特性
  • 如何根據這些特性使圖像不失真。

一些針孔相機會給圖像帶來明顯的失真。兩種主要的變形是徑向變形和切向變形。 徑向變形會導致直線出現彎曲。

距圖像中心越遠,徑向畸變越大。例如,下面顯示一個圖像,其中棋盤的兩個邊緣用紅線標記。但是,您會看到棋盤的邊框不是直線,并且與紅線不匹配。所有預期的直線都凸出。

徑向變形可以表示成如下:

xdistorted=x(1+k1r2+k2r4+k3r6)ydistorted=y(1+k1r2+k2r4+k3r6)x_{distorted} = x( 1 + k_1 r^2 + k_2 r^4 + k_3 r^6) \ y_{distorted} = y( 1 + k_1 r^2 + k_2 r^4 + k_3 r^6) xdistorted?=x(1+k1?r2+k2?r4+k3?r6)?ydistorted?=y(1+k1?r2+k2?r4+k3?r6)

同樣,由于攝像鏡頭未完全平行于成像平面對齊,因此會發生切向畸變。因此,圖像中的某些區域看起來可能比預期的要近。切向畸變的量可以表示為:

xdistorted=x+[2p1xy+p2(r2+2x2)]ydistorted=y+[p1(r2+2y2)+2p2xy]x_{distorted} = x + [ 2p_1xy + p_2(r^2+2x^2)] \ y_{distorted} = y + [ p_1(r^2+ 2y^2)+ 2p_2xy] xdistorted?=x+[2p1?xy+p2?(r2+2x2)]?ydistorted?=y+[p1?(r2+2y2)+2p2?xy]

簡而言之,我們需要找到五個參數,稱為失真系數,公式如下:

Distortioncoefficients=(k1k2p1p2k3)Distortion \; coefficients=(k_1 \hspace{10pt} k_2 \hspace{10pt} p_1 \hspace{10pt} p_2 \hspace{10pt} k_3) Distortioncoefficients=(k1?k2?p1?p2?k3?)

除此之外,我們還需要其他一些信息,例如相機的內在和外在參數。內部參數特定于攝像機。它們包括諸如焦距(fx,fy)(f_x,f_y)(fx?fy?)和光學中心(cx,cy)(c_x,c_y)(cx?,cy?)之類的信息。焦距和光學中心可用于創建相機矩陣,該相機矩陣可用于消除由于特定相機鏡頭而引起的畸變。相機矩陣對于特定相機而言是唯一的,因此一旦計算出,就可以在同一相機拍攝的其他圖像上重復使用。它表示為3x3矩陣:

cameramatrix=[fx0cx0fycy001]camera \; matrix = \left [ \begin{matrix} f_x & 0 & c_x \ 0 & f_y & c_y \ 0 & 0 & 1 \end{matrix} \right ] cameramatrix=[fx??0?cx??0?fy??cy??0?0?1?]

外在參數對應于旋轉和平移矢量,其將3D點的坐標平移為坐標系。

對于立體聲應用,首先需要糾正這些失真。要找到這些參數,我們必須提供一些定義良好的圖案的示例圖像(例如國際象棋棋盤)。我們找到一些已經知道其相對位置的特定點(例如棋盤上的四角)。我們知道現實世界空間中這些點的坐標,也知道圖像中的坐標,因此我們可以求解失真系數。為了獲得更好的結果,我們至少需要10個測試模式。

代碼

如上所述,相機校準至少需要10個測試圖案。OpenCV附帶了一些國際象棋棋盤的圖像(請參見samples / data / left01.jpg – left14.jpg),因此我們將利用這些圖像??紤]棋盤的圖像。相機校準所需的重要輸入數據是3D現實世界點集以及圖像中這些點的相應2D坐標??梢詮膱D像中輕松找到2D圖像點。(這些圖像點是國際象棋棋盤中兩個黑色正方形相互接觸的位置)

真實世界中的3D點如何處理?這些圖像是從靜態相機拍攝的,而國際象棋棋盤放置在不同的位置和方向。因此,我們需要知道(X,Y,Z)(X,Y,Z)(X,Y,Z)值。但是為簡單起見,我們可以說棋盤在XY平面上保持靜止(因此Z始終為0),并且照相機也相應地移動了。這種考慮有助于我們僅找到X,Y值?,F在對于X,Y值,我們可以簡單地將點傳遞為(0,0),(1,0),(2,0),…,這表示點的位置。在這種情況下,我們得到的結果將是棋盤正方形的大小比例。但是,如果我們知道正方形大小(例如30毫米),則可以將值傳遞為(0,0),(30,0),(60,0),…。因此,我們得到的結果以毫米為單位。(在這種情況下,我們不知道正方形的大小,因為我們沒有拍攝那些圖像,因此我們以正方形的大小進行傳遞)。

3D點稱為對象點,而2D圖像點稱為圖像點。
完整代碼示例:

import cv2 import numpy as np import glob# 設置尋找亞像素角點的參數,采用的停止準則是最大循環次數30和最大誤差容限0.001 criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001) w=9 h=5 # 準備對象點,如(0,0,0),(1,0,0)。。。。(6,5,0) # 獲取標定板角點的位置 objp = np.zeros((w * h, 3), np.float32) objp[:, :2] = np.mgrid[0:w, 0:h].T.reshape(-1, 2) # 將世界坐標系建在標定板上,所有點的Z坐標全部為0,所以只需要賦值x和y#用于存儲所有圖像的對象點和圖像點的數組 obj_points = [] # 存儲3D點 img_points = [] # 存儲2D點images = glob.glob('./image_test1/camera_calibration/*.jpg') i=0 for fname in images:img = cv2.imread(fname)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)size = gray.shape[::-1]ret, corners = cv2.findChessboardCorners(gray, (w,h), None)#print(corners)if ret:#添加對象點obj_points.append(objp)corners2 = cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria) # 在原角點的基礎上尋找亞像素角點,提高精度#print(corners2)if corners2:img_points.append(corners2)else:img_points.append(corners)#繪制并顯示拐角cv2.drawChessboardCorners(img, (w,h), corners, ret) # 記住,OpenCV的繪制函數一般無返回值i+=1cv2.imwrite('conimg'+str(i)+'.jpg', img)cv2.waitKey(1500)print(len(img_points)) cv2.destroyAllWindows()# 標定,使用此函數可返回攝像機矩陣,畸變系數,旋轉和變換向量 ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, gray.shape[::-1], None, None)print("ret:", ret) print("mtx:\n", mtx) # 內參數矩陣 print("dist:\n", dist) # 畸變系數 distortion cofficients = (k_1,k_2,p_1,p_2,k_3) print("rvecs:\n", rvecs) # 旋轉向量 # 外參數 print("tvecs:\n", tvecs ) # 平移向量 # 外參數print("-----------------------------------------------------")img = cv2.imread(images[2]) h, w = img.shape[:2] #畸變校正,如果縮放系數alpha=0,返回的非畸變圖像會帶有少量的不想要的像素,甚至可能在圖像角點去除一些像素 #如果alpha=1,所有的像素都會被返回,還有一些黑圖像。它還會返回一個roi(元組)圖像,我們可以用來對結果進行裁剪 newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))#顯示更大范圍的圖片(正常重映射之后會刪掉一部分圖像) print (newcameramtx) print("------------------使用undistort函數-------------------") #去除畸變 dst = cv2.undistort(img,mtx,dist,None,newcameramtx) x,y,w,h = roi dst1 = dst[y:y+h,x:x+w] cv2.imwrite('calibresult3.jpg', dst1) print ("dst的大小為:", dst1.shape)

以下是其步驟:
首先
**要在國際象棋棋盤中查找圖案,我們可以使用函數cv.findChessboardCorners()。**我們還需要傳遞所需的圖案,例如8x8網格,5x5網格等。在此示例中,我們使用7x6網格。(通常,棋盤有8x8的正方形和7x7的內部角)。它返回角點和retval,如果獲得圖案,則為True。這些角將按順序放置(從左到右,從上到下)

此功能可能無法在所有圖像中找到所需的圖案。因此,一個不錯的選擇是編寫代碼,使它啟動相機并檢查每幀所需的圖案。獲得圖案后,找到角并將其存儲在列表中。另外,在閱讀下一幀之前請提供一些時間間隔,以便我們可以在不同方向上調整棋盤。繼續此過程,直到獲得所需數量的良好圖案為止。即使在此處提供的示例中,我們也不確定給出的14張圖像中有多少張是好的。

因此,我們必須閱讀所有圖像并僅拍攝好圖像。 除了棋盤,我們還可以使用圓形網格。 在這種情況下,我們必須使用函數cv.findCirclesGrid()來找到模式。 較少的圖像足以使用圓形網格執行相機校準。
其次,
一旦找到拐角,就可以使用cv.cornerSubPix()來提高其精度。我們還可以使用cv.drawChessboardCorners()繪制圖案。所有這些步驟都包含在以下代碼中:

import numpy as np import cv2 as cv import glob # 終止條件 criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001) # 準備對象點, 如 (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) # 用于存儲所有圖像的對象點和圖像點的數組。 objpoints = [] # 真實世界中的3d點 imgpoints = [] # 圖像中的2d點 images = glob.glob('*.jpg') for fname in images:img = cv.imread(fname)gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)# 找到棋盤角落ret, corners = cv.findChessboardCorners(gray, (7,6), None)# 如果找到,添加對象點,圖像點(細化之后)if ret == True:objpoints.append(objp)corners2 = cv.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)imgpoints.append(corners)# 繪制并顯示拐角cv.drawChessboardCorners(img, (7,6), corners2, ret)cv.imshow('img', img)cv.waitKey(500) cv.destroyAllWindows()

運行結果:

校準

現在我們有了目標點和圖像點,現在可以進行校準了。我們可以使用函數cv.calibrateCamera()返回相機矩陣,失真系數,旋轉和平移矢量等。

ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)

現在,我們可以拍攝圖像并對其進行扭曲。OpenCV提供了兩種方法來執行此操作。但是,首先,我們可以使用**cv.getOptimalNewCameraMatrix()基于自由縮放參數來優化相機矩陣。**如果縮放參數alpha = 0,則返回具有最少不需要像素的未失真圖像。因此,它甚至可能會刪除圖像角落的一些像素。如果alpha = 1,則所有像素都保留有一些額外的黑色圖像。此函數還返回可用于裁剪結果的圖像ROI。

因此,我們拍攝一張新圖像(在本例中為left12.jpg。這是本章的第一張圖像)
img = cv.imread(‘left12.jpg’)
h, w = img.shape[:2]
newcameramtx, roi = cv.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h))
以下是求解結果的幾種方式:
1.使用cv.undistort(),調用該函數并使用上面獲得的ROI裁剪結果。

dst = cv.undistort(img, mtx, dist, None, newcameramtx)
剪裁圖像
x, y, w, h = roi
dst = dst[y:y+h, x:x+w]
cv.imwrite(‘calibresult.png’, dst)
2. 使用remapping

首先,找到從扭曲圖像到未扭曲圖像的映射函數。然后使用重映射功能。
mapx, mapy = cv.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w,h), 5)
dst = cv.remap(img, mapx, mapy, cv.INTER_LINEAR)

x, y, w, h = roi # 裁剪圖像
dst = dst[y:y+h, x:x+w]
cv.imwrite(‘calibresult.png’, dst)
盡管如此,兩種方法都給出相同的結果??吹较旅娴慕Y果:

您可以看到所有邊緣都是筆直的。 現在,您可以使用NumPy中的寫入功能(np.savez,np.savetxt等)存儲相機矩陣和失真系數,以備將來使用。

重投影誤差

重投影誤差可以很好地估計找到的參數的精確程度。重投影誤差越接近零,我們發現的參數越準確。給定固有,失真,旋轉和平移矩陣,我們必須首先使用**cv.projectPoints()將對象點轉換為圖像點。**然后,我們可以計算出通過變換得到的絕對值和拐角發現算法之間的絕對值范數。為了找到平均誤差,我們計算為所有校準圖像計算的誤差的算術平均值。

mean_error = 0
for i in xrange(len(objpoints)):
imgpoints2, _ = cv.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
error = cv.norm(imgpoints[i], imgpoints2, cv.NORM_L2)/len(imgpoints2)
mean_error += error
print( “total error: {}”.format(mean_error/len(objpoints)) )

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的相机校准的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。