轉載:https://blog.csdn.net/dcrmg/article/details/52939318

張正友相機標定Opencv實現以及標定流程&&標定結果評價&&圖像矯正流程解析(附標定程序和棋盤圖)

使用Opencv實現張正友法相機標定之前,有幾個問題事先要確認一下,那就是相機為什么需要標定,標定需要的輸入和輸出分別是哪些?


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

相機標定的輸入:標定圖像上所有內角點的圖像坐標,標定板圖像上所有內角點的空間三維坐標(一般情況下假定圖像位于Z=0平面上)。

相機標定的輸出:攝像機的內參、外參系數。


這三個基礎的問題就決定了使用Opencv實現張正友法標定相機的標定流程、標定結果評價以及使用標定結果矯正原始圖像的完整流程:


1. 準備標定圖片

2. 對每一張標定圖片,提取角點信息

3. 對每一張標定圖片,進一步提取亞像素角點信息

4. 在棋盤標定圖上繪制找到的內角點(非必須,僅為了顯示)

5. 相機標定

6. 對標定結果進行評價

7. 查看標定效果——利用標定結果對棋盤圖進行矯正


1. 準備標定圖片


標定圖片需要使用標定板在不同位置、不同角度、不同姿態下拍攝,最少需要3張,以10~20張為宜。標定板需要是黑白相間的矩形構成的棋盤圖,制作精度要求較高,如下圖所示:





2.對每一張標定圖片,提取角點信息


需要使用findChessboardCorners函數提取角點,這里的角點專指的是標定板上的內角點,這些角點與標定板的邊緣不接觸。

?findChessboardCorners函數原型:

[cpp] view plaincopy
  1. //!?finds?checkerboard?pattern?of?the?specified?size?in?the?image??
  2. CV_EXPORTS_W?bool?findChessboardCorners(?InputArray?image,?Size?patternSize,??
  3. ?????????????????????????????????????????OutputArray?corners,??
  4. ?????????????????????????????????????????int?flags=CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE?);??


第一個參數Image,傳入拍攝的棋盤圖Mat圖像,必須是8位的灰度或者彩色圖像;

第二個參數patternSize,每個棋盤圖上內角點的行列數,一般情況下,行列數不要相同,便于后續標定程序識別標定板的方向;

第三個參數corners,用于存儲檢測到的內角點圖像坐標位置,一般用元素是Point2f的向量來表示:vector<Point2f> image_points_buf;

第四個參數flage:用于定義棋盤圖上內角點查找的不同處理方式,有默認值。



3. 對每一張標定圖片,進一步提取亞像素角點信息


為了提高標定精度,需要在初步提取的角點信息上進一步提取亞像素信息,降低相機標定偏差,常用的方法是cornerSubPix,另一個方法是使用find4QuadCornerSubpix函數,這個方法是專門用來獲取棋盤圖上內角點的精確位置的,或許在相機標定的這個特殊場合下它的檢測精度會比cornerSubPix更高?

cornerSubPix函數原型:

[cpp] view plaincopy
  1. //!?adjusts?the?corner?locations?with?sub-pixel?accuracy?to?maximize?the?certain?cornerness?criteria??
  2. CV_EXPORTS_W?void?cornerSubPix(?InputArray?image,?InputOutputArray?corners,??
  3. ????????????????????????????????Size?winSize,?Size?zeroZone,??
  4. ????????????????????????????????TermCriteria?criteria?);??

第一個參數image,輸入的Mat矩陣,最好是8位灰度圖像,檢測效率更高;

第二個參數corners,初始的角點坐標向量,同時作為亞像素坐標位置的輸出,所以需要是浮點型數據,一般用元素是Pointf2f/Point2d的向量來表示:vector<Point2f/Point2d> iamgePointsBuf;

第三個參數winSize,大小為搜索窗口的一半;

第四個參數zeroZone,死區的一半尺寸,死區為不對搜索區的中央位置做求和運算的區域。它是用來避免自相關矩陣出現某些可能的奇異性。當值為(-1,-1)時表示沒有死區;

第五個參數criteria,定義求角點的迭代過程的終止條件,可以為迭代次數和角點精度兩者的組合;

find4QuadCornerSubpix函數原型:

[cpp] view plaincopy
  1. //!?finds?subpixel-accurate?positions?of?the?chessboard?corners??
  2. CV_EXPORTS?bool?find4QuadCornerSubpix(InputArray?img,?InputOutputArray?corners,?Size?region_size);??

第一個參數img,輸入的Mat矩陣,最好是8位灰度圖像,檢測效率更高;

第二個參數corners,初始的角點坐標向量,同時作為亞像素坐標位置的輸出,所以需要是浮點型數據,一般用元素是Pointf2f/Point2d的向量來表示:vector<Point2f/Point2d> iamgePointsBuf;

