既然已经能够找到了标定点,那么下边的工作就是使用标定结果了。【这本书在这里的内容组织让人莫名其妙】但是通过阅读代码能够很方便地串起来。

/*------------------------------------------------------------------------------------------*\
This file contains material supporting chapter 11 of the book:
OpenCV3 Computer Vision Application Programming Cookbook
Third Edition
by Robert Laganiere, Packt Publishing, 2016.
This program is free software; permission is hereby granted to use, copy, modify,
and distribute this source code, or portions thereof, for any purpose, without fee,
subject to the restriction that the copyright notice may not be removed
or altered from any source or altered source distribution.
The software is released on an as-is basis and without any warranties of any kind.
In particular, the software is not guaranteed to be fault-tolerant or free from failure.
The author disclaims all warranties with regard to this software, any use,
and any consequent failure, is purely the responsibility of the user.
Copyright (C) 2016 Robert Laganiere, www.laganiere.name
\*------------------------------------------------------------------------------------------*/
#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/features2d.hpp>
#include "CameraCalibrator.h"
int main()
{
    cv::Mat image;
    std::vector<std::string> filelist;
    // 按照规则读入27张图片
    // 名称为 chessboard01 to chessboard27 
    for (int i=1; i<=27; i++) {
        std::stringstream str;
        str << "E:/template/calibrateImages/calibrate" << std::setw(2) << std::setfill('0') << i << ".bmp";
        std::cout << str.str() << std::endl;
        filelist.push_back(str.str());
        image= cv::imread(str.str(),0);
    }
    // 创建Calibrator类
    CameraCalibrator cameraCalibrator;
    // 根据图片实际情况定下boardSize
    cv::Size boardSize(8,6);
    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 = cv::imread(filelist[1],0);
    cv::Size newSize(static_cast<int>(image.cols*1.5), static_cast<int>(image.rows*1.5));
    cv::Mat uImage= cameraCalibrator.remap(image, newSize);
    // 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);
    // Store everything in a xml file
    cv::FileStorage fs("calib.xml", cv::FileStorage::WRITE);
    fs << "Intrinsic" << cameraMatrix;
    fs << "Distortion" << cameraCalibrator.getDistCoeffs();
    cv::waitKey();
    return 0;
}
下面是类库:
/*------------------------------------------------------------------------------------------*\
This file contains material supporting chapter 11 of the book:
OpenCV3 Computer Vision Application Programming Cookbook
Third Edition
by Robert Laganiere, Packt Publishing, 2016.
This program is free software; permission is hereby granted to use, copy, modify,
and distribute this source code, or portions thereof, for any purpose, without fee,
subject to the restriction that the copyright notice may not be removed
or altered from any source or altered source distribution.
The software is released on an as-is basis and without any warranties of any kind.
In particular, the software is not guaranteed to be fault-tolerant or free from failure.
The author disclaims all warranties with regard to this software, any use,
and any consequent failure, is purely the responsibility of the user.
Copyright (C) 2016 Robert Laganiere, www.laganiere.name
\*------------------------------------------------------------------------------------------*/
#ifndef CAMERACALIBRATOR_H
#define CAMERACALIBRATOR_H
#include <vector>
#include <iostream>
#include <opencv2/core.hpp>
#include "opencv2/imgproc.hpp"
#include "opencv2/calib3d.hpp"
#include <opencv2/highgui.hpp>
class CameraCalibrator {
    // 输入点:  
    // 世界坐标系中的点 
    //(每个正方形为一个单位) 
    std::vector<std::vector<cv::Point3f> > objectPoints;
    // 点在图像中的位置(以像素为单位) 
    std::vector<std::vector<cv::Point2f> > imagePoints;
    // 输出矩阵 
    cv::Mat cameraMatrix;
    cv::Mat distCoeffs;
    // 指定标定方式的标志
    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, cv::Size &outputSize = cv::Size(-1, -1));
    // Getters
    cv::Mat getCameraMatrix() { return cameraMatrix; }
    cv::Mat getDistCoeffs()   { return distCoeffs; }
};
#endif // CAMERACALIBRATOR_H

