OpenCV学习系列:标定相关程序练习

//-----------------------------------OpenCV学习1------------------------------------- 
//  程序名称:利用OpenCV做标定板,可自定义!!!
//  201610Created by孙立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp> 
#include <iostream>
#include <string> 
using namespace cv;
using namespace std;
int main()
{
    //---生成标定图

    int dd = 80;        //棋盘格大小,像素为单位
    int dx = 3;     //行:白块开头,竖着格数为6.竖向为4个焦点
    int dy = 4;     //列:白块开头,横格数为8,横向为6个角点
    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    //注意:Size第一个为行,第二个为列!!
    Mat img(Size(2 * dy * dd, 2 * dx * dd), CV_8UC1, Scalar(0));

    int flag = 0;
    for (int i = 0; i < 2 * dx; i++)
    for (int j = 0; j < 2 * dy; j++)
    {
        flag = (i + j) % 2;
        if (flag == 0)
        {
            for (int m = i*dd; m < (i + 1)*dd; m++)
            for (int n = j*dd; n < (j + 1)*dd; n++)
                //or((uchar *)(img.data + m * img.step))[n] = 255;
                (*(img.data + m * img.step + n * img.elemSize())) = 255;
            //elemSize为一个像素所占用字节个数
            //*(img->imageData+m*img->widthStep+n)=255;
        }

    }
    //---END生成标定图
    imwrite("F:\\棋盘格标定图(80像素).bmp", img);
    cvNamedWindow("棋盘格", 1);
    imshow("棋盘格", img);
    cvWaitKey(0);
    cvDestroyWindow("棋盘格");
}
//-----------------------------------OpenCV学习2------------------------------------- 
//  程序名称:测试天敏VC400采集卡程序,该程序适用于笔记本自带摄像头视频采集
//需配置videoInput.cpp和videoInput.h文件
//  2016年10月 Created by孙立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp> 
#include <iostream>
#include <string> 

#include "videoInput.h"

using namespace std;
using namespace cv;
void main()
{
    //创建捕获对象
    videoInput VI;
    //可用摄像头,返回ID号的各路总个数,在此直接用0,因为采集卡插在0号ID
    int numID = VI.listDevices();

    int device1 = 0;
    //默认参数设置摄像头
    VI.setupDevice(device1, 640, 480, 1);//1代表采用混合路VI_COMPOSITE连接方式
    /*VI.setupDevice(device1);*/
    //VI.setFormat(device1, VI_PAL_B);  //可设置视频格式,默认下为PAL
    //长宽尺寸
    int width = VI.getWidth(device1);
    int height = VI.getHeight(device1);
    int size = VI.getSize(device1);
    cout << "width=" << width << "\t" << "height=" << height << endl;
    cout << "framesize=" << size << endl;

    //声明显示图像
    Mat image;
    Mat frame;
    image.create(Size(width, height), CV_8UC3);
    frame.create(Size(width, height), CV_8UC3);

    //分配内存
    uchar* yourBuffer = (uchar*)malloc(size);

    while (1)
    {
        VI.getPixels(device1, yourBuffer, false, false);
        image.data = (uchar*)yourBuffer;

        //左右翻转
        flip(image, image, 0);//0竖直翻转1水平翻转-1垂直水平翻转
        waitKey(50);
        imshow("采集的图像", image);

    }

}

//-----------------------------------OpenCV标定焊接图像------------------------------------- 
//  程序名称:OpenCV标定焊接图像,该程序根据DOS提示,一步步实现标定的自动化,求取内参,
//           标定请在F盘创建“biaoding”用于储存采集的图像和结果
//  过程描述:提取图像并保存,提取各图像序列角点,角点亚像素精确化,摄像机标定畸变参数和内参,
//           定标结果评价(保存结果在F:\\biaoding\\biaoding_result.txt),最后矫正所有图像到“F:\\biaoding”文件夹
//  需设参数:需要提取的的图像数imageCount = **,每个标定板图像角点数board_size = Size(*, *),每个格子像素边长Size square_size = Size(80, 80)这个参数设置为每个格子边长像素值;  

//******************************************************注意事项**********************************
/*
    注意:
    要想让程序跑完完成整个过程,必须把board_size设对,且程序正以假设得到的都是完全的包含所有角点的图像,所以采集的图像需包含所有格子!!!因为这点调了半天程序
*/
//  所用IDE版本:        Visual Studio 2013    
//  开发所用OpenCV版本:        2.4.9    
//  2016年10月 Created by 孙立波    

//包含程序所依赖的头文件:为方便起见把经常用的头文件都写在这里(前三必须包含),也可以用#include "opencv.hpp"包含下面所有头文件
#include <opencv2\opencv.hpp>   
#include <iostream>
#include <string> 
#include <vector>
#include <iomanip>
#include <fstream>