第三個參數region_size,角點搜索窗口的尺寸;

在其中一個標定的棋盤圖上分別運行cornerSubPix和find4QuadCornerSubpix尋找亞像素角點,兩者定位到的亞像素角點坐標分別為:


? ?cornerSubPix: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??find4QuadCornerSubpix:

? ? ? ? ? ? ? ? ? ? ? ?


雖然有一定差距,但偏差基本都控制在0.5個像素之內。



4. 在棋盤標定圖上繪制找到的內角點(非必須,僅為了顯示)



drawChessboardCorners函數用于繪制被成功標定的角點,函數原型:


[cpp] view plaincopy
  1. //!?draws?the?checkerboard?pattern?(found?or?partly?found)?in?the?image??
  2. CV_EXPORTS_W?void?drawChessboardCorners(?InputOutputArray?image,?Size?patternSize,??
  3. ?????????????????????????????????????????InputArray?corners,?bool?patternWasFound?);??

第一個參數image,8位灰度或者彩色圖像;

第二個參數patternSize,每張標定棋盤上內角點的行列數;

第三個參數corners,初始的角點坐標向量,同時作為亞像素坐標位置的輸出,所以需要是浮點型數據,一般用元素是Pointf2f/Point2d的向量來表示:vector<Point2f/Point2d> iamgePointsBuf;

第四個參數patternWasFound,標志位,用來指示定義的棋盤內角點是否被完整的探測到,true表示別完整的探測到,函數會用直線依次連接所有的內角點,作為一個整體,false表示有未被探測到的內角點,這時候函數會以(紅色)圓圈標記處檢測到的內角點;

以下是drawChessboardCorners函數中第四個參數patternWasFound設置為true和false時內角點的繪制效果:

patternWasFound=ture時,依次連接各個內角點:




patternWasFound=false時,以(紅色)圓圈標記處角點位置:




5. 相機標定



獲取到棋盤標定圖的內角點圖像坐標之后,就可以使用calibrateCamera函數進行標定,計算相機內參和外參系數,

calibrateCamera函數原型:

[cpp] view plaincopy
  1. //!?finds?intrinsic?and?extrinsic?camera?parameters?from?several?fews?of?a?known?calibration?pattern.??
  2. CV_EXPORTS_W?double?calibrateCamera(?InputArrayOfArrays?objectPoints,??
  3. ?????????????????????????????????????InputArrayOfArrays?imagePoints,??
  4. ?????????????????????????????????????Size?imageSize,??
  5. ?????????????????????????????????????CV_OUT?InputOutputArray?cameraMatrix,??
  6. ?????????????????????????????????????CV_OUT?InputOutputArray?distCoeffs,??
  7. ?????????????????????????????????????OutputArrayOfArrays?rvecs,?OutputArrayOfArrays?tvecs,??
  8. ?????????????????????????????????????int?flags=0,?TermCriteria?criteria?=?TermCriteria(??
  9. ?????????????????????????????????????????TermCriteria::COUNT+TermCriteria::EPS,?30,?DBL_EPSILON)?);??

第一個參數objectPoints,為世界坐標系中的三維點。在使用時,應該輸入一個三維坐標點的向量的向量,即vector<vector<Point3f>> object_points。需要依據棋盤上單個黑白矩陣的大小,計算出(初始化)每一個內角點的世界坐標。

第二個參數imagePoints,為每一個內角點對應的圖像坐標點。和objectPoints一樣,應該輸入vector<vector<Point2f>> image_points_seq形式的變量;

第三個參數imageSize,為圖像的像素尺寸大小,在計算相機的內參和畸變矩陣時需要使用到該參數;

第四個參數cameraMatrix為相機的內參矩陣。輸入一個Mat cameraMatrix即可,如Mat cameraMatrix=Mat(3,3,CV_32FC1,Scalar::all(0));

第五個參數distCoeffs為畸變矩陣。輸入一個Mat distCoeffs=Mat(1,5,CV_32FC1,Scalar::all(0))即可;

第六個參數rvecs為旋轉向量;應該輸入一個Mat類型的vector,即vector<Mat>rvecs;

第七個參數tvecs為位移向量,和rvecs一樣,應該為vector<Mat> tvecs;

第八個參數flags為標定時所采用的算法。有如下幾個參數:

