当前位置:   article > 正文

使用opencv进行双目相机标定_opencv双目标定

opencv双目标定

一、利用相机拍摄保存相片

拍摄保存想拍摄棋盘局相片,用来做相机标定

  1. #include<opencv2/opencv.hpp>
  2. #include<stdlib.h>
  3. using namespace cv;
  4. using namespace std;
  5. void main()
  6. {
  7. VideoCapture cap;
  8. cap.open(0); //打开摄像头
  9. if (!cap.isOpened())//如果视频不能正常打开则返回
  10. return;
  11. cvWaitKey(30);
  12. Mat frame;//用于保存每一帧图像
  13. cap >> frame;
  14. imshow("【双目原始视图】", frame);
  15. cvWaitKey(300);
  16. char buf[30] = { 0 }; //保存路径变量
  17. while (1)
  18. {
  19. cap >> frame; //等价于cap.read(frame);
  20. if (frame.empty()) //如果某帧为空则退出循环
  21. break;
  22. imshow("【双目原始视图】", frame); //显示双目原始图像 原始分辨率为 640*480
  23. Mat DoubleImage;
  24. resize(frame, DoubleImage, Size(640, 240), (0, 0), (0, 0), INTER_AREA); // 纵向分辨率缩小一半
  25. imshow("【双目缩小视图】", DoubleImage); //显示图像
  26. Mat LeftImage = DoubleImage(Rect(0, 0, 320, 240)); //分割得到左视图
  27. Mat RightImage = DoubleImage(Rect(320, 0, 320, 240)); //分割得到右视图
  28. imshow("【左视图】", LeftImage); //显示左视图
  29. imshow("【右视图】", RightImage); //显示右视图
  30. char c = cvWaitKey(30);
  31. if (c == 27)//Esc键退出
  32. {
  33. break;
  34. }
  35. static int i = 9;
  36. if (13 == char(c))
  37. {
  38. sprintf(buf, ".\\picture\\left_%d.png", i); //保存左视图
  39. cout << buf;
  40. imwrite(buf, LeftImage);
  41. sprintf(buf, ".\\picture\\right_%d.png", i); //保存右视图
  42. imwrite(buf, RightImage);
  43. sprintf(buf, ".\\picture\\total_%d.png", i); //保存整体图像
  44. imwrite(buf, DoubleImage);
  45. i++;
  46. }
  47. }
  48. cap.release();//释放资源
  49. }

二、相机标定