#include "videoInput.h"
using namespace cv;
using namespace std;
//隐藏控制台窗口
//#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
int main()
{
    //********************************************************************************************
    //创建捕获对象
    videoInput VI;
    //可用摄像头,返回ID号的各路总个数,在此直接用0,因为采集卡插在0号ID
    int numID = VI.listDevices();

    int device1 = 0;
    //默认参数设置摄像头
    VI.setupDevice(device1, 640, 480, 1);//1代表采用混合路VI_COMPOSITE连接方式,即针对模拟摄像头,视频一路传送的为亮度信号和两个色差信号的混合信号
    /*VI.setupDevice(device1);*/
    //VI.setFormat(device1, VI_PAL_B);  //可设置视频格式,默认下为PAL
    //长宽尺寸
    int width = VI.getWidth(device1);
    int height = VI.getHeight(device1);
    int size = VI.getSize(device1);
    cout << "width=" << width << "\t" << "height=" << height << endl;
    cout << "framesize=" << size << endl;

    //声明显示图像
    Mat frame;

    frame.create(Size(width, height), CV_8UC3);

    //分配内存
    uchar* yourBuffer = (uchar*)malloc(size);

    /************************************************************************
    读取21张图像,存入内存F:\biaoding文件中
    *************************************************************************/
    cout << "开始提取21张标定板图像………………" << endl;
    int imageCount = 21;
    int key = 0;
    int count1 = 0;
    for (int i = 0; i != imageCount; i++)
    {
        cout << "Frame#" << i + 1 << "..." << endl;
        std::stringstream StrStm;
        //为了将i转化为字符型,用StrStm做中介
        string imageFileName;
        StrStm << i + 1;
        StrStm >> imageFileName;
        imageFileName += ".jpg";

        //system("pause");//用waitKey必须有GUI窗口生成才行

        cout << "按Enter开始抽取图像,进入后可按q或者ESC键重新抽取图像,若按Enter键表明这帧图像被存入文件夹中" << endl;
        //key = waitKey();


        int flag = 1;
        while (flag)
        {
            VI.getPixels(device1, yourBuffer, false, false);
            frame.data = (uchar*)yourBuffer;
            waitKey(50);
            //左右翻转
            flip(frame, frame, 0);//0竖直翻转1水平翻转,-1垂直水平翻转

            Mat image0 = frame;//抽取到的临时图像数据并显示出来

            imshow("显示抓取图像", image0);//显示是否符合要求
            int key2;
            key2 = waitKey();
            if (key2 == 13)//按Enter键存取图像到F盘biaoding文件区
            {
                cout << "提取标定板图像成功!………………" << endl;
                std::stringstream str;
                str << "F:\\biaoding\\img" << std::setw(2) << std::setfill('0') << i + 1 << ".jpg";
                std::cout << "提取的图像保存路径及文件名" << str.str() << endl;
                imwrite(str.str(), image0);//保存的是从硬件得到的源格式图像
                flag = 0;
                count1 += 1;//已经得到的标定图像计数总数
            }
            else
            if (key2 == 113 || key2 == 27)//按Q或者ESC键从新获取一阵图像
                cout << "这次提取的标定板图像不成功!重新提取!!!!………………" << endl;
        };//分号很重要!!!!!!

    }
    if (count1 == imageCount)
    {
        cout << "***********************………………" << endl;
        cout << "***********************………………" << endl;
        cout << "下面开始标定图像...................." << endl;
        count1 = 0;
    }

    system("pause");//用waitKey必须有GUI窗口生成才行
    /************************************************************************
    读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
    *************************************************************************/

    cout << "开始提取角点………………" << endl;

    cout << "开始提取角点………………" << endl;

    double time0 = static_cast<double>(getTickCount());//记录定标参数求取和将所有图像矫正用的总时间
    ofstream fout("F:\\biaoding\\biaoding_result.txt");  /**    保存定标结果的文件     **/
    Size image_size;                          /****    图像的尺寸      ****/
    Size board_size(9, 9);                    /****    定标板上每行、列的角点数       ****/
    vector<Point2f> corners;                  /****    缓存每幅图像上检测到的角点     ****/
    vector<vector<Point2f>>  corners_Seq;     /****    保存检测到的所有角点           ****/
    vector<Mat>  image_Seq;

    int count = 0;
    int image_count = imageCount;
    for (int i = 0; i != image_count; i++)
    {
        cout << "Frame #" << i + 1 << "..." << endl;
        std::stringstream str;
        //str << "F:\\biaoding\\img" << std::setw(2) << std::setfill('0') << i + 1 << ".jpg";
        str << "F:\\biaoding\\img" << std::setw(2) << std::setfill('0') << i + 1 << ".jpg";
        std::cout << str.str() << std::endl;
        Mat image = imread(str.str());
        image_size = image.size();

        /* 提取角点 */
        Mat imageGray;
        cvtColor(image, imageGray, CV_RGB2GRAY);
        bool patternfound = findChessboardCorners(image, board_size, corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE +
            CALIB_CB_FAST_CHECK);
        if (!patternfound)
        {
            cout << "can not find chessboard corners!\n";
            continue;
            exit(1);
        }
        else
        {
            /*
            亚像素精确化 :迭代过程的终止条件可以是最大迭代次数CV_TERMCRIT_ITER类型,或者是设定的精度CV_TERMCRIT_EPS类型(或者是两
            者的组合)。终止条件的设置在极大程度上影响最终得到的亚像素值的精度。在此,指定为0.10,则求得的亚像素级精度为像素的十分
            之一
            */
            cornerSubPix(imageGray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
            //Size(11, 11)为搜索窗口的一半尺寸,Size(-1, -1)死区的一半尺寸,死区为不对搜索区的中央位置做求和运算的区域。/
            //它是用来避免自相关矩阵出现的某些可能的奇异性。当值为(-1,-1)表示没有死区。
            //TermCriteria为求角点的迭代过程的终止条件。即角点位置的确定,要么迭代数大于某个设定值,或者是精确懂达到某个设定值。
            //criteria可以是最大迭代数目,或者是设定的精确度,也可以是它们的组合。
            /* 绘制检测到的角点并保存 */
            Mat imageTemp = image.clone();
            for (int j = 0; j < corners.size(); j++)
            {
                circle(imageTemp, corners[j], 10, Scalar(0, 0, 255), 2, 8, 0);
            }
            string imageFileName;
            std::stringstream StrStm;
            StrStm << i + 1;
            StrStm >> imageFileName;
            imageFileName += "_corner.jpg";
            //保存提取角点的图像
            imwrite("F:\\biaoding\\" + imageFileName, imageTemp);
            cout << "Frame corner#" << i + 1 << "...end" << endl;

            count = count + corners.size();
            //将该角点压入角点序列堆栈
            corners_Seq.push_back(corners);
        }
        //将处理过的图像压入源图像堆栈
        image_Seq.push_back(image);
    }
    cout << "角点提取完成!\n";

    cout << "角点提取完成!下一步摄像机定标\n";
    system("pause");
    /************************************************************************
    摄像机定标
    *************************************************************************/
    cout << "开始定标………………" << endl;
    Size square_size = Size(80, 80);                                      /**** 实际测量得到的定标板上每个棋盘格的大小,单位为像素 ****/
    vector<vector<Point3f>>  object_Points;                       /**** 保存定标板上角点的三维坐标   ****/


    Mat image_points = Mat(1, count, CV_32FC2, Scalar::all(0));   /***** 保存提取的所有角点1*序列图像的角点总数   *****/
    vector<int>  point_counts;                                    /***** 每幅图像中角点的数量 ****/
    Mat intrinsic_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0));  /***** 摄像机内参数矩阵    ****/
    Mat distortion_coeffs = Mat(1, 4, CV_32FC1, Scalar::all(0));  /* 摄像机的4个畸变系数:k1,k2,p1,p2 */
    vector<cv::Mat> rotation_vectors;                             /* 图像序列图像的旋转向量,每一行代表一个旋转向量 */
    vector<cv::Mat> translation_vectors;                         /* 每幅图像的平移向量,每一行代表一个平移向量 */

    /* 初始化定标板上角点的三维坐标,此用的是像素坐标 */
    for (int t = 0; t<image_count; t++)
    {
        vector<Point3f> tempPointSet;//存储每幅图像的像素坐标
        for (int i = 0; i<board_size.height; i++)
        {
            for (int j = 0; j<board_size.width; j++)
            {
                /* 假设定标板放在世界坐标系中z=0的平面上 */
                Point3f tempPoint;
                //在这里,board_size中棋盘格子为单位长度,当square_size存储的像素边长为边长为80,代表width、height为80
                tempPoint.x = i*square_size.width;
                tempPoint.y = j*square_size.height;
                tempPoint.z = 0;
                tempPointSet.push_back(tempPoint);
            }
        }
        object_Points.push_back(tempPointSet);//存储图像序列中每幅图像的像素坐标
    }

    /* 初始化每幅图像中的角点数量,这里我们假设每幅图像中都可以看到完整的定标板 */
    for (int i = 0; i< image_count; i++)
    {
        point_counts.push_back(board_size.width*board_size.height);
    }

    /* 开始定标 */
    calibrateCamera(object_Points, corners_Seq, image_size, intrinsic_matrix, distortion_coeffs, rotation_vectors, translation_vectors, 0);
    cout << "定标完成!\n";
    /************************************************************************
    对定标结果进行评价
    *************************************************************************/
    cout << "开始评价定标结果………………" << endl;
    double total_err = 0.0;                   /* 所有图像的平均误差的总和 */
    double err = 0.0;                        /* 每幅图像的平均误差 */
    vector<Point2f>  image_points2;             /****   保存重新计算得到的投影点    ****/

    cout << "每幅图像的定标误差:" << endl;
    fout << "每幅图像的定标误差:" << endl << endl;
    for (int i = 0; i<image_count; i++)
    {
        vector<Point3f> tempPointSet = object_Points[i];
        /****    通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点     ****/
        projectPoints(tempPointSet, rotation_vectors[i], translation_vectors[i], intrinsic_matrix, distortion_coeffs, image_points2);
        /* 计算新的投影点和旧的投影点之间的误差*/
        vector<Point2f> tempImagePoint = corners_Seq[i];
        Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);
        Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
        for (size_t i = 0; i != tempImagePoint.size(); i++)
        {
            image_points2Mat.at<Vec2f>(0, i) = Vec2f(image_points2[i].x, image_points2[i].y);
            tempImagePointMat.at<Vec2f>(0, i) = Vec2f(tempImagePoint[i].x, tempImagePoint[i].y);
        }
        err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
        total_err += err /= point_counts[i];
        cout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
        fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
    }
    cout << "总体平均误差:" << total_err / image_count << "像素" << endl;
    fout << "总体平均误差:" << total_err / image_count << "像素" << endl << endl;
    cout << "评价完成!" << endl;

    /************************************************************************
    保存定标结果
    *************************************************************************/
    cout << "开始保存定标结果………………" << endl;
    Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */

    fout << "相机内参数矩阵:" << endl;
    cout << "相机内参数矩阵:" << endl;
    fout << intrinsic_matrix << endl;
    cout << intrinsic_matrix << endl;
    fout << "畸变系数:\n";
    cout << "畸变系数:\n";
    fout << distortion_coeffs << endl;
    cout << distortion_coeffs << endl;
    for (int i = 0; i<image_count; i++)
    {
        fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
        fout << rotation_vectors[i] << endl;

        /* 将旋转向量转换为相对应的旋转矩阵 */
        Rodrigues(rotation_vectors[i], rotation_matrix);
        fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
        fout << rotation_matrix << endl;
        fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
        fout << translation_vectors[i] << endl;
    }
    cout << "完成保存" << endl;
    fout << endl;


    /************************************************************************
    显示定标结果
    *************************************************************************/
    Mat mapx = Mat(image_size, CV_32FC1);
    Mat mapy = Mat(image_size, CV_32FC1);
    Mat R = Mat::eye(3, 3, CV_32F);
    cout << "保存矫正图像" << endl;
    for (int i = 0; i != image_count; i++)
    {
        cout << "Frame #" << i + 1 << "..." << endl;
        //newCameraMatrix——输入的校正后的3X3摄像机矩阵(也可用cvStereoRectify()得出的3X4的左或右投影矩阵,其实系统会自动提取该
        //矩阵前三列的有用部分作为输入参数)注:!!无校正变换的相机仍用求得内参矩阵
        Mat newCameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
        //得到映射关系:R——输入的第一和第二相机坐标系之间的旋转矩阵,一般般无校正变换的相机,默认为单位矩阵
        // opencv中,remap与undistortion都是消除畸变的函数,undistortion在设置了一些参数后调用了remap函数,二者的算法实质是一样
        //的。由目标图像的坐标,找到对应的原始图像坐标,然后将其值复制到目标图像。大致思路是如此,由于图像大小和变换,需要插值或
        //近似的方法,如最邻近法、线性插值等
        initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, R, intrinsic_matrix, image_size, CV_32FC1, mapx, mapy);
        Mat t = image_Seq[i].clone();
        cv::remap(image_Seq[i], t, mapx, mapy, INTER_LINEAR);
        string imageFileName;
        std::stringstream StrStm;
        StrStm << i + 1;
        StrStm >> imageFileName;
        imageFileName += "_校正图像.jpg";
        imwrite("F:\\biaoding\\" + imageFileName, t);
    }
    cout << "保存结束" << endl;

    time0 = ((double)getTickCount() - time0) / getTickFrequency();
    cout << "标定用时:" << time0 << "秒" << endl;
    system("pause");

    /************************************************************************
    测试一张图片,用标定过参数去校正畸变,并记所用时间
    *************************************************************************/
    /*
    double time1 = static_cast<double>(getTickCount());
    if (1)
    {
    cout << "TestImage ..." << endl;
    //newCameraMatrix——输入的校正后的3X3摄像机矩阵(也可用cvStereoRectify()得出的3X4的左或右投影矩阵,其实系统会自动提取该
    //矩阵前三列的有用部分作为输入参数)
    Mat newCameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
    Mat testImage = imread("F:\\biaoding\\img03.jpg", 1);
    initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, R, intrinsic_matrix, image_size, CV_32FC1, mapx, mapy);
    Mat t = testImage.clone();
    cv::remap(testImage, t, mapx, mapy, INTER_LINEAR);

    imwrite("img3_TestOutput.jpg", t);
    cout << "保存结束" << endl;
    }
    time1 = ((double)getTickCount() - time1) / getTickFrequency();
    cout << "一张图片的畸变校正用时:" << time1 << "秒" << endl;
    */
    return 0;
}
//-----------------------------------OpenCV学习------------------------------------- 
//  程序名称:标定
//  2016年10月 Created by孙立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp> 
#include <iostream>
#include <string> 
#include <vector>
#include <iomanip>
#include <fstream>
using namespace cv;
using namespace std;
int main()
{
    int imageCount = 17;//因为当时采集的21张图片,后面几张角点图像没完全显示出来,导致调试了半天程序
    cout << "开始提取角点………………" << endl;

    double time0 = static_cast<double>(getTickCount());//记录定标参数求取和将所有图像矫正用的总时间
    ofstream fout("F:\\biaoding\\biaoding_result.txt");  /**    保存定标结果的文件     **/
    Size image_size;                          /****    图像的尺寸      ****/
    Size board_size(9, 9);                    /****    定标板上每行、列的角点数       ****/
    vector<Point2f> corners;                  /****    缓存每幅图像上检测到的角点     ****/
    vector<vector<Point2f>>  corners_Seq;     /****    保存检测到的所有角点           ****/
    vector<Mat>  image_Seq;

    int count = 0;
    int image_count = imageCount;
    for (int i = 0; i != image_count; i++)
    {
        cout << "Frame #" << i + 1 << "..." << endl;
        std::stringstream str;
        //str << "F:\\biaoding\\img" << std::setw(2) << std::setfill('0') << i + 1 << ".jpg";
        str << "F:\\biaoding\\img" << std::setw(2) << std::setfill('0') << i + 1 << ".jpg";
        std::cout << str.str() << std::endl;
        Mat image = imread(str.str());
        image_size = image.size();

        /* 提取角点 */
        Mat imageGray;
        cvtColor(image, imageGray, CV_RGB2GRAY);
        bool patternfound = findChessboardCorners(image, board_size, corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE +
            CALIB_CB_FAST_CHECK);
        if (!patternfound)
        {
            cout << "can not find chessboard corners!\n";
            continue;
            exit(1);
        }
        else
        {
            /*
            亚像素精确化 :迭代过程的终止条件可以是最大迭代次数CV_TERMCRIT_ITER类型,或者是设定的精度CV_TERMCRIT_EPS类型(或者是两
            者的组合)。终止条件的设置在极大程度上影响最终得到的亚像素值的精度。在此,指定为0.10,则求得的亚像素级精度为像素的十分
            之一
            */
            cornerSubPix(imageGray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
            //Size(11, 11)为搜索窗口的一半尺寸,Size(-1, -1)死区的一半尺寸,死区为不对搜索区的中央位置做求和运算的区域。/
            //它是用来避免自相关矩阵出现的某些可能的奇异性。当值为(-1,-1)表示没有死区。
            //TermCriteria为求角点的迭代过程的终止条件。即角点位置的确定,要么迭代数大于某个设定值,或者是精确懂达到某个设定值。
            //criteria可以是最大迭代数目,或者是设定的精确度,也可以是它们的组合。
            /* 绘制检测到的角点并保存 */
            Mat imageTemp = image.clone();
            for (int j = 0; j < corners.size(); j++)
            {
                circle(imageTemp, corners[j], 10, Scalar(0, 0, 255), 2, 8, 0);
            }
            string imageFileName;
            std::stringstream StrStm;
            StrStm << i + 1;
            StrStm >> imageFileName;
            imageFileName += "_corner.jpg";
            //保存提取角点的图像
            imwrite("F:\\biaoding\\" + imageFileName, imageTemp);
            cout << "Frame corner#" << i + 1 << "...end" << endl;

            count = count + corners.size();
            //将该角点压入角点序列堆栈
            corners_Seq.push_back(corners);
        }
        //将处理过的图像压入源图像堆栈
        image_Seq.push_back(image);
    }
    cout << "角点提取完成!\n";

    cout << "角点提取完成!下一步摄像机定标\n";
    system("pause");
    /************************************************************************
    摄像机定标
    *************************************************************************/
    cout << "开始定标………………" << endl;
    Size square_size = Size(80, 80);                                      /**** 实际测量得到的定标板上每个棋盘格的大小,单位为像素 ****/
    vector<vector<Point3f>>  object_Points;                       /**** 保存定标板上角点的三维坐标   ****/


    Mat image_points = Mat(1, count, CV_32FC2, Scalar::all(0));   /***** 保存提取的所有角点1*序列图像的角点总数   *****/
    vector<int>  point_counts;                                    /***** 每幅图像中角点的数量 ****/
    Mat intrinsic_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0));  /***** 摄像机内参数矩阵    ****/
    Mat distortion_coeffs = Mat(1, 4, CV_32FC1, Scalar::all(0));  /* 摄像机的4个畸变系数:k1,k2,p1,p2 */
    vector<cv::Mat> rotation_vectors;                             /* 图像序列图像的旋转向量,每一行代表一个旋转向量 */
    vector<cv::Mat> translation_vectors;                         /* 每幅图像的平移向量,每一行代表一个平移向量 */

    /* 初始化定标板上角点的三维坐标,此用的是像素坐标 */
    for (int t = 0; t<image_count; t++)
    {
        vector<Point3f> tempPointSet;//存储每幅图像的像素坐标
        for (int i = 0; i<board_size.height; i++)
        {
            for (int j = 0; j<board_size.width; j++)
            {
                /* 假设定标板放在世界坐标系中z=0的平面上 */
                Point3f tempPoint;
                //在这里,board_size中棋盘格子为单位长度,当square_size存储的像素边长为边长为80,代表width、height为80
                tempPoint.x = i*square_size.width;
                tempPoint.y = j*square_size.height;
                tempPoint.z = 0;
                tempPointSet.push_back(tempPoint);
            }
        }
        object_Points.push_back(tempPointSet);//存储图像序列中每幅图像的像素坐标
    }

    /* 初始化每幅图像中的角点数量,这里我们假设每幅图像中都可以看到完整的定标板 */
    for (int i = 0; i< image_count; i++)
    {
        point_counts.push_back(board_size.width*board_size.height);
    }

    /* 开始定标 */
    calibrateCamera(object_Points, corners_Seq, image_size, intrinsic_matrix, distortion_coeffs, rotation_vectors, translation_vectors, 0);
    cout << "定标完成!\n";
    /************************************************************************
    对定标结果进行评价
    *************************************************************************/
    cout << "开始评价定标结果………………" << endl;
    double total_err = 0.0;                   /* 所有图像的平均误差的总和 */
    double err = 0.0;                        /* 每幅图像的平均误差 */
    vector<Point2f>  image_points2;             /****   保存重新计算得到的投影点    ****/

    cout << "每幅图像的定标误差:" << endl;
    fout << "每幅图像的定标误差:" << endl << endl;
    for (int i = 0; i<image_count; i++)
    {
        vector<Point3f> tempPointSet = object_Points[i];
        /****    通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点     ****/
        projectPoints(tempPointSet, rotation_vectors[i], translation_vectors[i], intrinsic_matrix, distortion_coeffs, image_points2);
        /* 计算新的投影点和旧的投影点之间的误差*/
        vector<Point2f> tempImagePoint = corners_Seq[i];
        Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);
        Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
        for (size_t i = 0; i != tempImagePoint.size(); i++)
        {
            image_points2Mat.at<Vec2f>(0, i) = Vec2f(image_points2[i].x, image_points2[i].y);
            tempImagePointMat.at<Vec2f>(0, i) = Vec2f(tempImagePoint[i].x, tempImagePoint[i].y);
        }
        err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
        total_err += err /= point_counts[i];
        cout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
        fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
    }
    cout << "总体平均误差:" << total_err / image_count << "像素" << endl;
    fout << "总体平均误差:" << total_err / image_count << "像素" << endl << endl;
    cout << "评价完成!" << endl;

    /************************************************************************
    保存定标结果
    *************************************************************************/
    cout << "开始保存定标结果………………" << endl;
    Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */

    fout << "相机内参数矩阵:" << endl;
    cout << "相机内参数矩阵:" << endl;
    fout << intrinsic_matrix << endl;
    cout << intrinsic_matrix << endl;
    fout << "畸变系数:\n";
    cout << "畸变系数:\n";
    fout << distortion_coeffs << endl;
    cout << distortion_coeffs << endl;
    for (int i = 0; i<image_count; i++)
    {
        fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
        fout << rotation_vectors[i] << endl;

        /* 将旋转向量转换为相对应的旋转矩阵 */
        Rodrigues(rotation_vectors[i], rotation_matrix);
        fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
        fout << rotation_matrix << endl;
        fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
        fout << translation_vectors[i] << endl;
    }
    cout << "完成保存" << endl;
    fout << endl;


    /************************************************************************
    显示定标结果
    *************************************************************************/
    Mat mapx = Mat(image_size, CV_32FC1);
    Mat mapy = Mat(image_size, CV_32FC1);
    Mat R = Mat::eye(3, 3, CV_32F);
    cout << "保存矫正图像" << endl;
    for (int i = 0; i != image_count; i++)
    {
        cout << "Frame #" << i + 1 << "..." << endl;
        //newCameraMatrix——输入的校正后的3X3摄像机矩阵(也可用cvStereoRectify()得出的3X4的左或右投影矩阵,其实系统会自动提取该
        //矩阵前三列的有用部分作为输入参数)注:!!无校正变换的相机仍用求得内参矩阵
        Mat newCameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
        //得到映射关系:R——输入的第一和第二相机坐标系之间的旋转矩阵,一般般无校正变换的相机,默认为单位矩阵
        // opencv中,remap与undistortion都是消除畸变的函数,undistortion在设置了一些参数后调用了remap函数,二者的算法实质是一样
        //的。由目标图像的坐标,找到对应的原始图像坐标,然后将其值复制到目标图像。大致思路是如此,由于图像大小和变换,需要插值或
        //近似的方法,如最邻近法、线性插值等
        initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, R, intrinsic_matrix, image_size, CV_32FC1, mapx, mapy);
        Mat t = image_Seq[i].clone();
        cv::remap(image_Seq[i], t, mapx, mapy, INTER_LINEAR);
        string imageFileName;
        std::stringstream StrStm;
        StrStm << i + 1;
        StrStm >> imageFileName;
        imageFileName += "_校正图像.jpg";
        imwrite("F:\\biaoding\\" + imageFileName, t);
    }
    cout << "保存结束" << endl;

    time0 = ((double)getTickCount() - time0) / getTickFrequency();
    cout << "标定用时:" << time0 << "秒" << endl;
    system("pause");

    /************************************************************************
    测试一张图片,用标定过参数去校正畸变,并记所用时间
    *************************************************************************/
    /*
    double time1 = static_cast<double>(getTickCount());
    if (1)
    {
    cout << "TestImage ..." << endl;
    //newCameraMatrix——输入的校正后的3X3摄像机矩阵(也可用cvStereoRectify()得出的3X4的左或右投影矩阵,其实系统会自动提取该
    //矩阵前三列的有用部分作为输入参数)
    Mat newCameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
    Mat testImage = imread("F:\\biaoding\\img03.jpg", 1);
    initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, R, intrinsic_matrix, image_size, CV_32FC1, mapx, mapy);
    Mat t = testImage.clone();
    cv::remap(testImage, t, mapx, mapy, INTER_LINEAR);

    imwrite("img3_TestOutput.jpg", t);
    cout << "保存结束" << endl;
    }
    time1 = ((double)getTickCount() - time1) / getTickFrequency();
    cout << "一张图片的畸变校正用时:" << time1 << "秒" << endl;
    */
    return 0;
}
//-----------------------------------OpenCV学习18------------------------------------- 
//  程序名称:标定
//  2016年10月 Created by孙立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp> 
#include <iostream>
#include <string> 
#include <vector>
#include <iomanip>
#include <fstream>
using namespace cv;
using namespace std;
int main()
{
    double time0 = static_cast<double>(getTickCount());
    ofstream fout("biaoding_result.txt");  /**    保存定标结果的文件     **/

    /************************************************************************
    读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
    *************************************************************************/
    cout << "开始提取角点………………" << endl;
    int image_count = 17;                     /****    图像数量        ****/
    Size image_size;                          /****    图像的尺寸      ****/
    Size board_size = Size(9, 9);             /****    定标板上每行、列的角点数       ****/
    vector<Point2f> corners;                  /****    缓存每幅图像上检测到的角点     ****/
    vector<vector<Point2f>>  corners_Seq;     /****    保存检测到的所有角点           ****/
    vector<Mat>  image_Seq;


    int count = 0;
    for (int i = 0; i != image_count; i++)
    {
        cout << "Frame #" << i + 1 << "..." << endl;

        string imageFileName;
        std::stringstream StrStm;
        //为了将i转化为字符型,用StrStm做中介
        StrStm << i + 1;
        StrStm >> imageFileName;
        imageFileName += ".jpg";

        std::stringstream str;
        str << "F:\\biaoding\\img" << std::setw(2) << std::setfill('0') << i + 1 << ".jpg";
        std::cout << str.str() << std::endl;
        Mat image = cv::imread(str.str());

        image_size = image.size();
        //image_size = Size(image.cols , image.rows);

        /* 提取角点 */
        Mat imageGray;
        cvtColor(image, imageGray, CV_RGB2GRAY);
        bool patternfound = findChessboardCorners(image, board_size, corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE +
            CALIB_CB_FAST_CHECK);
        if (!patternfound)
        {
            cout << "can not find chessboard corners!\n";
            continue;
            exit(1);
        }
        else
        {
            /*
            亚像素精确化 :迭代过程的终止条件可以是最大迭代次数CV_TERMCRIT_ITER类型,或者是设定的精度CV_TERMCRIT_EPS类型(或者是两
            者的组合)。终止条件的设置在极大程度上影响最终得到的亚像素值的精度。在此,指定为0.10,则求得的亚像素级精度为像素的十分
            之一
            */
            cornerSubPix(imageGray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
            //Size(11, 11)为搜索窗口的一半尺寸,Size(-1, -1)死区的一半尺寸,死区为不对搜索区的中央位置做求和运算的区域。/
            //它是用来避免自相关矩阵出现的某些可能的奇异性。当值为(-1,-1)表示没有死区。
            //TermCriteria为求角点的迭代过程的终止条件。即角点位置的确定,要么迭代数大于某个设定值,或者是精确懂达到某个设定值。
            //criteria可以是最大迭代数目,或者是设定的精确度,也可以是它们的组合。
            /* 绘制检测到的角点并保存 */
            Mat imageTemp = image.clone();
            for (int j = 0; j < corners.size(); j++)
            {
                circle(imageTemp, corners[j], 10, Scalar(0, 0, 255), 2, 8, 0);
            }
            string imageFileName;
            std::stringstream StrStm;
            StrStm << i + 1;
            StrStm >> imageFileName;
            imageFileName += "_corner.jpg";
            //保存提取角点的图像
            imwrite("F:\\biaoding\\" + imageFileName, imageTemp);
            cout << "Frame corner#" << i + 1 << "...end" << endl;

            count = count + corners.size();
            //将该角点压入角点序列堆栈
            corners_Seq.push_back(corners);
        }
        //将处理过的图像压入源图像堆栈
        image_Seq.push_back(image);
    }
    cout << "角点提取完成!\n";

    /************************************************************************
    摄像机定标
    *************************************************************************/
    cout << "开始定标………………" << endl;
    Size square_size = Size(80, 80);                                      /**** 实际测量得到的定标板上每个棋盘格的大小 ****/
    vector<vector<Point3f>>  object_Points;                               /**** 保存定标板上角点的三维坐标   ****/


    Mat image_points = Mat(1, count, CV_32FC2, Scalar::all(0));          /***** 保存提取的所有角点   *****/
    vector<int>  point_counts;                                           /***** 每幅图像中角点的数量 ****/
    Mat intrinsic_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0));          /***** 摄像机内参数矩阵    ****/
    Mat distortion_coeffs = Mat(1, 4, CV_32FC1, Scalar::all(0));         /* 摄像机的4个畸变系数:k1,k2,p1,p2 */
    vector<cv::Mat> rotation_vectors;                                    /* 每幅图像的旋转向量 */
    vector<cv::Mat> translation_vectors;                                 /* 每幅图像的平移向量 */

    /* 初始化定标板上角点的三维坐标 */
    for (int t = 0; t<image_count; t++)
    {
        vector<Point3f> tempPointSet;
        for (int i = 0; i<board_size.height; i++)
        {
            for (int j = 0; j<board_size.width; j++)
            {
                /* 假设定标板放在世界坐标系中z=0的平面上 */
                Point3f tempPoint;
                //在这里,坐标为位置的单位为:当棋盘格子为单位长度,则代表width、height为1,当为边长为20,代表width、height为20
                tempPoint.x =i*square_size.width;
                tempPoint.y =j*square_size.height;
                tempPoint.z = 0;
                tempPointSet.push_back(tempPoint);
            }
        }
        object_Points.push_back(tempPointSet);
    }

    /* 初始化每幅图像中的角点数量,这里我们假设每幅图像中都可以看到完整的定标板 */
    for (int i = 0; i< image_count; i++)
    {
        point_counts.push_back(board_size.width*board_size.height);
    }

    /* 开始定标 */
    calibrateCamera(object_Points, corners_Seq, image_size, intrinsic_matrix, distortion_coeffs, rotation_vectors, translation_vectors, 0);
    cout << "定标完成!\n";

    /************************************************************************
    对定标结果进行评价
    *************************************************************************/
    cout << "开始评价定标结果………………" << endl;
    double total_err = 0.0;                   /* 所有图像的平均误差的总和 */
    double err = 0.0;                        /* 每幅图像的平均误差 */
    vector<Point2f>  image_points2;             /****   保存重新计算得到的投影点    ****/

    cout << "每幅图像的定标误差:" << endl;
    fout << "每幅图像的定标误差:" << endl << endl;
    for (int i = 0; i<image_count; i++)
    {
        vector<Point3f> tempPointSet = object_Points[i];
        /****    通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点     ****/
        projectPoints(tempPointSet, rotation_vectors[i], translation_vectors[i], intrinsic_matrix, distortion_coeffs, image_points2);
        /* 计算新的投影点和旧的投影点之间的误差*/
        vector<Point2f> tempImagePoint = corners_Seq[i];
        Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);
        Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
        for (size_t i = 0; i != tempImagePoint.size(); i++)
        {
            image_points2Mat.at<Vec2f>(0, i) = Vec2f(image_points2[i].x, image_points2[i].y);
            tempImagePointMat.at<Vec2f>(0, i) = Vec2f(tempImagePoint[i].x, tempImagePoint[i].y);
        }
        err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
        total_err += err /= point_counts[i];
        cout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
        fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
    }
    cout << "总体平均误差:" << total_err / image_count << "像素" << endl;
    fout << "总体平均误差:" << total_err / image_count << "像素" << endl << endl;
    cout << "评价完成!" << endl;

    /************************************************************************
    保存定标结果
    *************************************************************************/
    cout << "开始保存定标结果………………" << endl;
    Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */

    fout << "相机内参数矩阵:" << endl;
    cout << "相机内参数矩阵:" << endl;
    fout << intrinsic_matrix << endl;
    cout << intrinsic_matrix << endl;
    fout << "畸变系数:\n";
    cout << "畸变系数:\n";
    fout << distortion_coeffs << endl;
    cout << distortion_coeffs << endl;
    for (int i = 0; i<image_count; i++)
    {
        fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
        fout << rotation_vectors[i] << endl;

        /* 将旋转向量转换为相对应的旋转矩阵 */
        Rodrigues(rotation_vectors[i], rotation_matrix);
        fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
        fout << rotation_matrix << endl;
        fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
        fout << translation_vectors[i] << endl;
    }
    cout << "完成保存" << endl;
    fout << endl;


    /************************************************************************
    显示定标结果
    *************************************************************************/
    Mat mapx = Mat(image_size, CV_32FC1);
    Mat mapy = Mat(image_size, CV_32FC1);
    Mat R = Mat::eye(3, 3, CV_32F);
    cout << "保存矫正图像" << endl;
    for (int i = 0; i != image_count; i++)
    {
        cout << "Frame #" << i + 1 << "..." << endl;
        //newCameraMatrix——输入的校正后的3X3摄像机矩阵(也可用cvStereoRectify()得出的3X4的左或右投影矩阵,其实系统会自动提取该
        //矩阵前三列的有用部分作为输入参数)注:!!无校正变换的相机仍用求得内参矩阵
        Mat newCameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
        //得到映射关系:R——输入的第一和第二相机坐标系之间的旋转矩阵,一般般无校正变换的相机,默认为单位矩阵
        // opencv中,remap与undistortion都是消除畸变的函数,undistortion在设置了一些参数后调用了remap函数,二者的算法实质是一样
        //的。由目标图像的坐标,找到对应的原始图像坐标,然后将其值复制到目标图像。大致思路是如此,由于图像大小和变换,需要插值或
        //近似的方法,如最邻近法、线性插值等
        initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, R, intrinsic_matrix, image_size, CV_32FC1, mapx, mapy);
        Mat t = image_Seq[i].clone();
        cv::remap(image_Seq[i], t, mapx, mapy, INTER_LINEAR);
        string imageFileName;
        std::stringstream StrStm;
        StrStm << i + 1;
        StrStm >> imageFileName;
        imageFileName += "_校正图像.jpg";
        imwrite("F:\\biaoding\\" + imageFileName, t);
    }
    cout << "保存结束" << endl;

    time0 = ((double)getTickCount() - time0) / getTickFrequency();
    cout << "标定用时:" << time0 << "秒" << endl;
    system("pause");

    /************************************************************************
    测试一张图片,用标定过参数去校正畸变,并记所用时间
    *************************************************************************/
    /*
    double time1 = static_cast<double>(getTickCount());
    if (1)
    {
        cout << "TestImage ..." << endl;
        //newCameraMatrix——输入的校正后的3X3摄像机矩阵(也可用cvStereoRectify()得出的3X4的左或右投影矩阵,其实系统会自动提取该
        //矩阵前三列的有用部分作为输入参数)
        Mat newCameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
        Mat testImage = imread("F:\\biaoding\\img03.jpg", 1);
        initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, R, intrinsic_matrix, image_size, CV_32FC1, mapx, mapy);
        Mat t = testImage.clone();
        cv::remap(testImage, t, mapx, mapy, INTER_LINEAR);

        imwrite("img3_TestOutput.jpg", t);
        cout << "保存结束" << endl;
    }
    time1 = ((double)getTickCount() - time1) / getTickFrequency();
    cout << "一张图片的畸变校正用时:" << time1 << "秒" << endl;
    */
    return 0;
}