CV_CALIB_USE_INTRINSIC_GUESS:使用該參數時,在cameraMatrix矩陣中應該有fx,fy,u0,v0的估計值。否則的話,將初始化(u0,v0)圖像的中心點,使用最小二乘估算出fx,fy。?
CV_CALIB_FIX_PRINCIPAL_POINT:在進行優化時會固定光軸點。當CV_CALIB_USE_INTRINSIC_GUESS參數被設置,光軸點將保持在中心或者某個輸入的值。?
CV_CALIB_FIX_ASPECT_RATIO:固定fx/fy的比值,只將fy作為可變量,進行優化計算。當CV_CALIB_USE_INTRINSIC_GUESS沒有被設置,fx和fy將會被忽略。只有fx/fy的比值在計算中會被用到。?
CV_CALIB_ZERO_TANGENT_DIST:設定切向畸變參數(p1,p2)為零。?
CV_CALIB_FIX_K1,…,CV_CALIB_FIX_K6:對應的徑向畸變在優化中保持不變。?
CV_CALIB_RATIONAL_MODEL:計算k4,k5,k6三個畸變參數。如果沒有設置,則只計算其它5個畸變參數。

第九個參數criteria是最優迭代終止條件設定。

在使用該函數進行標定運算之前,需要對棋盤上每一個內角點的空間坐標系的位置坐標進行初始化,標定的結果是生成相機的內參矩陣cameraMatrix、相機的5個畸變系數distCoeffs,另外每張圖像都會生成屬于自己的平移向量和旋轉向量。



6. 對標定結果進行評價



對標定結果進行評價的方法是通過得到的攝像機內外參數,對空間的三維點進行重新投影計算,得到空間三維點在圖像上新的投影點的坐標,計算投影坐標和亞像素角點坐標之間的偏差,偏差越小,標定結果越好。

對空間三維坐標點進行反向投影的函數是projectPoints,函數原型是:

[cpp] view plaincopy
  1. //!?projects?points?from?the?model?coordinate?space?to?the?image?coordinates.?Also?computes?derivatives?of?the?image?coordinates?w.r.t?the?intrinsic?and?extrinsic?camera?parameters??
  2. CV_EXPORTS_W?void?projectPoints(?InputArray?objectPoints,??
  3. ?????????????????????????????????InputArray?rvec,?InputArray?tvec,??
  4. ?????????????????????????????????InputArray?cameraMatrix,?InputArray?distCoeffs,??
  5. ?????????????????????????????????OutputArray?imagePoints,??
  6. ?????????????????????????????????OutputArray?jacobian=noArray(),??
  7. ?????????????????????????????????double?aspectRatio=0?);??


第一個參數objectPoints,為相機坐標系中的三維點坐標;

第二個參數rvec為旋轉向量,每一張圖像都有自己的選擇向量;

第三個參數tvec為位移向量,每一張圖像都有自己的平移向量;

第四個參數cameraMatrix為求得的相機的內參數矩陣;

第五個參數distCoeffs為相機的畸變矩陣;

第六個參數iamgePoints為每一個內角點對應的圖像上的坐標點;

第七個參數jacobian是雅可比行列式;

第八個參數aspectRatio是跟相機傳感器的感光單元有關的可選參數,如果設置為非0,則函數默認感光單元的dx/dy是固定的,會依此對雅可比矩陣進行調整;

下邊顯示了某一張標定圖片上的亞像素角點坐標和根據標定結果把空間三維坐標點映射回圖像坐標點的對比:


find4QuadCornerSubpix查找到的亞像素點坐標: ? ? ? ? ? ? ? ? ? ? ? ? ??projectPoints映射的坐標:

? ? ? ? ? ? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????


以下是每一幅圖像上24個內角點的平均誤差統計數據:




7. 查看標定效果——利用標定結果對棋盤圖進行矯正



利用求得的相機的內參和外參數據,可以對圖像進行畸變的矯正,這里有兩種方法可以達到矯正的目的,分別說明一下。

方法一:使用initUndistortRectifyMap和remap兩個函數配合實現。

initUndistortRectifyMap用來計算畸變映射,remap把求得的映射應用到圖像上。

initUndistortRectifyMap的函數原型:

[cpp] view plaincopy
  1. //!?initializes?maps?for?cv::remap()?to?correct?lens?distortion?and?optionally?rectify?the?image??
  2. CV_EXPORTS_W?void?initUndistortRectifyMap(?InputArray?cameraMatrix,?InputArray?distCoeffs,??
  3. ???????????????????????????InputArray?R,?InputArray?newCameraMatrix,??
  4. ???????????????????????????Size?size,?int?m1type,?OutputArray?map1,?OutputArray?map2?);??

第一個參數cameraMatrix為之前求得的相機的內參矩陣;

第二個參數distCoeffs為之前求得的相機畸變矩陣;

第三個參數R,可選的輸入,是第一和第二相機坐標之間的旋轉矩陣;

第四個參數newCameraMatrix,輸入的校正后的3X3攝像機矩陣;

第五個參數size,攝像機采集的無失真的圖像尺寸;

第六個參數m1type,定義map1的數據類型,可以是CV_32FC1或者CV_16SC2;

第七個參數map1和第八個參數map2,輸出的X/Y坐標重映射參數;


remap函數原型:

