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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

用OpenCV进行摄像机标定

發布時間:2023/11/28 生活经验 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用OpenCV进行摄像机标定 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

用OpenCV進行攝像機標定
照相機已經存在很長時間了。然而,隨著廉價針孔相機在20世紀末的引入,日常生活中變得司空見慣。不幸的是,這種廉價伴隨著它的代價:顯著的扭曲。幸運的是,這些常數,通過校準和一些重新映射,可以糾正這一點。此外,通過校準,還可以確定相機的自然單位(像素)和真實世界單位(例如毫米)之間的關系。
原理
對于畸變,OpenCV考慮了徑向和切向因素。對于徑向,使用以下公式:

So for an old pixel point at
coordinate in the input image, for a corrected output image its position will be
.
徑向畸變的存在表現為“桶”或“魚眼”效應。
由于攝像鏡頭與成像平面不完全平行,因此會發生切向失真。通過以下公式進行修正:

有五個失真參數,在OpenCV中被組織在一個1行5列的矩陣中:

Now for the unit conversion, we use the following formula:

Here the presence of the is cause we use a homography coordinate system (and
). The unknown parameters are
and
(camera focal lengths) and what are the optical centers expressed in pixels coordinates. If for both axes a common focal length is used with a given
aspect ratio (usually 1), then
and in the upper formula we will have a single focal length. 包含這四個參數的矩陣稱為攝像機矩陣。盡管失真系數是相同的,不管使用何種攝像頭分辨率,但這些失真系數應與當前校準分辨率一起縮放。
確定這兩個矩陣的變換過程就是校準。這些參數的計算是通過一些基本的幾何方程來完成的。使用的方程式,取決于使用的校準對象。目前OpenCV支持三種類型的對象進行校準:
?經典黑白棋盤
?對稱圓模式
?不對稱圓形圖案
基本上,需要用相機拍下這些圖案的快照,然后讓OpenCV找到它們。在一個新的方程中,每一個可見的模式都相等。為了解這個方程,至少需要預定數量的模式快照,來形成一個適配的方程組。這個數字具有較高的棋盤圖案和較少的圓的。例如,在理論上,一個棋盤至少需要兩個快照。然而,實際上,輸入圖像中存在大量的噪聲,因此為了獲得好的結果,可能需要至少10個不同位置的輸入模式的良好快照。
目標
示例應用程序將:
?確定失真矩陣
?確定攝像機矩陣
?攝像機、視頻和圖像文件列表的輸入
?從XML/YAML文件進行配置
?將結果保存到XML/YAML文件中
?計算重投影誤差
Source code
You may also find the source code in the samples/cpp/tutorial_code/calib3d/camera_calibration/ folder of the OpenCV source library or download it from here.
可以在OpenCV源代碼庫的samples/cpp/tutorial\u code/calib3d/camera\u calibration/文件夾中找到源代碼。程序只有一個參數。其配置文件的名稱。如果沒有,它將嘗試打開一個名為“default.xml”. 下面是一個XML格式的示例配置文件。在配置文件中,可以選擇使用相機、視頻文件或圖像列表作為輸入。如果選擇后者,則需要創建一個配置文件,在其中枚舉要使用的映像。下面是一個例子。需要記住的重要一點是,需要使用應用程序工作目錄中的絕對路徑或相對路徑來指定映像。可以在前面提到的目錄中找到所有這些。
應用程序首先從配置文件中讀取設置。盡管這是其中的一個重要部分,但與本文的主題無關:相機校準。因此,選擇不在這里發布代碼部分。關于如何做到這一點的技術背景可以在XML YAML中找到。
Explanation

  1. Read the settings.

  2. Settings s;

  3. const string inputSettingsFile = argc > 1 ? argv[1] : “default.xml”;

  4. FileStorage fs(inputSettingsFile, FileStorage::READ); // Read the settings

  5. if (!fs.isOpened())

  6. {

  7.    cout << "Could not open the configuration file: \"" << inputSettingsFile << "\"" << endl;
    
  8.    return -1;
    
  9. }

  10. fs[“Settings”] >> s;

  11. fs.release(); // close Settings file

  12. if (!s.goodInput)

  13. {

  14.   cout << "Invalid input detected. Application stopping. " << endl;
    
  15.   return -1;
    
  16. }
    使用簡單的OpenCV類輸入操作。在讀取文件之后,有一個額外的后處理函數,來檢查輸入的有效性。只有當它們都正常,goodInput變量才是正常。
    獲取下一個輸入,如果失敗,或者有足夠的輸入。此后,有一個大的循環,在這里,做以下操作:從圖像列表中獲取下一個圖像,相機或視頻文件。如果這失敗了,或者有足夠的圖像,運行校準過程。在圖像的情況下,步出循環,否則其余的幀將不失真(如果選項設置),通過改變檢測模式到校準一。

  17. for(int i = 0;;++i)

  18. {

  19. Mat view;

  20. bool blinkOutput = false;

  21. view = s.nextImage();

  22. //----- If no more image, or got enough, then stop calibration and show result -------------

  23. if( mode == CAPTURING && imagePoints.size() >= (unsigned)s.nrFrames )

  24. {

  25.     if( runCalibrationAndSave(s, imageSize,  cameraMatrix, distCoeffs, imagePoints))
    
  26.           mode = CALIBRATED;
    
  27.     else
    
  28.           mode = DETECTION;
    
  29. }

  30. if(view.empty()) // If no more images then run calibration, save and stop loop.

  31. {

  32.         if( imagePoints.size() > 0 )
    
  33.               runCalibrationAndSave(s, imageSize,  cameraMatrix, distCoeffs, imagePoints);
    
  34.         break;
    
  35. imageSize = view.size(); // Format input image.

  36. if( s.flipVertical ) flip( view, view, 0 );

  37. }
    For some cameras we may need to flip the input image. Here we do this too.

  38. Find the pattern in the current input. The formation of the equations I mentioned above consists of finding the major patterns in the input: in case of the chessboard this is their corners of the squares and for the circles, well, the circles itself. The position of these will form the result and is collected into the pointBuf vector.

  39. vector pointBuf;

  40. bool found;

  41. switch( s.calibrationPattern ) // Find feature points on the input format

  42. {

  43. case Settings::CHESSBOARD:

  44. found = findChessboardCorners( view, s.boardSize, pointBuf,

  45. CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FAST_CHECK | CV_CALIB_CB_NORMALIZE_IMAGE);

  46. break;

  47. case Settings::CIRCLES_GRID:

  48. found = findCirclesGrid( view, s.boardSize, pointBuf );

  49. break;

  50. case Settings::ASYMMETRIC_CIRCLES_GRID:

  51. found = findCirclesGrid( view, s.boardSize, pointBuf, CALIB_CB_ASYMMETRIC_GRID );

  52. break;

  53. }
    根據輸入模式的類型,可以使用findChessboardCorners或findCirclesGrid函數。對于這兩種情況,會傳遞當前的圖像、電路板的大小,會得到圖案的位置。此外,還返回一個布爾變量,說明在輸入中是否可以找到模式(只需要考慮圖像中的情況)。
    同樣,對于相機,只在輸入延遲時間,過后才拍攝相機圖像。用戶移動棋盤,獲得不同的圖像。相同的圖像意味著相同的方程,在標定時,相同的方程將形成不適定問題,因此標定將失敗。對于正方形圖像,角點的位置只是近似值。可以通過調用cornerSubPix函數來改進這一點。這樣可以得到更好的標定結果。之后,將一個有效的輸入結果添加到imagePoints向量中,將所有方程收集到一個容器中。最后,為了實現可視化反饋,將使用findChessboardCorners函數在輸入圖像上繪制找到的點。
    if ( found) // If done with success,
    {
    // improve the found corners’ coordinate accuracy for chessboard
    if( s.calibrationPattern == Settings::CHESSBOARD)
    {
    Mat viewGray;
    cvtColor(view, viewGray, CV_BGR2GRAY);
    cornerSubPix( viewGray, pointBuf, Size(11,11),
    Size(-1,-1), TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));
    }

    if( mode == CAPTURING &&  // For camera only take new samples after delay time(!s.inputCapture.isOpened() || clock() - prevTimestamp > s.delay*1e-3*CLOCKS_PER_SEC) )
    {imagePoints.push_back(pointBuf);prevTimestamp = clock();blinkOutput = s.inputCapture.isOpened();
    }// Draw the corners.
    drawChessboardCorners( view, s.boardSize, Mat(pointBuf), found );
    

}
為用戶顯示狀態和結果,以及應用程序的命令行控制。顯示部分由實時文本輸出組成,對于要顯示“捕獲”幀的視頻或相機輸入,只需按位求反輸入圖像。
58. //----------------------------- Output Text ------------------------------------------------
59. string msg = (mode == CAPTURING) ? “100/100” :
60. mode == CALIBRATED ? “Calibrated” : “Press ‘g’ to start”;
61. int baseLine = 0;
62. Size textSize = getTextSize(msg, 1, 1, 1, &baseLine);
63. Point textOrigin(view.cols - 2textSize.width - 10, view.rows - 2baseLine - 10);
64.
65. if( mode == CAPTURING )
66. {
67. if(s.showUndistorsed)
68. msg = format( “%d/%d Undist”, (int)imagePoints.size(), s.nrFrames );
69. else
70. msg = format( “%d/%d”, (int)imagePoints.size(), s.nrFrames );
71. }
72.
73. putText( view, msg, textOrigin, 1, 1, mode == CALIBRATED ? GREEN : RED);
74.
75. if( blinkOutput )
76. bitwise_not(view, view);
If we only ran the calibration and got the camera matrix plus the distortion coefficients we may just as correct the image with the undistort function:
//------------------------- Video capture output undistorted ------------------------------
if( mode == CALIBRATED && s.showUndistorsed )
{
Mat temp = view.clone();
undistort(temp, view, cameraMatrix, distCoeffs);
}
//------------------------------ Show image and check for input commands -------------------
imshow(“Image View”, view);
Then we wait for an input key and if this is u we toggle the distortion removal, if it is g we start all over the detection process (or simply start it), and finally for the ESC key quit the application:
char key = waitKey(s.inputCapture.isOpened() ? 50 : s.delay);
if( key == ESC_KEY )
break;

if( key == ‘u’ && mode == CALIBRATED )
s.showUndistorsed = !s.showUndistorsed;

if( s.inputCapture.isOpened() && key == ‘g’ )
{
mode = CAPTURING;
imagePoints.clear();
}
顯示圖像的失真消除。使用圖像列表時,無法消除循環中的失真。因此,必須在循環之后附加。利將展開無失真函數,實際上是首先調用initundortrectitymap來找出變換矩陣,然后用remap函數進行變換。在成功校準后,地圖計算只需進行一次,通過使用此擴展表格,可以加快應用程序的速度:
77. if( s.inputType == Settings::IMAGE_LIST && s.showUndistorsed )
78. {
79. Mat view, rview, map1, map2;
80. initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(),
81. getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0),
82. imageSize, CV_16SC2, map1, map2);
83.
84. for(int i = 0; i < (int)s.imageList.size(); i++ )
85. {
86. view = imread(s.imageList[i], 1);
87. if(view.empty())
88. continue;
89. remap(view, rview, map1, map2, INTER_LINEAR);
90. imshow(“Image View”, rview);
91. char c = waitKey();
92. if( c == ESC_KEY || c == ‘q’ || c == ‘Q’ )
93. break;
94. }
95. }
The calibration and save
每個攝像機只需要校準一次,在成功校準后,保存它們是有意義的。這樣以后就可以將這些值加載到程序中。因此,首先進行校準,如果校準成功,將結果保存到OpenCV樣式的XML或YAML文件中,具體取決于在配置文件中給出的擴展名。
因此,在第一個函數中,只是將這兩個過程分開。因為想保存許多校準變量,所以將在這里創建這些變量,并將它們傳遞給校準和保存函數。再次,將不顯示保存部分,因為與校準幾乎沒有共同點。瀏覽源文件以了解如何和內容:
bool runCalibrationAndSave(Settings& s, Size imageSize, Mat& cameraMatrix, Mat& distCoeffs,vector<vector > imagePoints )
{
vector rvecs, tvecs;
vector reprojErrs;
double totalAvgErr = 0;

bool ok = runCalibration(s,imageSize, cameraMatrix, distCoeffs, imagePoints, rvecs, tvecs,
reprojErrs, totalAvgErr);
cout << (ok ? “Calibration succeeded” : “Calibration failed”)
<< ". avg re projection error = " << totalAvgErr ;

if( ok ) // save only if the calibration was done with success
saveCameraParams( s, imageSize, cameraMatrix, distCoeffs, rvecs ,tvecs, reprojErrs,
imagePoints, totalAvgErr);
return ok;
}
在calibleCamera函數進行校準。具有以下參數:
?物體角點。這是點3f向量的向量,對于每個輸入圖像,它描述了模式的外觀。如果有一個平面圖案(如棋盤),可以簡單地將所有Z坐標設置為零。這是這些要點所在的要點的集合。對所有的輸入圖像使用一個模式,只需計算一次,然后乘以所有其他的輸入視圖。使用CalcBoardCornePositions函數計算角點,如下所示:
?
? void calcBoardCornerPositions(Size boardSize, float squareSize, vector& corners,
? Settings::Pattern patternType /= Settings::CHESSBOARD/)
? {
? corners.clear();
?
? switch(patternType)
? {
? case Settings::CHESSBOARD:
? case Settings::CIRCLES_GRID:
? for( int i = 0; i < boardSize.height; ++i )
? for( int j = 0; j < boardSize.width; ++j )
? corners.push_back(Point3f(float( jsquareSize ), float( isquareSize ), 0));
? break;
?
? case Settings::ASYMMETRIC_CIRCLES_GRID:
? for( int i = 0; i < boardSize.height; i++ )
? for( int j = 0; j < boardSize.width; j++ )
? corners.push_back(Point3f(float((2j + i % 2)squareSize), float(isquareSize), 0));
? break;
? }
? }
And then multiply it as:
vector<vector > objectPoints(1);
calcBoardCornerPositions(s.boardSize, s.squareSize, objectPoints[0], s.calibrationPattern);
objectPoints.resize(imagePoints.size(),objectPoints[0]);
? ?圖像點。這是點2f向量的向量,對于每個輸入圖像,該向量包含找到重要點(棋盤的角點和圓模式的圓心)的位置。已經從findChessboardCorners或findCirclesGrid函數返回的內容中,收集了這個。只需要把它傳下去。
? ?從相機、視頻文件或圖像中獲取的圖像大小。
? ?攝像機矩陣。如果使用“固定縱橫比”選項,則需要將設置
為零:
? cameraMatrix = Mat::eye(3, 3, CV_64F);
? if( s.flag & CV_CALIB_FIX_ASPECT_RATIO )
? cameraMatrix.at(0,0) = 1.0;
? The distortion coefficient matrix. Initialize with zero.
? distCoeffs = Mat::zeros(8, 1, CV_64F);
? ?該函數將為所有視圖計算旋轉和平移矢量,該矢量將對象點(在模型坐標空間中給出)轉換為圖像點(在世界坐標空間中給出)。第7和第8參數是矩陣的輸出向量,該矩陣在第i個位置中,包含第i個目標角點到第i個圖像點的旋轉和平移向量。
? ?最后一個參數是flag。需要在這里指定選項,如固定焦距的縱橫比、假設零切向失真或固定主點。
?
double rms = calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix,
distCoeffs, rvecs, tvecs, s.flag|CV_CALIB_FIX_K4|CV_CALIB_FIX_K5);
? ?函數返回平均重投影誤差。這個數字很好地估計了,找到的參數到底有多精確。應該盡可能接近于零。在給定內稟矩陣、畸變矩陣、旋轉矩陣和平移矩陣的情況下,可以利用投影點,將物體點變換為像點,來計算一個視圖的誤差。然后,計算得到的絕對范數之間的轉換和角/圓發現算法。為了找出平均誤差,計算了所有校準圖像的誤差算術平均值。
? double computeReprojectionErrors( const vector<vector >& objectPoints,
? const vector<vector >& imagePoints,
? const vector& rvecs, const vector& tvecs,
? const Mat& cameraMatrix , const Mat& distCoeffs,
? vector& perViewErrors)
? {
? vector imagePoints2;
? int i, totalPoints = 0;
? double totalErr = 0, err;
? perViewErrors.resize(objectPoints.size());
?
? for( i = 0; i < (int)objectPoints.size(); ++i )
? {
? projectPoints( Mat(objectPoints[i]), rvecs[i], tvecs[i], cameraMatrix, // project
? distCoeffs, imagePoints2);
? err = norm(Mat(imagePoints[i]), Mat(imagePoints2), CV_L2); // difference
?
? int n = (int)objectPoints[i].size();
? perViewErrors[i] = (float) std::sqrt(err
err/n); // save for this view
? totalErr += err*err; // sum it up
? totalPoints += n;
? }
?
? return std::sqrt(totalErr/totalPoints); // calculate the arithmetical mean
? }
Results
設置這個輸入棋盤圖案的大小為9 X 6。用一個AXIS IP攝像頭,創建幾個板的快照,并將其保存到VID5目錄中。我已將其放入工作目錄的images/cameracalibration文件夾中,并創建了以下VID5.XML文件,該文件描述了要使用的圖像:

<?xml version="1.0"?>

<opencv_storage>

images/CameraCalibraation/VID5/xx1.jpg
images/CameraCalibraation/VID5/xx2.jpg
images/CameraCalibraation/VID5/xx3.jpg
images/CameraCalibraation/VID5/xx4.jpg
images/CameraCalibraation/VID5/xx5.jpg
images/CameraCalibraation/VID5/xx6.jpg
images/CameraCalibraation/VID5/xx7.jpg
images/CameraCalibraation/VID5/xx8.jpg

</opencv_storage>
然后將images/cameracalibration/VID5/VID5.XML指定為配置文件中的輸入。在應用程序運行時,可見棋盤模式:

應用失真消除后,得到:

通過將“輸入寬度”(input width)設置為4,將“高度”(height)設置為11,同樣的方法也適用于這種不對稱的圓形圖案。使用了一個實時攝像機feed,為輸入指定了它的ID(“1”)。以下是檢測到的模式的照片:

在這兩種情況下,在指定的輸出XML/YAML文件中,將發現攝影機和失真系數矩陣:
<Camera_Matrix type_id=“opencv-matrix”>
3
3

d6.5746697944293521e+002 0. 3.1950000000000000e+002 0. 6.5746697944293521e+002 2.3950000000000000e+002 0. 0. 1. 5 1 d-4.1802327176423804e-001 5.0715244063187526e-001 0. 0. -5.7843597214487474e-001 將這些值作為常量添加到程序中,調用initundortrectitymap和remap函數以消除失真,并使用廉價和低質量的相機享受無失真輸入。