//-----------------------------------OpenCV学习------------------------------------- 
//  程序名称:相机标定
//  2016年10月 Created by孙立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp> 
#include <iostream>
#include <string> 
using namespace cv;
using namespace std;
#include <iomanip>
#include <vector>

#include "CameraCalibrator.h"


int main()
{
    cv::namedWindow("Board Image");
    cv::Mat image;
    std::vector<std::string> filelist;

    // generate list of chessboard image filename
    for (int i = 1; i <= 20; i++) {

        std::stringstream str;
        str << "F:\\biaoding\\colar4\\\img" << std::setw(2) << std::setfill('0') << i << ".jpg";
        std::cout << str.str() << std::endl;

        filelist.push_back(str.str());
        image = cv::imread(str.str(), 0);
        cv::imshow("Board Image", image);

        cv::waitKey(100);
    }

    waitKey(0);
    // Create calibrator object
    CameraCalibrator cameraCalibrator;
    // add the corners from the chessboard
    cv::Size boardSize(9, 9);
    cameraCalibrator.addChessboardPoints(
        filelist,   // filenames of chessboard image
        boardSize, "Detected points");  // size of chessboard

    // calibrate the camera
    //  cameraCalibrator.setCalibrationFlag(true,true);
    cameraCalibrator.calibrate(image.size());

    // Image Undistortion
    image = cv::imread(filelist[6], 0);
    cv::Mat uImage = cameraCalibrator.remap(image);

    // display camera matrix
    cv::Mat cameraMatrix = cameraCalibrator.getCameraMatrix();
    std::cout << " Camera intrinsic: " << cameraMatrix.rows << "x" << cameraMatrix.cols << std::endl;
    std::cout << cameraMatrix.at<double>(0, 0) << " " << cameraMatrix.at<double>(0, 1) << " " << cameraMatrix.at<double>(0, 2) << std::endl;
    std::cout << cameraMatrix.at<double>(1, 0) << " " << cameraMatrix.at<double>(1, 1) << " " << cameraMatrix.at<double>(1, 2) << std::endl;
    std::cout << cameraMatrix.at<double>(2, 0) << " " << cameraMatrix.at<double>(2, 1) << " " << cameraMatrix.at<double>(2, 2) << std::endl;

    cv::namedWindow("Original Image");
    cv::imshow("Original Image", image);
    cv::namedWindow("Undistorted Image");
    cv::imshow("Undistorted Image", uImage);

    waitKey();

    return 0;
}