[cpp] view plaincopy
  1. //!?warps?the?image?using?the?precomputed?maps.?The?maps?are?stored?in?either?floating-point?or?integer?fixed-point?format??
  2. CV_EXPORTS_W?void?remap(?InputArray?src,?OutputArray?dst,??
  3. ?????????????????????????InputArray?map1,?InputArray?map2,??
  4. ?????????????????????????int?interpolation,?int?borderMode=BORDER_CONSTANT,??
  5. ?????????????????????????const?Scalar&?borderValue=Scalar());??

第一個參數src,輸入參數,代表畸變的原始圖像;

第二個參數dst,矯正后的輸出圖像,跟輸入圖像具有相同的類型和大小;

第三個參數map1和第四個參數map2,X坐標和Y坐標的映射;

第五個參數interpolation,定義圖像的插值方式;

第六個參數borderMode,定義邊界填充方式;


方法二:使用undistort函數實現

undistort函數原型:

[cpp] view plaincopy
  1. //!?corrects?lens?distortion?for?the?given?camera?matrix?and?distortion?coefficients??
  2. CV_EXPORTS_W?void?undistort(?InputArray?src,?OutputArray?dst,??
  3. ?????????????????????????????InputArray?cameraMatrix,??
  4. ?????????????????????????????InputArray?distCoeffs,??
  5. ?????????????????????????????InputArray?newCameraMatrix=noArray()?);??

第一個參數src,輸入參數,代表畸變的原始圖像;

第二個參數dst,矯正后的輸出圖像,跟輸入圖像具有相同的類型和大小;

第三個參數cameraMatrix為之前求得的相機的內參矩陣;

第四個參數distCoeffs為之前求得的相機畸變矩陣;

第五個參數newCameraMatrix,默認跟cameraMatrix保持一致;

方法一相比方法二執行效率更高一些,推薦使用。


以下是使用某一張標定圖使用方法一和方法二進行矯正的效果圖對比。

原始標定圖像:



方法一,使用initUndistortRectifyMap和remap實現矯正效果:



方法二,使用undistort函數實現矯正效果:



兩個方法從矯正效果上看,結果是一致的。


以下是完整的工程代碼:


