https://blog.csdn.net/u010128736/article/details/52875137
https://blog.csdn.net/h532600610/article/details/51800488
python 角點檢測+相機標定+去畸變+重投影誤差計算:
#coding:utf-8 import cv2 import numpy as np import glob # 找棋盤格角點 # 閾值 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) #棋盤格模板規格 w = 9 h = 6 # 世界坐標系中的棋盤格點,例如(0,0,0), (1,0,0), (2,0,0) ....,(8,5,0),去掉Z坐標,記為二維矩陣 objp = np.zeros((w*h,3), np.float32) objp[:,:2] = np.mgrid[0:w,0:h].T.reshape(-1,2) # 儲存棋盤格角點的世界坐標和圖像坐標對 objpoints = [] # 在世界坐標系中的三維點 imgpoints = [] # 在圖像平面的二維點 images = glob.glob('calib/*.png') for fname in images: img = cv2.imread(fname) gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 找到棋盤格角點 ret, corners = cv2.findChessboardCorners(gray, (w,h),None) # 如果找到足夠點對,將其存儲起來 if ret == True: cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria) objpoints.append(objp) imgpoints.append(corners) # 將角點在圖像上顯示 cv2.drawChessboardCorners(img, (w,h), corners, ret) cv2.imshow('findCorners',img) cv2.waitKey(1) cv2.destroyAllWindows() # 標定 ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) # 去畸變 img2 = cv2.imread('calib/00169.png') h, w = img2.shape[:2] newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),0,(w,h)) # 自由比例參數 dst = cv2.undistort(img2, mtx, dist, None, newcameramtx) # 根據前面ROI區域裁剪圖片 #x,y,w,h = roi #dst = dst[y:y+h, x:x+w] cv2.imwrite('calibresult.png',dst) # 反投影誤差 total_error = 0 for i in xrange(len(objpoints)): imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist) error = cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2) total_error += error print "total error: ", total_error/len(objpoints)
標定 cv2.calibrateCamera函數文檔:https://docs.opencv.org/2.4.1/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html
c++ 角點檢測+角點繪制:
#include <iostream> #include <cv.h> #include <cxcore.h> #include <highgui.h> using namespace std; int main( ) { cout<<"Draw Chess OpenCV!"<<endl; char* filename="..//image5.jpg"; char* filename2="..//5.jpg"; IplImage* imgRGB = cvLoadImage(filename); IplImage* imgGrey = cvLoadImage(filename,CV_LOAD_IMAGE_GRAYSCALE); if (imgGrey==NULL){//image validation cout<< "No valid image input."<<endl; char c=getchar(); return 1; } //-------find chessboard corners-------------- int corner_row=7;//interior number of row corners.(this can be countered by fingers.) int corner_col=7;//interior number of column corners. int corner_n=corner_row*corner_col; CvSize pattern_size=cvSize(corner_row,corner_col); // CvPoint2D32f* corners=new CvPoint2D32f[corner_n]; CvPoint2D32f corners[49]; int corner_count; int found=cvFindChessboardCorners(//returning non-zero means sucess. imgGrey,// 8-bit single channel greyscale image. pattern_size,//how many INTERIOR corners in each row and column of the chessboard. corners,//an array where the corner locations can be recorded. &corner_count,// optional, if non-NULL, its a point to an integer where the nuber of corners found can be recorded. // CV_CALIB_CB_ADAPTIVE_THRESH|CV_CALIB_CB_FILTER_QUADS// check page 382-383. 0 ); cout<<"corner_count = "<<corner_count; //-------Draw the corner pattern------- cvDrawChessboardCorners( imgRGB, pattern_size, corners, corner_count, found ); cvSaveImage(filename2,imgRGB); //to summary a bit of findings. cout<<"found="<<found<<endl; cout<<"x="<<corners[1].x; cout<<",y="<<corners[1].y<<endl; cvNamedWindow("Find and Draw ChessBoard", 0 ); cvShowImage( "Find and Draw ChessBoard", imgRGB ); cvWaitKey(0); cvReleaseImage(&imgGrey); cvReleaseImage(&imgRGB); cvDestroyWindow("Find and Draw ChessBoard"); return 0; }
注意事項:
- pattern_size參數傳遞內點數,8*8的棋盤只有7*7內點。
- 圖像選取應注意減少干擾,例如光照與背景等。
- Corners中的角點坐標順序排列規律不一定是以行從左上到右下。使用坐標計算映射關系時應提高警惕,對坐標進行重新排列。
關鍵函數參數說明:
int cvFindChessboardCorners( const void* image, CvSize pattern_size, CvPoint2D32f* corners, int* corner_count=NULL, int flags=CV_CALIB_CB_ADAPTIVE_THRESH );
Image:
輸入的棋盤圖,必須是8位的灰度或者彩色圖像。
pattern_size:
棋盤圖中每行和每列角點的個數。
Corners:
檢測到的角點
corner_count:
輸出,角點的個數。如果不是NULL,函數將檢測到的角點的個數存儲於此變量。
Flags:
各種操作標志,可以是0或者下面值的組合:
CV_CALIB_CB_ADAPTIVE_THRESH -使用自適應閾值(通過平均圖像亮度計算得到)將圖像轉換為黑白圖,而不是一個固定的閾值。
CV_CALIB_CB_NORMALIZE_IMAGE -在利用固定閾值或者自適應的閾值進行二值化之前,先使用cvNormalizeHist來均衡化圖像亮度。
CV_CALIB_CB_FILTER_QUADS -使用其他的准則(如輪廓面積,周長,方形形狀)來去除在輪廓檢測階段檢測到的錯誤方塊。