**CameraCalibrator.h:**


#ifndef CAMERACALIBRATOR_H
#define CAMERACALIBRATOR_H

#include <vector>
#include <iostream>

#include <opencv2/core/core.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include <opencv2/highgui/highgui.hpp>

class CameraCalibrator {

    // input points:
    // the points in world coordinates
    std::vector<std::vector<cv::Point3f> > objectPoints;
    // the point positions in pixels
    std::vector<std::vector<cv::Point2f> > imagePoints;
    // output Matrices
    cv::Mat cameraMatrix;
    cv::Mat distCoeffs;
    // flag to specify how calibration is done
    int flag;
    // used in image undistortion 
    cv::Mat map1, map2;
    bool mustInitUndistort;

public:
    CameraCalibrator() : flag(0), mustInitUndistort(true) {}

    // Open the chessboard images and extract corner points
    int addChessboardPoints(const std::vector<std::string>& filelist, cv::Size & boardSize, std::string windowName = "");
    // Add scene points and corresponding image points
    void addPoints(const std::vector<cv::Point2f>& imageCorners, const std::vector<cv::Point3f>& objectCorners);
    // Calibrate the camera
    double calibrate(const cv::Size imageSize);
    // Set the calibration flag
    void setCalibrationFlag(bool radial8CoeffEnabled = false, bool tangentialParamEnabled = false);
    // Remove distortion in an image (after calibration)
    cv::Mat remap(const cv::Mat &image);