[cpp] view plaincopy
  1. #include?"opencv2/core/core.hpp"??
  2. #include?"opencv2/imgproc/imgproc.hpp"??
  3. #include?"opencv2/calib3d/calib3d.hpp"??
  4. #include?"opencv2/highgui/highgui.hpp"??
  5. #include?<iostream>??
  6. #include?<fstream>??
  7. ??
  8. using?namespace?cv;??
  9. using?namespace?std;??
  10. ??
  11. void?main()???
  12. {??
  13. ????ifstream?fin("calibdata.txt");?/*?標定所用圖像文件的路徑?*/??
  14. ????ofstream?fout("caliberation_result.txt");??/*?保存標定結果的文件?*/????
  15. ????//讀取每一幅圖像,從中提取出角點,然后對角點進行亞像素精確化???
  16. ????cout<<"開始提取角點………………";??
  17. ????int?image_count=0;??/*?圖像數量?*/??
  18. ????Size?image_size;??/*?圖像的尺寸?*/??
  19. ????Size?board_size?=?Size(4,6);????/*?標定板上每行、列的角點數?*/??
  20. ????vector<Point2f>?image_points_buf;??/*?緩存每幅圖像上檢測到的角點?*/??
  21. ????vector<vector<Point2f>>?image_points_seq;?/*?保存檢測到的所有角點?*/??
  22. ????string?filename;??
  23. ????int?count=?-1?;//用于存儲角點個數。??
  24. ????while?(getline(fin,filename))??
  25. ????{??
  26. ????????image_count++;????????
  27. ????????//?用于觀察檢驗輸出??
  28. ????????cout<<"image_count?=?"<<image_count<<endl;??????????
  29. ????????/*?輸出檢驗*/??
  30. ????????cout<<"-->count?=?"<<count;????????
  31. ????????Mat?imageInput=imread(filename);??
  32. ????????if?(image_count?==?1)??//讀入第一張圖片時獲取圖像寬高信息??
  33. ????????{??
  34. ????????????image_size.width?=?imageInput.cols;??
  35. ????????????image_size.height?=imageInput.rows;???????????
  36. ????????????cout<<"image_size.width?=?"<<image_size.width<<endl;??
  37. ????????????cout<<"image_size.height?=?"<<image_size.height<<endl;??
  38. ????????}??
  39. ??
  40. ????????/*?提取角點?*/??
  41. ????????if?(0?==?findChessboardCorners(imageInput,board_size,image_points_buf))??
  42. ????????{?????????????
  43. ????????????cout<<"can?not?find?chessboard?corners!\n";?//找不到角點??
  44. ????????????exit(1);??
  45. ????????}???
  46. ????????else???
  47. ????????{??
  48. ????????????Mat?view_gray;??
  49. ????????????cvtColor(imageInput,view_gray,CV_RGB2GRAY);??
  50. ????????????/*?亞像素精確化?*/??
  51. ????????????find4QuadCornerSubpix(view_gray,image_points_buf,Size(5,5));?//對粗提取的角點進行精確化??
  52. ????????????//cornerSubPix(view_gray,image_points_buf,Size(5,5),Size(-1,-1),TermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.1));??
  53. ????????????image_points_seq.push_back(image_points_buf);??//保存亞像素角點??
  54. ????????????/*?在圖像上顯示角點位置?*/??
  55. ????????????drawChessboardCorners(view_gray,board_size,image_points_buf,false);?//用于在圖片中標記角點??
  56. ????????????imshow("Camera?Calibration",view_gray);//顯示圖片??
  57. ????????????waitKey(500);//暫停0.5S?????????
  58. ????????}??
  59. ????}??
  60. ????int?total?=?image_points_seq.size();??
  61. ????cout<<"total?=?"<<total<<endl;??
  62. ????int?CornerNum=board_size.width*board_size.height;??//每張圖片上總的角點數??
  63. ????for?(int?ii=0?;?ii<total?;ii++)??
  64. ????{??
  65. ????????if?(0?==?ii%CornerNum)//?24?是每幅圖片的角點個數。此判斷語句是為了輸出?圖片號,便于控制臺觀看???
  66. ????????{?????
  67. ????????????int?i?=?-1;??
  68. ????????????i?=?ii/CornerNum;??
  69. ????????????int?j=i+1;??
  70. ????????????cout<<"-->?第?"<<j?<<"圖片的數據?-->?:?"<<endl;??
  71. ????????}??
  72. ????????if?(0?==?ii%3)??//?此判斷語句,格式化輸出,便于控制臺查看??
  73. ????????{??
  74. ????????????cout<<endl;??
  75. ????????}??
  76. ????????else??
  77. ????????{??
  78. ????????????cout.width(10);??
  79. ????????}??
  80. ????????//輸出所有的角點??
  81. ????????cout<<"?-->"<<image_points_seq[ii][0].x;??
  82. ????????cout<<"?-->"<<image_points_seq[ii][0].y;??
  83. ????}?????
  84. ????cout<<"角點提取完成!\n";??
  85. ??
  86. ????//以下是攝像機標定??
  87. ????cout<<"開始標定………………";??
  88. ????/*棋盤三維信息*/??
  89. ????Size?square_size?=?Size(10,10);??/*?實際測量得到的標定板上每個棋盤格的大小?*/??
  90. ????vector<vector<Point3f>>?object_points;?/*?保存標定板上角點的三維坐標?*/??
  91. ????/*內外參數*/??
  92. ????Mat?cameraMatrix=Mat(3,3,CV_32FC1,Scalar::all(0));?/*?攝像機內參數矩陣?*/??
  93. ????vector<int>?point_counts;??//?每幅圖像中角點的數量??
  94. ????Mat?distCoeffs=Mat(1,5,CV_32FC1,Scalar::all(0));?/*?攝像機的5個畸變系數:k1,k2,p1,p2,k3?*/??
  95. ????vector<Mat>?tvecsMat;??/*?每幅圖像的旋轉向量?*/??
  96. ????vector<Mat>?rvecsMat;?/*?每幅圖像的平移向量?*/??
  97. ????/*?初始化標定板上角點的三維坐標?*/??
  98. ????int?i,j,t;??
  99. ????for?(t=0;t<image_count;t++)???
  100. ????{??
  101. ????????vector<Point3f>?tempPointSet;??
  102. ????????for?(i=0;i<board_size.height;i++)???
  103. ????????{??
  104. ????????????for?(j=0;j<board_size.width;j++)???
  105. ????????????{??
  106. ????????????????Point3f?realPoint;??
  107. ????????????????/*?假設標定板放在世界坐標系中z=0的平面上?*/??
  108. ????????????????realPoint.x?=?i*square_size.width;??
  109. ????????????????realPoint.y?=?j*square_size.height;??
  110. ????????????????realPoint.z?=?0;??
  111. ????????????????tempPointSet.push_back(realPoint);??
  112. ????????????}??
  113. ????????}??
  114. ????????object_points.push_back(tempPointSet);??
  115. ????}??
  116. ????/*?初始化每幅圖像中的角點數量,假定每幅圖像中都可以看到完整的標定板?*/??
  117. ????for?(i=0;i<image_count;i++)??
  118. ????{??
  119. ????????point_counts.push_back(board_size.width*board_size.height);??
  120. ????}?????
  121. ????/*?開始標定?*/??
  122. ????calibrateCamera(object_points,image_points_seq,image_size,cameraMatrix,distCoeffs,rvecsMat,tvecsMat,0);??
  123. ????cout<<"標定完成!\n";??
  124. ????//對標定結果進行評價??
  125. ????cout<<"開始評價標定結果………………\n";??
  126. ????double?total_err?=?0.0;?/*?所有圖像的平均誤差的總和?*/??
  127. ????double?err?=?0.0;?/*?每幅圖像的平均誤差?*/??
  128. ????vector<Point2f>?image_points2;?/*?保存重新計算得到的投影點?*/??
  129. ????cout<<"\t每幅圖像的標定誤差:\n";??
  130. ????fout<<"每幅圖像的標定誤差:\n";??
  131. ????for?(i=0;i<image_count;i++)??
  132. ????{??
  133. ????????vector<Point3f>?tempPointSet=object_points[i];??
  134. ????????/*?通過得到的攝像機內外參數,對空間的三維點進行重新投影計算,得到新的投影點?*/??
  135. ????????projectPoints(tempPointSet,rvecsMat[i],tvecsMat[i],cameraMatrix,distCoeffs,image_points2);??
  136. ????????/*?計算新的投影點和舊的投影點之間的誤差*/??
  137. ????????vector<Point2f>?tempImagePoint?=?image_points_seq[i];??
  138. ????????Mat?tempImagePointMat?=?Mat(1,tempImagePoint.size(),CV_32FC2);??
  139. ????????Mat?image_points2Mat?=?Mat(1,image_points2.size(),?CV_32FC2);??
  140. ????????for?(int?j?=?0?;?j?<?tempImagePoint.size();?j++)??
  141. ????????{??
  142. ????????????image_points2Mat.at<Vec2f>(0,j)?=?Vec2f(image_points2[j].x,?image_points2[j].y);??
  143. ????????????tempImagePointMat.at<Vec2f>(0,j)?=?Vec2f(tempImagePoint[j].x,?tempImagePoint[j].y);??
  144. ????????}??
  145. ????????err?=?norm(image_points2Mat,?tempImagePointMat,?NORM_L2);??
  146. ????????total_err?+=?err/=??point_counts[i];?????
  147. ????????std::cout<<"第"<<i+1<<"幅圖像的平均誤差:"<<err<<"像素"<<endl;?????
  148. ????????fout<<"第"<<i+1<<"幅圖像的平均誤差:"<<err<<"像素"<<endl;?????
  149. ????}?????
  150. ????std::cout<<"總體平均誤差:"<<total_err/image_count<<"像素"<<endl;?????
  151. ????fout<<"總體平均誤差:"<<total_err/image_count<<"像素"<<endl<<endl;?????
  152. ????std::cout<<"評價完成!"<<endl;????
  153. ????//保存定標結果??????
  154. ????std::cout<<"開始保存定標結果………………"<<endl;?????????
  155. ????Mat?rotation_matrix?=?Mat(3,3,CV_32FC1,?Scalar::all(0));?/*?保存每幅圖像的旋轉矩陣?*/??
  156. ????fout<<"相機內參數矩陣:"<<endl;?????
  157. ????fout<<cameraMatrix<<endl<<endl;?????
  158. ????fout<<"畸變系數:\n";?????
  159. ????fout<<distCoeffs<<endl<<endl<<endl;?????
  160. ????for?(int?i=0;?i<image_count;?i++)???
  161. ????{???
  162. ????????fout<<"第"<<i+1<<"幅圖像的旋轉向量:"<<endl;?????
  163. ????????fout<<tvecsMat[i]<<endl;??????
  164. ????????/*?將旋轉向量轉換為相對應的旋轉矩陣?*/?????
  165. ????????Rodrigues(tvecsMat[i],rotation_matrix);?????
  166. ????????fout<<"第"<<i+1<<"幅圖像的旋轉矩陣:"<<endl;?????
  167. ????????fout<<rotation_matrix<<endl;?????
  168. ????????fout<<"第"<<i+1<<"幅圖像的平移向量:"<<endl;?????
  169. ????????fout<<rvecsMat[i]<<endl<<endl;?????
  170. ????}?????
  171. ????std::cout<<"完成保存"<<endl;???
  172. ????fout<<endl;??
  173. ????/************************************************************************???
  174. ????顯示定標結果???
  175. ????*************************************************************************/??
  176. ????Mat?mapx?=?Mat(image_size,CV_32FC1);??
  177. ????Mat?mapy?=?Mat(image_size,CV_32FC1);??
  178. ????Mat?R?=?Mat::eye(3,3,CV_32F);??
  179. ????std::cout<<"保存矯正圖像"<<endl;??
  180. ????string?imageFileName;??
  181. ????std::stringstream?StrStm;??
  182. ????for?(int?i?=?0?;?i?!=?image_count?;?i++)??
  183. ????{??
  184. ????????std::cout<<"Frame?#"<<i+1<<"..."<<endl;??
  185. ????????initUndistortRectifyMap(cameraMatrix,distCoeffs,R,cameraMatrix,image_size,CV_32FC1,mapx,mapy);????????
  186. ????????StrStm.clear();??
  187. ????????imageFileName.clear();??
  188. ????????string?filePath="chess";??
  189. ????????StrStm<<i+1;??
  190. ????????StrStm>>imageFileName;??
  191. ????????filePath+=imageFileName;??
  192. ????????filePath+=".bmp";??
  193. ????????Mat?imageSource?=?imread(filePath);??
  194. ????????Mat?newimage?=?imageSource.clone();??
  195. ????????//另一種不需要轉換矩陣的方式??
  196. ????????//undistort(imageSource,newimage,cameraMatrix,distCoeffs);??
  197. ????????remap(imageSource,newimage,mapx,?mapy,?INTER_LINEAR);?????????
  198. ????????StrStm.clear();??
  199. ????????filePath.clear();??
  200. ????????StrStm<<i+1;??
  201. ????????StrStm>>imageFileName;??
  202. ????????imageFileName?+=?"_d.jpg";??
  203. ????????imwrite(imageFileName,newimage);??
  204. ????}??
  205. ????std::cout<<"保存結束"<<endl;??????
  206. ????return?;??
  207. }??


