/* This is sample from the OpenCV book. The copyright notice is below */
/* *************** License:**************************
Oct. 3, 2008
Right to use this code in any way you want without warranty, support or any guarantee of it working.
BOOK: It would be nice if you cited it:
Learning OpenCV: Computer Vision with the OpenCV Library
by Gary Bradski and Adrian Kaehler
Published by O'Reilly Media, October 3, 2008
AVAILABLE AT:
http://www.amazon.com/Learning-OpenCV-Computer-Vision-Library/dp/0596516134
Or: http://oreilly.com/catalog/9780596516130/
ISBN-10: 0596516134 or: ISBN-13: 978-0596516130
OPENCV WEBSITES:
Homepage: http://opencv.org
Online docs: http://docs.opencv.org
Q&A forum: http://answers.opencv.org
Issue tracker: http://code.opencv.org
GitHub: https://github.com/opencv/opencv/
************************************************** */
#include "opencv2/calib3d.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
using namespace cv;
using namespace std;
static int print_help()
{
cout <<
" Given a list of chessboard images, the number of corners (nx, ny)\n"
" on the chessboards, and a flag: useCalibrated for \n"
" calibrated (0) or\n" //flag为0,私使用标定函数标定
" uncalibrated \n"
" (1: use cvStereoCalibrate(), 2: compute fundamental\n"
" matrix separately) stereo. \n"//flag为1,使用立体标定函数;flag为2,分别计算重要的矩阵
" Calibrate the cameras and display the\n"
" rectified results along with the computed disparity images. \n" << endl;
cout << "Usage:\n ./stereo_calib -w=<board_width default=9> -h=<board_height default=6> -s=<square_size default=1.0> <image list XML/YML file default=../data/stereo_calib.xml>\n" << endl;
return 0;
}
/*
立体标定函数
参数:
const vector<string>& imagelist---------一个容器名叫imagelist,每个元素都是一个图片名
Size boardSize----------标定板的大小
float squareSize---------每个角点之间的距离
bool displayCorners = false----------
bool useCalibrated=true, -----使用
bool showRectified=true----显示校正后的
返回值:无
功能:核心函数,进行立体标定,得到两个摄像机之间的参数(包括单个相机的内外参和两个相机之间的外参)
*/
static void //在形参中赋值,那么调用时可以给它传值,也可以不传,传了就用穿了的值,没传就用形参中的值;而形参中没赋值的,那么调用时必须传值
StereoCalib(const vector<string>& imagelist, Size boardSize, float squareSize, bool displayCorners = false, bool useCalibrated = true, bool showRectified = true)
{
if (imagelist.size() % 2 != 0)//图片列表必须为偶数,左右才能配对成功
{
cout << "Error: the image list contains odd (non-even) number of elements\n";
return;
}
const int maxScale = 2;
// ARRAY AND VECTOR STORAGE:
vector<vector<Point2f> > imagePoints[2];//定义两个像素坐标容器,它的元素仍为容器,容器存放二维坐标
vector<vector<Point3f> > objectPoints;//定义一个世界坐标容器,它的元素仍为容器,容器里存放三维坐标
Size imageSize;
int i, j, k, nimages = (int)imagelist.size() / 2;//将图片的数量除以2,为每个摄像机拍摄的图片数
imagePoints[0].resize(nimages);
imagePoints[1].resize(nimages);//调整左右两个容器的大小,等于总的图片数/2
vector<string> goodImageList;//存放配好对的的图片
for (i = j = 0; i < nimages; i++)//i,j表示第几对图
{
for (k = 0; k < 2; k++)//k表示“对”里边的第几张图
{
const string& filename = imagelist[i * 2 + k];//就是从图片列表中读取图片名,因为要匹配着来,所以有这个循环公式
Mat img = imread(filename, 0);//读取这个图片,并将这张图片转换成灰度
if (img.empty())
break;
if (imageSize == Size())
imageSize = img.size();
else if (img.size() != imageSize)
{
cout << "The image " << filename << " has the size different from the first image size. Skipping the pair\n";
break;
}//检查这两幅图大小是否一样
bool found = false;
vector<Point2f>& corners = imagePoints[k][j];//定义一个容器存放像素坐标,初值设置为imagePoints[2]的第k个,其实可以理解成k=0是存放左摄像机的图片,k=1同理,然后j是在左摄像机里取取第k张图
//imagelist容器就是存放图片名的,而imagePoints容器分为【0】和【1】,代表左右,【0】号容器里的元素还是容器(存放图片)
for (int scale = 1; scale <= maxScale; scale++)//maxScale=2,也就是说对一对图中的每一幅都进行这个操作
{
Mat timg;
if (scale == 1)//就把第一幅图存储到timg
timg = img;
else
resize(img, timg, Size(), scale, scale);//调整大小,img为输入,timg为输出
found = findChessboardCorners(timg, boardSize, corners,
CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE);//检测timg的角点,放到corners容器里
if (found)//找到角点后
{
if (scale > 1)
{
Mat cornersMat(corners);//定义矩阵类型的cornersMat,矩阵值就是corners容器的值
cornersMat *= 1. / scale;
}
break;//scale=1,跳出这个循环了
}//scale没有机会为2
}
if (displayCorners)
{
cout << filename << endl;
Mat cimg, cimg1;
cvtColor(img, cimg, COLOR_GRAY2BGR);
drawChessboardCorners(cimg, boardSize, corners, found);
double sf = 640. / MAX(img.rows, img.cols);
resize(cimg, cimg1, Size(), sf, sf);//首先将img调成灰度cimg,在cimg上绘制角点,重置cimg的大小cimg1
imshow("corners", cimg1);
char c = (char)waitKey(500);//等待500ms,如果这期间有键按下,则返回该键的ASCII值,否则返回-1
if (c == 27 || c == 'q' || c == 'Q') //Allow ESC to quit
exit(-1);
}
else
putchar('.');
if (!found)
break;
/* cornerSubPix(img, corners, Size(11, 11), Size(-1, -1),
TermCriteria(TermCriteria::COUNT + TermCriteria::EPS,
30, 0.01));//找亚角点,corners作为输入,也作为输出。都绘制完了,为什么还要找亚角点?*/
}
//如果是同一对的第二幅图,则还需进行以下操作:也就是说通过上面的代码已经把一对的两幅图处理完了,下面把配对好的存到goodImageList容器里
if (k == 2)
{
goodImageList.push_back(imagelist[i * 2]);
goodImageList.push_back(imagelist[i * 2 + 1]);
j++;
}
}//所有图片的循环结束
cout << j << " pairs have been successfully detected.\n";
nimages = j;
if (nimages < 2)
{
cout << "Error: too little pairs to run the calibration\n";
return;
}
imagePoints[0].resize(nimages);
imagePoints[1].resize(nimages);
objectPoints.resize(nimages);
for (i = 0; i < nimages; i++)
{
for (j = 0; j < boardSize.height; j++)
for (k = 0; k < boardSize.width; k++)
objectPoints[i].push_back(Point3f(k*squareSize, j*squareSize, 0));//计算每幅图对应的世界坐标,跟i无关,所以每幅图对应的世界坐标是一样的
}
cout << "Running stereo calibration ...\n";
Mat cameraMatrix[2], distCoeffs[2];
cameraMatrix[0] = initCameraMatrix2D(objectPoints, imagePoints[0], imageSize, 0);//初始化相机内参矩阵,这个函数只针对Zw轴为0时的标定方法有用
cameraMatrix[1] = initCameraMatrix2D(objectPoints, imagePoints[1], imageSize, 0);//调用这个函数后,则可以得到相机的内参数矩阵
Mat R, T, E, F;
//没有给畸变矩阵赋值啊,怎么作为参数传给stereo
binCalibration.zip_Vision_vs2015双目标定_双目_双目标定_双目标定vs2015
版权申诉
142 浏览量
2022-07-14
17:25:34
上传
评论
收藏 706KB ZIP 举报
局外狗
- 粉丝: 66
- 资源: 1万+
最新资源
- postgresql-42.7.3.jar
- 2024-05-21 20-36-43.mkv
- 基于QT+C++的智能云监护仪项目,能够实时显示使用者心电、血氧、血压波形及其它各种参数+源码(毕业设计&课程设计&项目开发)
- 基于java开发的app接收硬件端传输的心音信号,具有显示心音波形,发出心音的功能+源码(毕业设计&课程设计&项目开发)
- Python 程序语言设计模式思路-行为型模式:职责链模式:将请求从一个处理者传递到下一个处理者
- 9241703124789646.16健身系统2.apk
- postgresql-16.3-1-windows-x64.exe
- Python 程序语言设计模式思路-结构型模式:装饰器讲解及利用Python装饰器模式实现高效日志记录和性能测试
- 基于YOLOv5和DeepSORT的多目标跟踪仿真与记录
- Python 程序语言设计模式思路-创建型模式:原型模式:通过复制现有对象来创建新对象,面向对象编程
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