    // Getters
    cv::Mat getCameraMatrix() { return cameraMatrix; }
    cv::Mat getDistCoeffs()   { return distCoeffs; }
};

#endif // CAMERACALIBRATOR_H

**CameraCalibrator.cpp:**
#include "CameraCalibrator.h"

// Open chessboard images and extract corner points
int CameraCalibrator::addChessboardPoints(
    const std::vector<std::string>& filelist, // list of filenames containing board images
    cv::Size & boardSize,                     // size of the board
    std::string windowName) {                 // name of window to display results
    // if null, no display shown
    // the points on the chessboard
    std::vector<cv::Point2f> imageCorners;
    std::vector<cv::Point3f> objectCorners;

    // 3D Scene Points:
    // Initialize the chessboard corners 
    // in the chessboard reference frame
    // The corners are at 3D location (X,Y,Z)= (i,j,0)
    for (int i = 0; i<boardSize.height; i++) {
        for (int j = 0; j<boardSize.width; j++) {

            objectCorners.push_back(cv::Point3f(i, j, 0.0f));
        }
    }

    // 2D Image points:
    cv::Mat image; // to contain chessboard image
    int successes = 0;
    // for all viewpoints
    for (int i = 0; i<filelist.size(); i++) {

        // Open the image
        image = cv::imread(filelist[i], 0);

        // Get the chessboard corners
        bool found = cv::findChessboardCorners(
            image, boardSize, imageCorners);

        // Get subpixel accuracy on the corners
        cv::cornerSubPix(image, imageCorners,
            cv::Size(5, 5),
            cv::Size(-1, -1),
            cv::TermCriteria(cv::TermCriteria::MAX_ITER +
            cv::TermCriteria::EPS,
            30,     // max number of iterations 
            0.1));     // min accuracy

        // If we have a good board, add it to our data
        if (imageCorners.size() == boardSize.area()) {

            // Add image and scene points from one view
            addPoints(imageCorners, objectCorners);
            successes++;
        }

        if (windowName.length()>0) {

            //Draw the corners
            cv::drawChessboardCorners(image, boardSize, imageCorners, found);
            cv::imshow(windowName, image);
            cv::waitKey(100);
        }
    }

    return successes;
}