標定圖例1:



標定圖例2:



標定結果1:



標定結果2:



矯正效果1:



矯正效果2:



以上程序已經是完整程序,需要棋盤標定圖或者整個項目包的可以到這里下載:張正友相機標定Opencv實現(完整程序+棋盤圖)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/252022.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/252022.shtml
英文地址,請注明出處:http://en.pswp.cn/news/252022.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Redis學習筆記--Redis數據過期策略詳解==轉

本文對Redis的過期機制簡單的講解一下  講解之前我們先拋出一個問題&#xff0c;我們知道很多時候服務器經常會用到redis作為緩存&#xff0c;有很多數據都是臨時緩存一下&#xff0c;可能用過之后很久都不會再用到了&#xff08;比如暫存session&#xff0c;又或者只存放日行…

會員連鎖配置以及金額走向

PS&#xff1a;所有電子支付方式的資金走向都是同樣的&#xff0c;配置的是什么支付方式就走什么支付方式;下面以支付寶為例說明 一、連鎖非總機模式 資金走向&#xff1a; 支付寶&#xff1a;收到的錢在主賬號配置的支付寶&#xff0c;會員卡的金額在主賬號 微信&#xff1a;收…

Python標準模塊--logging

Python標準模塊--logging參考http://www.cnblogs.com/zhbzz2007/p/5943685.html1 logging模塊簡介logging模塊是Python內置的標準模塊&#xff0c;主要用于輸出運行日志&#xff0c;可以設置輸出日志的等級、日志保存路徑、日志文件回滾等&#xff1b;相比print&#xff0c;具備…