/*------------------------------------------------------------------------------------------*\
This file contains material supporting chapter 11 of the book:
OpenCV3 Computer Vision Application Programming Cookbook
Third Edition
by Robert Laganiere, Packt Publishing, 2016.
This program is free software; permission is hereby granted to use, copy, modify,
and distribute this source code, or portions thereof, for any purpose, without fee,
subject to the restriction that the copyright notice may not be removed
or altered from any source or altered source distribution.
The software is released on an as-is basis and without any warranties of any kind.
In particular, the software is not guaranteed to be fault-tolerant or free from failure.
The author disclaims all warranties with regard to this software, any use,
and any consequent failure, is purely the responsibility of the user.
Copyright (C) 2016 Robert Laganiere, www.laganiere.name
\*------------------------------------------------------------------------------------------*/
#include "stdafx.h"
#include "CameraCalibrator.h"
// 打开棋盘图像,提取角点 
int CameraCalibrator::addChessboardPoints(
         const std::vector<std::string>& filelist, // 文件名列表
         cv::Size & boardSize,                     // 标定面板的大小 
         std::string windowName) {                 // name of window to display results
                                                   // if null, no display shown
    // 棋盘上的角点 
    std::vector<cv::Point2f> imageCorners;
    std::vector<cv::Point3f> objectCorners;
    // 场景中的三维点: 
    // 在棋盘坐标系中,初始化棋盘中的角点 
    // 角点的三维坐标(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));
        }
    }
    // 图像上的二维点:
    cv::Mat image; // 用于存储棋盘图像 
    int successes = 0;
    // 处理所有视角 
    for (int i=0; i<filelist.size(); i++) {
        // 打开图像
        image = cv::imread(filelist[i],0);
        // 取得棋盘中的角点
        bool found = cv::findChessboardCorners(image,         // 包含棋盘图案的图像
                                               boardSize,     // 图案的大小
                                               imageCorners); // 检测到角点的列表
        // 取得角点上的亚像素级精度
        if (found) {
            cv::cornerSubPix(image, imageCorners,
                cv::Size(5, 5), // 搜索窗口的半径 
                cv::Size(-1, -1),
                cv::TermCriteria(cv::TermCriteria::MAX_ITER +
                    cv::TermCriteria::EPS,
                    30,        // 最大迭代次数 
                    0.1));  // 最小精度 
            // 如果棋盘是完好的,就把它加入结果  
            if (imageCorners.size() == boardSize.area()) {
                // 加入从同一个视角得到的图像和场景点 
                addPoints(imageCorners, objectCorners);
                successes++;
            }
        }
        if (windowName.length()>0 && imageCorners.size() == boardSize.area()) {
        
            //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);
}
// 标定相机 
// 返回重投影误差 
double CameraCalibrator::calibrate(const cv::Size imageSize)
{
    mustInitUndistort= true;
    // 输出旋转量和平移量 
    std::vector<cv::Mat> rvecs, tvecs;
    // 开始标定
    return 
     calibrateCamera(objectPoints, // 三维点 
                    imagePoints,   // 图像点 
                    imageSize,     // 图像尺寸 
                    cameraMatrix,  // 输出相机矩阵 
                    distCoeffs,    // 输出畸变矩阵 
                    rvecs, tvecs,  // Rs、Ts 
                    flag);         // 设置选项 
//                    ,CV_CALIB_USE_INTRINSIC_GUESS);
}
// 去除图像中的畸变(标定后) 
cv::Mat CameraCalibrator::remap(const cv::Mat &image, cv::Size &outputSize) {
    cv::Mat undistorted;
    if (outputSize.height == -1)
        outputSize = image.size();
    if (mustInitUndistort) { // 每个标定过程调用一次  
    
        cv::initUndistortRectifyMap(
            cameraMatrix,  // 计算得到的相机矩阵 
            distCoeffs,    // 计算得到的畸变矩阵 
            cv::Mat(),     // 可选矫正项(无) 
            cv::Mat(),     // 生成无畸变的相机矩阵
            outputSize,    // 无畸变图像的尺寸
            CV_32FC1,      // 输出图片的类型 
            map1, map2);   // x 和 y 映射功能 
        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;
}
一发3连之后,倒是的确能够获得标定的结果,看上去也不错,问题就是缺乏量化的东西。

效果似乎是更好一些:
从边界上能够看出被拉动了好多,但是实际上不认真分析的话还真看不出来。
这系列操作的目的,是获得关于相机的参数,比如我这里这个相机,获得的是:
<?xml version="1.0"?>
<opencv_storage>
<Intrinsic type_id="opencv-matrix">
  <rows>3</rows>
  <cols>3</cols>
  <dt>d</dt>
  <data>
    1.3589305122261344e+003 0. 5.7505355544729957e+002 
    0. 1.3565816672769690e+003 6.0423226535731465e+002 
    0. 0. 1.
   </data>
</Intrinsic>

<Distortion type_id="opencv-matrix">
  <rows>1</rows>
  <cols>14</cols>
  <dt>d</dt>
  <data>
    9.5113243912423840e+001 1.4262144540955842e+003
    5.2119492051277685e-003 2.8847713358900241e-003
    1.2859720255043484e+002 9.5182218776001392e+001
    1.4741397414456521e+003 6.8332022963370434e+002 0. 0. 0. 0. 0. 0.</data></Distortion>
</opencv_storage>

我重新计算了一次(去掉了几张图片),差距好像有些大。
<?xml version="1.0"?>
<opencv_storage>
<Intrinsic type_id="opencv-matrix">
  <rows>3</rows>
  <cols>3</cols>
  <dt>d</dt>
  <data>
    1.3505709175120112e+003 0. 5.8070986392008831e+002 
    0. 1.3474004248060101e+003 5.9253033568240335e+002 
    0. 0. 1.
  </data>
</Intrinsic>
<Distortion type_id="opencv-matrix">
  <rows>1</rows>
  <cols>14</cols>
  <dt>d</dt>
  <data>
    4.7269890458124472e+001 1.4478281139927145e+002
    5.0572001753860724e-003 2.7283262006574539e-003
    1.3271367851070463e+002 4.7547115235593054e+001
    1.6768734113490575e+002 1.8621811777918711e+002 0. 0. 0. 0. 0. 0.</data></Distortion>
</opencv_storage>

第一个矩阵,显然是3X3的内参矩阵;第二个矩阵的内容是输入的点,以相机为坐标系中心。它有一个旋转向量(3X3)和一个平移向量(3X1)组成。
大概对应的是这个样子:
或者文档中的表示方法:
这样,这里(X, Y, Z)是一个点的世界坐标,(u, v)是点投影在图像平面的坐标,以像素为单位。A被称作摄像机矩阵,或者内参数矩阵。(cx, cy)是基准点(通常在图像的中心),fx, fy是以像素为单位的焦距。所以如果因为某些因素对来自于摄像机的一幅图像升采样或者降采样,所有这些参数(fx, fy, cx和cy)都将被缩放(乘或者除)同样的尺度。内参数矩阵不依赖场景的视图,一旦计算出,可以被重复使用(只要焦距固定)。旋转-平移矩阵[R|t]被称作外参数矩阵,它用来描述相机相对于一个固定场景的运动,或者相反,物体围绕相机的的刚性运动。也就是[R|t]将点(X, Y, Z)的坐标变换到某个坐标系,这个坐标系相对于摄像机来说是固定不变的。上面的变换等价与下面的形式(z≠0):

这些图像为1280*1024,所以这里得到cx,cy = 580,590,算是比较靠近图像中心。

附件列表

基于OpenCV做“三维重建”(2)--封装标定过程的更多相关文章

  1. 基于OpenCV做“三维重建”(1)--找到并绘制棋盘

    <OpenCV计算机视觉编程攻略(第3版)>这套书已经出到第3版了,如果你非要我说这本书有多好,我说不出来:只是很多我第一手的例子都是来源于这本书的-相比较OpenCV官方提供的代码,这本 ...

  2. 基于OpenCV做“三维重建”(3)--相机参数矩阵

    通过前面的相机标定,我们能够获得一些参数模型.但是这些相机的参数矩阵到底是什么意思?怎样才能够判断是否正确?误差都会来自哪里?这里就必须要通过具体实验来加深认识.采集带相机参数的图片具有一定难度,幸好 ...

  3. 基于OpenCV做“三维重建”(0)-- OpenCV3.2+VIZ6.3.0在vs2012下的编译和使用

    一.问题提出         ViZ对于显示3维的效果图来说,非常有帮助:我在使用OpenCV进行双目测距的过程中,有一些参数希望能够通过可视化的方法显示出来,所以参考了这方面相关的资料.做了一些实验 ...

  4. 基于OpenCV做“三维重建”(4)--相机姿态还原和实现三维重建

    v当我们构建成功了viz,就可以使用3维效果给我们提供的便利,进一步进行一些3维的操作. 在这个动画中,注意图片后面的那个黑线,对应的是相机的位置. /*----------------------- ...

  5. 机器视觉学习笔记(5)——基于OpenCV的单目摄像机标定

    本文CameraCalibrator类源代码来自于OpenCV2 计算机视觉编程手册(Robert Laganiere 著 张静 译) 强烈建议阅读机器视觉学习笔记(4)--单目摄像机标定参数说明之后 ...

  6. 基于OpenCV的双目视觉匹配测距系统

    刚读研究生的时候,自己导师研究的方向是双目视觉,于是让自己研究OpenCV,折腾了几个月,算法上没啥突破,不过工程上还是折腾出了一个能用的小玩意,基于OpenCV实现了相机的标定.双目视觉图片的矫正. ...

  7. 基于OpenCV单目相机的快速标定--源码、工程、实现过程

    相机的标定是所有人走进视觉世界需要做的第一件事,辣么多的视觉标定原理解释你可以随便在网上找到,这里只讲到底如何去实现,也算是给刚入门的朋友做个简单的分享. 1.单目相机标定的工程源码 首先请到同性交友 ...

  8. 相机标定过程(opencv) + matlab参数导入opencv + matlab标定和矫正

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 辛苦原创所得,转载请注明出处 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ...

  9. Pull Request的过程、基于git做的协同开发、git常见的一些命令、git实现代码的review、git实现版本的管理、gitlab、GitHub上为开源项目贡献代码

    前言: Pull Request的流程 1.fork 首先是找到自己想要pull request的项目, 然后点击fork按钮,此时就会在你的仓库中多出来一个仓库,格式是:自己的账户名/想要pull ...

随机推荐

  1. Centos7双网卡绑定配置 bonding

    bonding的七种工作模式: bonding技术提供了七种工作模式,在使用的时候需要指定,每种有各自的优缺点,我们使用的是 mode=4 balance-rr (mode=0) 默认, 有高可用 ( ...

  2. 是否能设计一种DNN的特定网络结构来改善DNN,使得其学习起来更加高效

    小结: 1. 是否能设计一种DNN的特定网络结构来改善DNN,使得其学习起来更加高效 https://mp.weixin.qq.com/s/lF_WLAn6JyQqf10076hsjA Deep &a ...

  3. (转载)python调用shell命令之os 、commands、subprocess

    linux系统下进入python交互式环境: 一.os 模块 1.1.os模块的exec方法簇: python交互界面中: In [1]: import os In [2]: os.exec os.e ...

  4. hadoop学习笔记--找到执行hadoop的入口

    参与个hadoop项目,之前没搞过,赶紧学习: 照葫芦画瓢,得到代码是hdfs2local.sh脚本和LiaoNingFilter.jar包,迫不及待用jd-gui打开jar包,搜索到main(在MA ...

  5. ES6 Symbol数据类型和set-map 数据结构

    Symbol数据类型 ES6新加的数据类型,提供一个独一无二的值 { let a1 = Symbol() ;let a2 = Symbol() } //声明 { let a3 = Symbol.for ...

  6. Hibernate处理事务并发问题

    在Hibernate中设置事务的隔离级别.<property name="hibernate.connection.isolation">2</property& ...

  7. 马拉车算法,mannacher查找最长回文子串

    作用: 在线性时间内找到一个字符串的最大回文子串 原理: 奇偶变换:为处理字符串方便,现将给定的任意字符串进行处理,使所有可能的奇数/偶数长度的回文子串都转换成了奇数长度. 具体就是在每个字符的两边都 ...

  8. 001-zookeeper 简介-paxos算法,zk简介,特点

    一.概述 大数据体系概述 1.1.什么是zookeeper 是Google的Chubby一个开源的实现,是Hadoop的分布式协调服务 它包含一个简单的原语集,分布式应用程序可以基于他实现同步服务,配 ...

  9. JavaScript 的if语句和==的判断

    一. if(xx)的判断 JavaScript 遇到预期为布尔值的地方(比如if语句的条件部分),就会将非布尔值的参数自动转换为布尔值.系统内部会自动调用Boolean函数. 1.当if括号里面的表达 ...

  10. 2019-oo-第二次总结

    这一单元是关于模拟电梯运行,考验多线程的一个单元,难度由简入入深,从多线程单部电梯,到优化,再到多线程多部电梯,难度一次次的提高. 一.多线程单部电梯(傻瓜调度) 1.设计策略 这一次我只额外的开了一 ...