注意stereo_calibration.xml放置目录要准确,保证上一步骤拍摄的相片能够读到。

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <time.h>
  4. #include <iostream>
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <cv.hpp>
  8. #include <highgui\highgui.hpp>
  9. #include <calib3d\calib3d.hpp>
  10. #include <imgproc\imgproc.hpp>
  11. #include <core\core.hpp>
  12. #include<stdlib.h>
  13. #include<Windows.h>
  14. //此处参数需要根据棋盘格个数修改
  15. //例如 黑白棋盘格 宽(w)为10个棋盘格 那么 w 为 10 -1 = 9
  16. #define w 9 //棋盘格宽的黑白交叉点个数
  17. #define h 6 //棋盘格高的黑白交叉点个数
  18. const float chessboardSquareSize = 12.5f; //每个棋盘格方块的边长 单位 为 mm
  19. using namespace std;
  20. using namespace cv;
  21. //从 xml 文件中读取图片存储路径
  22. static bool readStringList(const string& filename, vector<string>& list)
  23. {
  24. list.resize(0);
  25. FileStorage fs(filename, FileStorage::READ);
  26. if (!fs.isOpened())
  27. return false;
  28. FileNode n = fs.getFirstTopLevelNode();
  29. if (n.type() != FileNode::SEQ)
  30. return false;
  31. FileNodeIterator it = n.begin(), it_end = n.end();
  32. for (; it != it_end; ++it)
  33. list.push_back((string)*it);
  34. return true;
  35. }
  36. //记录棋盘格角点个数
  37. static void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners)
  38. {
  39. corners.resize(0);
  40. for (int i = 0; i < boardSize.height; i++) //height和width位置不能颠倒
  41. for (int j = 0; j < boardSize.width; j++)
  42. {
  43. corners.push_back(Point3f(j * squareSize, i * squareSize, 0));
  44. }
  45. }
  46. bool calibrate(Mat& intrMat, Mat& distCoeffs, vector<vector<Point2f>>& imagePoints,
  47. vector<vector<Point3f>>& ObjectPoints, Size& imageSize, const int cameraId,
  48. vector<string> imageList)
  49. {
  50. double rms = 0; //重投影误差
  51. Size boardSize;
  52. boardSize.width = w;
  53. boardSize.height = h;
  54. vector<Point2f> pointBuf;
  55. float squareSize = chessboardSquareSize;
  56. vector<Mat> rvecs, tvecs; //定义两个摄像头的旋转矩阵 和平移向量
  57. bool ok = false;
  58. int nImages = (int)imageList.size() / 2;
  59. cout << "图片张数" << nImages;
  60. namedWindow("View", 1);
  61. int nums = 0; //有效棋盘格图片张数
  62. for (int i = 0; i < nImages; i++)
  63. {
  64. Mat view, viewGray;
  65. view = imread(imageList[i * 2 + cameraId], 1); //读取图片
  66. imageSize = view.size();
  67. cvtColor(view, viewGray, COLOR_BGR2GRAY); //转化成灰度图
  68. bool found = findChessboardCorners(view, boardSize, pointBuf,
  69. CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FAST_CHECK | CV_CALIB_CB_NORMALIZE_IMAGE); //寻找棋盘格角点
  70. if (found)
  71. {
  72. nums++;
  73. cornerSubPix(viewGray, pointBuf, Size(11, 11),
  74. Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
  75. drawChessboardCorners(view, boardSize, Mat(pointBuf), found);
  76. bitwise_not(view, view);
  77. imagePoints.push_back(pointBuf);
  78. cout << '.';
  79. }
  80. imshow("View", view);
  81. waitKey(50);
  82. }
  83. cout << "有效棋盘格张数" << nums << endl;
  84. //calculate chessboardCorners
  85. calcChessboardCorners(boardSize, squareSize, ObjectPoints[0]);
  86. ObjectPoints.resize(imagePoints.size(), ObjectPoints[0]);
  87. rms = calibrateCamera(ObjectPoints, imagePoints, imageSize, intrMat, distCoeffs,
  88. rvecs, tvecs);
  89. ok = checkRange(intrMat) && checkRange(distCoeffs);
  90. if (ok)
  91. {
  92. cout << "done with RMS error=" << rms << endl;
  93. return true;
  94. }
  95. else
  96. return false;
  97. }
  98. int main()
  99. {
  100. //initialize some parameters
  101. bool okcalib = false;
  102. Mat intrMatFirst, intrMatSec, distCoeffsFirst, distCoffesSec;
  103. Mat R, T, E, F, RFirst, RSec, PFirst, PSec, Q;
  104. vector<vector<Point2f>> imagePointsFirst, imagePointsSec;
  105. vector<vector<Point3f>> ObjectPoints(1);
  106. Rect validRoi[2];
  107. Size imageSize;
  108. int cameraIdFirst = 0, cameraIdSec = 1;
  109. double rms = 0;
  110. //get pictures and calibrate
  111. vector<string> imageList;
  112. string filename = "D:\\desktop\\双目\\学习例程\\TestOpencv\\x64\\Debug\\stereo_calibration.xml";
  113. bool okread = readStringList(filename, imageList);
  114. if (!okread || imageList.empty())
  115. {
  116. cout << "can not open " << filename << " or the string list is empty" << endl;
  117. return false;
  118. }
  119. if (imageList.size() % 2 != 0)
  120. {
  121. cout << "Error: the image list contains odd (non-even) number of elements\n";
  122. return false;
  123. }
  124. FileStorage fs("intrinsics.yml", FileStorage::WRITE);
  125. //calibrate
  126. cout << "calibrate left camera..." << endl;
  127. okcalib = calibrate(intrMatFirst, distCoeffsFirst, imagePointsFirst, ObjectPoints,
  128. imageSize, cameraIdFirst, imageList);
  129. if (!okcalib)
  130. {
  131. cout << "fail to calibrate left camera" << endl;
  132. return -1;
  133. }
  134. else
  135. {
  136. cout << "calibrate the right camera..." << endl;
  137. }
  138. okcalib = calibrate(intrMatSec, distCoffesSec, imagePointsSec, ObjectPoints,
  139. imageSize, cameraIdSec, imageList);
  140. fs << "M1" << intrMatFirst << "D1" << distCoeffsFirst <<
  141. "M2" << intrMatSec << "D2" << distCoffesSec;
  142. if (!okcalib)
  143. {
  144. cout << "fail to calibrate the right camera" << endl;
  145. return -1;
  146. }
  147. destroyAllWindows();
  148. //estimate position and orientation
  149. cout << "estimate position and orientation of the second camera" << endl
  150. << "relative to the first camera..." << endl;
  151. cout << intrMatFirst;
  152. cout << distCoeffsFirst;
  153. cout << intrMatSec;
  154. cout << distCoffesSec;
  155. rms = stereoCalibrate(ObjectPoints, imagePointsFirst, imagePointsSec,
  156. intrMatFirst, distCoeffsFirst, intrMatSec, distCoffesSec,
  157. imageSize, R, T, E, F, CALIB_USE_INTRINSIC_GUESS,//CV_CALIB_FIX_INTRINSIC,
  158. TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, 1e-6)); //计算重投影误差
  159. cout << "done with RMS error=" << rms << endl;
  160. //stereo rectify
  161. cout << "stereo rectify..." << endl;
  162. stereoRectify(intrMatFirst, distCoeffsFirst, intrMatSec, distCoffesSec, imageSize, R, T, RFirst,
  163. RSec, PFirst, PSec, Q, CALIB_ZERO_DISPARITY, -1, imageSize, &validRoi[0], &validRoi[1]);
  164. cout << "Q" << Q << endl;
  165. cout << "P1" << PFirst << endl;
  166. cout << "P2" << PSec << endl;
  167. //read pictures for 3d-reconstruction
  168. if (fs.isOpened())
  169. {
  170. cout << "in";
  171. fs << "R" << R << "T" << T << "R1" << RFirst << "R2" << RSec << "P1" << PFirst << "P2" << PSec << "Q" << Q;
  172. fs.release();
  173. }
  174. namedWindow("canvas", 1);
  175. cout << "read the picture for 3d-reconstruction...";
  176. Mat canvas(imageSize.height, imageSize.width * 2, CV_8UC3), viewLeft, viewRight;
  177. Mat canLeft = canvas(Rect(0, 0, imageSize.width, imageSize.height));
  178. Mat canRight = canvas(Rect(imageSize.width, 0, imageSize.width, imageSize.height));
  179. viewLeft = imread(imageList[6], 1);//cameraIdFirst
  180. viewRight = imread(imageList[7], 1); //cameraIdSec
  181. viewLeft.copyTo(canLeft);
  182. viewRight.copyTo(canRight);
  183. cout << "done" << endl;
  184. imshow("canvas", canvas);
  185. waitKey(50); //必须要加waitKey ,否则可能存在无法显示图像问题
  186. //stereoRectify
  187. Mat rmapFirst[2], rmapSec[2], rviewFirst, rviewSec;
  188. initUndistortRectifyMap(intrMatFirst, distCoeffsFirst, RFirst, PFirst,
  189. imageSize, CV_16SC2, rmapFirst[0], rmapFirst[1]);//CV_16SC2
  190. initUndistortRectifyMap(intrMatSec, distCoffesSec, RSec, PSec,//CV_16SC2
  191. imageSize, CV_16SC2, rmapSec[0], rmapSec[1]);
  192. remap(viewLeft, rviewFirst, rmapFirst[0], rmapFirst[1], INTER_LINEAR);
  193. imshow("remap", rviewFirst);
  194. waitKey(40);
  195. remap(viewRight, rviewSec, rmapSec[0], rmapSec[1], INTER_LINEAR);
  196. rviewFirst.copyTo(canLeft);
  197. rviewSec.copyTo(canRight);
  198. //rectangle(canLeft, validRoi[0], Scalar(255, 0, 0), 3, 8);
  199. //rectangle(canRight, validRoi[1], Scalar(255, 0, 0), 3, 8);
  200. Mat before_rectify = imread("./picture/total_0.png");
  201. for (int j = 0; j <= canvas.rows; j += 16) //画绿线
  202. line(canvas, Point(0, j), Point(canvas.cols, j), Scalar(0, 255, 0), 1, 8);
  203. for (int j = 0; j <= canvas.rows; j += 16) //画绿线
  204. line(before_rectify, Point(0, j), Point(canvas.cols, j), Scalar(0, 255, 0), 1, 8);
  205. cout << "stereo rectify done" << endl;
  206. imshow("校正前", before_rectify); //显示画绿线的校正后图像
  207. imshow("校正后", canvas); //显示画绿线的校正前图像
  208. waitKey(400000);//必须要加waitKey ,否则可能存在无法显示图像问题
  209. return 0;
  210. }

三、标定板

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/341151?site
推荐阅读
相关标签
  

闽ICP备14008679号