Podfile grammar

參考&#xff1a;http://www.jianshu.com/p/8af475c4f717 Podfile Podfile文件詳細描述了一個或多個工程中targets的依賴關系。Podfile會默認創建一個隱式的目標鏈接到工程中用戶的第一個target&#xff0c;名稱為“default”。 一個Podfile可以非常簡單: *pod AFNetworking, ~…

并發編程 - 協程 - 1.協程概念/2.greenlet模塊/3.gevent模塊/4.gevent實現并發的套接字通信...

1.協程并發&#xff1a;切保存狀態單線程下實現并發&#xff1a;協程 切 保存狀態 yield 遇到io切&#xff0c;提高效率 遇到計算切&#xff0c;并沒有提高效率 檢測單線程下 IO行為 io阻塞 切 相當于騙操作系統 一直處于計算協程&#xff1a;。。。單線程下實現…

pymysql

連接數據庫 連接時需要額外指定參數dbcursor.execute( ) 操作SQL語句SELECT VERSION() 獲得當前版本CREATE DATABASE spiders DEFAULT CHARACTER SET utf8 創建數據庫import pymysql db pymysql.connect(hostlocalhost,user ,password ,port3306)#IP&#xff0c;用戶名&#x…

C# 多線程及同步簡介示例

60年代&#xff0c;在OS中能擁有資源和獨立運行的基本單位是進程&#xff0c;然而隨著計算機技術的發展&#xff0c;進程出現了很多弊端&#xff0c;一是由于進程是資源擁有者&#xff0c;創建、撤消與切換存在較大的時空開銷&#xff0c;因此需要引入輕型進程&#xff1b;二是…

opencv-python單目視覺標定,簡單易用。

import cv2 import numpy as np import glob# 設置尋找亞像素角點的參數&#xff0c;采用的停止準則是最大循環次數30和最大誤差容限0.001 criteria (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001)# 獲取標定板角點的位置 objp np.zeros((6 * 7, 3), np.f…

python多線程多進程