// Add scene points and corresponding image points
void CameraCalibrator::addPoints(const std::vector<cv::Point2f>& imageCorners, const std::vector<cv::Point3f>& objectCorners) {

    // 2D image points from one view
    imagePoints.push_back(imageCorners);
    // corresponding 3D scene points
    objectPoints.push_back(objectCorners);
}

// Calibrate the camera
// returns the re-projection error
double CameraCalibrator::calibrate(const cv::Size imageSize)
{
    // undistorter must be reinitialized
    mustInitUndistort = true;

    //Output rotations and translations
    std::vector<cv::Mat> rvecs, tvecs;

    // start calibration
    return
        calibrateCamera(objectPoints, // the 3D points
        imagePoints,  // the image points
        imageSize,    // image size
        cameraMatrix, // output camera matrix
        distCoeffs,   // output distortion matrix
        rvecs, tvecs, // Rs, Ts 
        flag);        // set options
    //                  ,CV_CALIB_USE_INTRINSIC_GUESS);

}

// remove distortion in an image (after calibration)
cv::Mat CameraCalibrator::remap(const cv::Mat &image) {

    cv::Mat undistorted;

    if (mustInitUndistort) { // called once per calibration

        cv::initUndistortRectifyMap(
            cameraMatrix,  // computed camera matrix
            distCoeffs,    // computed distortion matrix
            cv::Mat(),     // optional rectification (none) 
            cv::Mat(),     // camera matrix to generate undistorted
            //          cv::Size(640,480),
            image.size(),  // size of undistorted
            CV_32FC1,      // type of output map
            map1, map2);   // the x and y mapping functions

        mustInitUndistort = false;
    }

    // Apply mapping functions
    cv::remap(image, undistorted, map1, map2,
        cv::INTER_LINEAR); // interpolation type

    return undistorted;
}


