1. 程式人生 > 程式設計 >Python opencv相機標定實現原理及步驟詳解

Python opencv相機標定實現原理及步驟詳解

相機標定相機標定的目的

獲取攝像機的內參和外參矩陣(同時也會得到每一幅標定影象的選擇和平移矩陣),內參和外參係數可以對之後相機拍攝的影象就進行矯正,得到畸變相對很小的影象。

相機標定的輸入

標定影象上所有內角點的影象座標,標定板影象上所有內角點的空間三維座標(一般情況下假定影象位於Z=0平面上)。

相機標定的輸出

攝像機的內參、外參係數。

拍攝的物體都處於三維世界座標系中,而相機拍攝時鏡頭看到的是三維相機座標系,成像時三維相機座標系向二維影象座標系轉換。不同的鏡頭成像時的轉換矩陣不同,同時可能引入失真,標定的作用是近似地估算出轉換矩陣和失真係數。為了估算,需要知道若干點的三維世界座標系中的座標和二維影象座標系中的座標,也就是拍攝棋盤的意義。

相機成像

相機的成像原理:小孔成像

Python opencv相機標定實現原理及步驟詳解

相機的內參相機的外參

在實際由於設計工藝問題、相機安裝環境或物體擺放位置等影響,會照成成像與實際影象不一樣的現象。

由於設計工藝照成的影響是無法改變的事實,所以這將是相機的內參;

由環境或安裝方式照成的影響是可以改變的,這就是相機的外參。

張正友標定相機原理

    1.求得相機內參數:

      用於標定的棋盤格是特製的,其角點座標已知。標定棋盤格是三維場景中的一個平面∏,棋盤格在成像平面為π(知道了∏與π的對應點座標之後,可求解兩個平面1對應的單應矩陣H)。

根據相機成像模型,P為標定的棋盤座標,p為其畫素點座標。則Python opencv相機標定實現原理及步驟詳解,通過對應的點座標求解H後,可用於求K,R,T。

    2.設棋盤格所在平面為世界座標系上XOY平面,則棋盤格上任一角點P世界座標系為(X,Y,0)。

Python opencv相機標定實現原理及步驟詳解

    3、內參約束條件

      Python opencv相機標定實現原理及步驟詳解

      Python opencv相機標定實現原理及步驟詳解

Python opencv相機標定實現原理及步驟詳解

Python opencv相機標定實現原理及步驟詳解

實驗步驟列印棋盤圖片(網上找一張)

Python opencv相機標定實現原理及步驟詳解

將打印出的紙固定放到一個平面上,使用同一相機從不同的位置,不同的角度,拍攝標定板的多張照片(我拍了15張)手機型號是華為mate9

Python opencv相機標定實現原理及步驟詳解

提取標定板的世界座標

標定板的大小是標定板在水平和豎直方向上內角點的個數。內角點指的是,標定板上不挨著邊界的角點。

我列印的是6x9的標定板。

Python opencv相機標定實現原理及步驟詳解

標定相機

Python opencv相機標定實現原理及步驟詳解

Python opencv相機標定實現原理及步驟詳解

Python opencv相機標定實現原理及步驟詳解

mtx -->內參數矩陣

dist --> 畸變係數

rvecs --> 旋轉向量

tvecs --> 平移向量

我們可以通過反投影誤差來評估結果的好壞,越接近0,說明結果越理想。

通過之前計算的內參數矩陣、畸變係數、旋轉矩陣和平移向量,使用cv2.projectPoints()計算三維點到二維影象的投影,然後計算反投影得到的點與影象上檢測到的點的誤差,最後計算一個對於所有標定影象的平均誤差即反投影誤差

我的棋盤打印出來有些不平整,可能是列印的紙張沒有放正,導致有些地方翹著,效果不是很好,誤差值有些大了,把紙張貼平整應該會好很多。而且我可能拍照的角度變化不是太大,可以試著把拍照的角度更加差異些,結果會更明顯。

import cv2
import numpy as np
import glob
# 設定尋找亞畫素角點的引數,採用的停止準則是最大迴圈次數30和最大誤差容限0.001
criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS,30,0.001)
# 獲取標定板角點的位置
objp = np.zeros((6 * 9,3),np.float32)
objp[:,:2] = np.mgrid[0:9,0:6].T.reshape(-1,2) # 將世界座標系建在標定板上,所有點的Z座標全部為0,所以只需要賦值x和y
obj_points = [] # 儲存3D點
img_points = [] # 儲存2D點
images = glob.glob("E:/test_pic/qipan/*.jpg")
for fname in images:
  img = cv2.imread(fname)
  cv2.imshow('img',img)
  gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
  size = gray.shape[::-1]
  ret,corners = cv2.findChessboardCorners(gray,(6,9),None)
  print(ret)
  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,(8,6),ret) # 記住,OpenCV的繪製函式一般無返回值
    cv2.imshow('img',img)
    cv2.waitKey(2000)
print(len(img_points))
cv2.destroyAllWindows()
# 標定
ret,mtx,dist,rvecs,tvecs = cv2.calibrateCamera(obj_points,img_points,size,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("-----------------------------------------------------")

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。