一、線程&進程 對于操作系統來說&#xff0c;一個任務就是一個進程&#xff08;Process&#xff09;&#xff0c;比如打開一個瀏覽器就是啟動一個瀏覽器進程&#xff0c;打開一個記事本就啟動了一個記事本進程&#xff0c;打開兩個記事本就啟動了兩個記事本進程&#xff0c…

Spring Framework 5.1.6、5.0.13 與?4.3.23 發布

開發四年只會寫業務代碼&#xff0c;分布式高并發都不會還做程序員&#xff1f; Spring Framework 5.1.6、5.0.13 與 4.3.23 發布了。 v5.1.6 包含 49 個 bug 修復和功能改進&#xff1b;v5.0.13 是 5.0.x 系列的最后一個版本&#xff0c;包含了 25 個 bug 修復和功能改進&am…

curl命令

Curl是一種支持多種協議&#xff08;http、https&#xff0c;ftp&#xff09;等&#xff0c;利用url規則在命令行下工作的文件傳輸工具&#xff0c;還支持POST、cookies、認證、從指定偏移處下載部分文件、用戶代理字符串、限速、文件大小、進度條等特征 1.語法&#xff1a; cu…

單目視覺標定:世界坐標系、相機坐標系、圖像坐標系、像素坐標系——簡單粗暴,粗暴

轉&#xff1a;https://blog.csdn.net/chentravelling/article/details/53558096 1.正文 圖像處理、立體視覺等等方向常常涉及到四個坐標系&#xff1a;世界坐標系、相機坐標系、圖像坐標系、像素坐標系。例如下圖&#xff1a; 構建世界坐標系只是為了更好的描述相機的位置在哪…

Python基礎知識-05-數據類型總結字典

python其他知識目錄 1、一道題&#xff0c;選擇商品的序號。程序員和用戶各自面對的序號起始值 如有變量 googs [汽車,飛機,火箭] 提示用戶可供選擇的商品&#xff1a; 0,汽車1,飛機2,火箭用戶輸入索引后&#xff0c;將指定商品的內容拼接打印&#xff0c;如&#xff1a;用戶輸…

Python學習筆記之異常

Python用異常對象來表示異常情況&#xff0c;如果異常對象未被處理或捕捉&#xff0c;程序就會回溯&#xff08;traceback&#xff09;中止執行。 異常可以在出錯時自動引發&#xff0c;也可以主動引發。 異常被引發后如果不被處理就會傳播至程序調用的地方&#xff0c;直到主程…

VSFTP的使用

一、基本安裝 1.安裝服務 yum -y install vsftpd //centos Redhat apt-get install vsftpd //debian ubuntu 2.開啟服務 service vsftpd status //查看狀態&#xff0c;默認是關閉的 service vsftpd start 3.開機隨操作系統啟動 chkconfig vsftpd on4.添加賬號 useradd -d /…

OC Swift混編-Swift.h File not found

https://www.jianshu.com/p/f860fe1718ca 2016.09.13 11:53* 字數 266 閱讀 1935評論 1喜歡 1今天碰到個神坑,本人項目是OC項目,最近開始使用Swift開始替代.但是,在替代的已開始就出現問題了:新建swift文件,然后提示創建bridging-Hearder文件,然后swift可以使用OC代碼了.這些都…

視覺標定,再來一波!!更簡單粗暴!!!!!!

繼續&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 一、四個坐標系簡介和轉換 相機模型為以后一切標定算法的關鍵&#xff0c;只有這邊有相當透徹的理解&#xff0c;對以后的標定算法才能有更好的理解。本人研究了好長時間&#xff0c;幾乎每天…

深入淺出NIO之Selector實現原理

2019獨角獸企業重金招聘Python工程師標準>>> 前言 Java NIO 由以下幾個核心部分組成&#xff1a; 1、Buffer 2、Channel 3、Selector Buffer和Channel在深入淺出NIO之Channel、Buffer一文中已經介紹過&#xff0c;本文主要講解NIO的Selector實現原理。 之前進行sock…

介紹一下畫圖小能手matplotlib。

我們在做完數據分析的時候需要把分析出來的結果&#xff0c;做一個圖形化的形象表達&#xff0c;這里我們就需要用到畫圖小能手matplotlib&#xff0c;下面就演示一下常用的條形圖和折線圖 散點圖 散點圖的做大的作用是研究兩個變量的相關性&#xff08;正相關&#xff0c;負相…

立體視覺標定源代碼C++,簡單粗暴!粗暴·······

疑點解答&#xff1a; 攝像機矩陣由內參矩陣和外參矩陣組成&#xff0c;對攝像機矩陣進行QR分解可以得到內參矩陣和外參矩陣。 內參包括焦距、主點、傾斜系數、畸變系數 &#xff08;1&#xff09; 其中&#xff0c;fx&#xff0c;fy為焦距&#xff0c;一般情況下&#xff…