// Set the calibration options
// 8radialCoeffEnabled should be true if 8 radial coefficients are required (5 is default)
// tangentialParamEnabled should be true if tangeantial distortion is present
void CameraCalibrator::setCalibrationFlag(bool radial8CoeffEnabled, bool tangentialParamEnabled) {

    // Set the flag used in cv::calibrateCamera()
    flag = 0;
    if (!tangentialParamEnabled) flag += CV_CALIB_ZERO_TANGENT_DIST;
    if (radial8CoeffEnabled) flag += CV_CALIB_RATIONAL_MODEL;
}
//-----------------------------------OpenCV标定焊接图像------------------------------------- 
//  程序名称:OpenCV标定焊接图像,该程序根据DOS提示,一步步实现标定的自动化,求取内参,标定请在F盘创建“biaoding”用于储存采集的图像和结果
//  需要设置的参数: 需要提取的的图像数imageCount = 21,每个标定板图像角点数board_size = Size(9, 9),每个格子像素边长Size square_size = Size(80, 80);  
//  过程描述:提取图像并保存,提取各图像序列角点,角点亚像素精确化,摄像机标定畸变参数和内参,定标结果评价(保存结果在F:\\biaoding\\caliberation_result.txt),最后矫正所有图像到F:\\biaoding
//  所用IDE版本:        Visual Studio 2013    
//  开发所用OpenCV版本:        2.4.9    
//  2016年10月 Created by 孙立波    