總結

以上是生活随笔為你收集整理的用OpenCV进行摄像机标定的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 2021毛片| 青娱乐在线免费视频 | 亚洲一区自拍偷拍 | 鲁一鲁一鲁一鲁一av | 日韩电影一区二区在线观看 | 日韩手机看片 | 麻豆av毛片 | 超级黄色录像 | 蜜桃久久久 | 粉嫩久久99精品久久久久久夜 | 欧美激情视频二区 | 精品人妻无码一区二区三区蜜桃一 | 在线免费观看污片 | 久久久久99精品成人片试看 | 黄色一级网 | 白白色在线播放 | 精品少妇人妻av免费久久洗澡 | 女性向av免费网站 | 国产精品19乱码一区二区三区 | 8x8ⅹ国产精品一区二区 | 在线免费黄网 | 四虎精品视频 | 久久老熟女一区二区三区 | 97国产超碰 | 日本人妖xxxx| 在线免费观看一区二区 | 三级av在线 | 91传媒理伦片在线观看 | www.在线播放 | 色欲av永久无码精品无码蜜桃 | 成人国产网站 | 国产一二三区av | 夜夜操夜夜爽 | 国产真实乱偷精品视频 | 国产欧美日韩一区二区三区 | 国内自拍视频在线播放 | 亚洲深夜福利 | 久久久亚洲一区 | 中文字幕三级视频 | 国产精品国产三级国产专播品爱网 | 69视频在线| 泰坦尼克号3小时49分的观看方法 | 成年人黄色| 少妇高潮久久久 | 在线免费看污视频 | 99国产精品白浆在线观看免费 | 国产精品www色诱视频 | 欧美精品久久久久久久久老牛影院 | 污色视频| 成人在线视频免费 | 黄色一级一片 | 中日韩免费视频 | 91高清在线视频 | 中文字幕一区二区在线观看 | 亚欧在线 | 国产一区二区三区在线观看 | 看片网站在线观看 | 五月天丁香激情 | 熟妇高潮一区二区三区 | 午夜影院美女 | 91在线精品一区二区 | 男女视频一区二区 | 色婷婷久久一区二区三区麻豆 | 国产91久久精品一区二区 | 男女男精品视频 | xxx色 | 激情五月在线观看 | 一本久草| 欧美区亚洲区 | 免费成人电影在线观看 | 国产一区精品在线观看 | 三日本三级少妇三级99 | 粉嫩av国产一区二区三区 | 丁香婷婷综合网 | 国产精品久久国产精品99 | 国产亚洲一区二区不卡 | 亚洲精品影视 | 公侵犯人妻一区二区三区 | 在线免费av网址 | 蜜臀久久99精品久久一区二区 | 天堂av手机版 | 91精品国产亚洲 | 亚洲草逼视频 | 人妻少妇一区二区三区 | 国产xxxxxx| 国产精品色 | 亚欧成人精品一区二区 | 一区免费在线观看 | 美女视频黄色在线观看 | 韩日av片 | av观看国产| 欧美性天天影院 | 电影一区二区三区 | 老狼影院伦理片 | 欧美一区二区三区精品 | 男女视频在线观看免费 | 亲嘴脱内衣内裤 | 国内自拍视频在线播放 | 嫩草在线观看 |