//包含程序所依赖的头文件:为方便起见把经常用的头文件都写在这里(前三必须包含),也可以用#include "opencv.hpp"包含下面所有头文件
#include <opencv2\opencv.hpp>   
#include <iostream>
#include <string> 
#include <vector>
#include <iomanip>
#include <fstream>

#include "videoInput.h"
using namespace cv;
using namespace std;
//隐藏控制台窗口
//#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
void main()
{
    //********************************************************************************************
    //创建捕获对象
    videoInput VI;
    //可用摄像头,返回ID号的各路总个数,在此直接用0,因为采集卡插在0号ID
    int numID = VI.listDevices();

    int device1 = 0;
    //默认参数设置摄像头
    VI.setupDevice(device1, 640, 480, 1);//1代表采用混合路VI_COMPOSITE连接方式,即针对模拟摄像头,视频一路传送的为亮度信号和两个色差信号的混合信号
    /*VI.setupDevice(device1);*/
    //VI.setFormat(device1, VI_PAL_B);  //可设置视频格式,默认下为PAL
    //长宽尺寸
    int width = VI.getWidth(device1);
    int height = VI.getHeight(device1);
    int size = VI.getSize(device1);
    cout << "width=" << width << "\t" << "height=" << height << endl;
    cout << "framesize=" << size << endl;

    //声明显示图像
    Mat frame;

    frame.create(Size(width, height), CV_8UC3);

    //分配内存
    uchar* yourBuffer = (uchar*)malloc(size);

    /************************************************************************
    读取21张图像,存入内存F:\biaoding文件中
    *************************************************************************/
    cout << "开始提取21张标定板图像………………" << endl;
    int imageCount = 21;
    int key = 0;
    int count1 = 0;
    for (int i = 0; i != imageCount; i++)
    {
        cout << "Frame#" << i + 1 << "..." << endl;
        std::stringstream StrStm;
        //为了将i转化为字符型,用StrStm做中介
        string imageFileName;
        StrStm << i + 1;
        StrStm >> imageFileName;
        imageFileName += ".jpg";

        //system("pause");//用waitKey必须有GUI窗口生成才行

        cout << "按Enter开始抽取图像,进入后可按q或者ESC键重新抽取图像,若按Enter键表明这帧图像被存入文件夹中" << endl;
        //key = waitKey();


        int flag = 1;
        while (flag)
        {
            VI.getPixels(device1, yourBuffer, false, false);
            frame.data = (uchar*)yourBuffer;
            waitKey(50);
            //左右翻转
            flip(frame, frame, 0);//0竖直翻转1水平翻转,-1垂直水平翻转

            Mat image0 = frame;//抽取到的临时图像数据并显示出来

            imshow("显示抓取图像", image0);//显示是否符合要求
            int key2;
            key2 = waitKey();
            if (key2 == 13)//按Enter键存取图像到F盘biaoding文件区
            {
                cout << "提取标定板图像成功!………………" << endl;
                std::stringstream str;
                str << "F:\\biaoding\\img" << std::setw(2) << std::setfill('0') << i + 1 << ".jpg";
                std::cout << "提取的图像保存路径及文件名" << str.str() << endl;
                imwrite(str.str(), image0);//保存的是从硬件得到的源格式图像
                flag = 0;
                count1 += 1;//已经得到的标定图像计数总数
            }
            else
            if (key2 == 113 || key2 == 27)//按Q或者ESC键从新获取一阵图像
                cout << "这次提取的标定板图像不成功!重新提取!!!!………………" << endl;
        };//分号很重要!!!!!!

    }
    if (count1 == imageCount)
    {
        cout << "***********************………………" << endl;
        cout << "***********************………………" << endl;
        cout << "下面开始标定图像...................." << endl;
        count1 = 0;
    }

    system("pause");//用waitKey必须有GUI窗口生成才行
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值