【opencv】相机模型与相机标定

小孔相机模型

在计算机视觉中,最常用的相机模型就是小孔模型(小孔成像模型),它将相机的透镜组简化为一个小孔,光线透过小孔在小孔后方的像面上成像,如下图所示。 
这里写图片描述        这里写图片描述
由上图可知,小孔模型成的是倒像,为了表述与研究的方便,我们常常将像面至于小孔之前,且到小孔的距离仍然是焦距f,这样的模型与原来的小孔模型是等价的,只不过成的是正像,符合人的直观感受。在这种情况下,往往将小孔称作光心(Optical Center)。 
 
小孔模型是一种理想相机模型,没有考虑实际相机中存在的场曲、畸变等问题。在实际使用时,这些问题可以通过在标定的过程中引入畸变参数解决,所以小孔模型仍然是目前最广泛使用的相机模型。

坐标系

为了用数学研究SfM,我们需要坐标系。在SfM中主要有两类坐标系,一类为相机坐标系,一类为世界坐标系。在本系列中,所以坐标系均为右手坐标系。 
相机坐标系以相机的光心(小孔)作为原点,X轴为水平方向,Y轴为竖直方向,Z轴指向相机所观察的方向。 
世界坐标系的原点可以任意选择,与相机的具体位置无关。 
相机坐标系与世界坐标系的关系

内参矩阵

设空间中有一点P,若世界坐标系与相机坐标系重合,则该点在空间中的坐标为(X, Y, Z),其中Z为该点到相机光心的垂直距离。设该点在像面上的像为点p,像素坐标为(x, y),那么(X, Y, Z)和(x, y)有什么关系呢? 
这里写图片描述 由上图可知,这是一个简单的相似三角形关系,从而得到 x=fX/Z,   y=fY/Z



但是,图像的像素坐标系原点在左上角,而上面公式假定原点在图像中心,为了处理这一偏移,设光心在图像上对应的像素坐标为 (cx,cy) ,则 
x=fX/Z+cx,   y=fY/Z+cy

将以上关系表示为矩阵形式,有 
其中,将矩阵 

称为内参矩阵,因为它只和相机自身的内部参数有关(焦距,光心位置)。

外参矩阵

一般情况下,世界坐标系和相机坐标系不重合,这时,世界坐标系中的某一点P要投影到像面上时,先要将该点的坐标转换到相机坐标系下。设P在世界坐标系中的坐标为X,P到光心的垂直距离为s(即上文中的Z),在像面上的坐标为x,世界坐标系与相机坐标系之间的相对旋转为矩阵R(R是一个三行三列的旋转矩阵),相对位移为向量T(三行一列),则 

sx=K[RX+T]

其中 RX+T  即为P在相机坐标系下的坐标,使用齐次坐标改写上式,有 
sx=K[RT][X1]

其中 [RT] 是一个三行四列的矩阵,称为外参矩阵,它和相机的参数无关,只与相机在世界坐标系中的位置有关。 
这里写图片描述

相机的标定

相机的标定,即为通过某个已知的目标,求取相机内参矩阵的过程。最常用的标定目标就是棋盘格。用相机对棋盘格从不同角度拍摄多张照片,然后将这些照片导入标定程序或算法,即可自动求出相机的内参。 

相机标定:每个摄像机都有唯一的参数,例如,焦点,主点以及透镜的畸变模型。查找摄像机内参数差的过程为摄像机的标定;对基于增强现实的应用来讲,对摄像机标定很重要,因为它将透视变换和透镜的畸变都反映在输出图像上。

为了让用户在增强现实应用中获得更佳的体验,应该用相同的透视投影来增强物体的可视化效果;标定摄像机需要特殊的模式图像,例如:棋盘板或具有白色背景的黑圆圈,被标定的摄像机需要从不同的角度对特殊模式图像拍摄 10-15张照片,然后通过标定算法来找到最优的摄像机内部参数和畸变向量

我们用opencv的例程来进行标定,在你的opencv目录下 
sources\samples\cpp\tutorial_code\calib3d\camera_calibration 
有3个文件 :

camera_calibration.cpp 
VID5.xml 
in_VID5.xml

第一个是标定程序的源代码。 
第二个是配置文件,你可以更改标定图片获取的方式以及标定板的一些参数。 
第三个里面可以修改标定图片序列的文件名。

前提准备: 
标定板。这里我制作好了一个,按照原比例打印出来,然后固定在一个硬板子上。 
这里写图片描述

接下来就可以开始了…… 
我们这里只介绍从摄像头获取标定图片的方式。其他方式可以按照说明更改VID5.xml自行实现。

第一步,新建一个工程,将camera_calibration.cpp文件的源码拷贝进去。 
第二步,将VID5.xml拷贝到工程目录下面。 
第三步,编辑VID5.xml,将Input标签里的内容改为待标定相机的ID,我的是”1”,记得加上引号。 
第四步,编译并运行程序。 “

下面是我的VID5.xml文件

<?xml version="1.0"?>
<opencv_storage>
<Settings>
  <!-- Number of inner corners per a item row and column. (square, circle) -->
  <BoardSize_Width> 9</BoardSize_Width>
  <BoardSize_Height>6</BoardSize_Height>

  <!-- The size of a square in some user defined metric system (pixel, millimeter)-->
  <Square_Size>50</Square_Size>

  <!-- The type of input used for camera calibration. One of: CHESSBOARD CIRCLES_GRID ASYMMETRIC_CIRCLES_GRID -->
  <Calibrate_Pattern>"CHESSBOARD"</Calibrate_Pattern>

  <!-- The input to use for calibration. 
        To use an input camera -> give the ID of the camera, like "1"
        To use an input video  -> give the path of the input video, like "/tmp/x.avi"
        To use an image list   -> give the path to the XML or YAML file containing the list of the images, like "/tmp/circles_list.xml"
        -->
  <Input>"1"</Input>
  <!--  If true (non-zero) we flip the input images around the horizontal axis.-->
  <Input_FlipAroundHorizontalAxis>0</Input_FlipAroundHorizontalAxis>

  <!-- Time delay between frames in case of camera. -->
  <Input_Delay>100</Input_Delay>    

  <!-- How many frames to use, for calibration. -->
  <Calibrate_NrOfFrameToUse>25</Calibrate_NrOfFrameToUse>
  <!-- Consider only fy as a free parameter, the ratio fx/fy stays the same as in the input cameraMatrix. 
       Use or not setting. 0 - False Non-Zero - True-->
  <Calibrate_FixAspectRatio> 1 </Calibrate_FixAspectRatio>
  <!-- If true (non-zero) tangential distortion coefficients  are set to zeros and stay zero.-->
  <Calibrate_AssumeZeroTangentialDistortion>1</Calibrate_AssumeZeroTangentialDistortion>
  <!-- If true (non-zero) the principal point is not changed during the global optimization.-->
  <Calibrate_FixPrincipalPointAtTheCenter> 1 </Calibrate_FixPrincipalPointAtTheCenter>

  <!-- The name of the output log file. -->
  <Write_outputFileName>"out_camera_data.xml"</Write_outputFileName>
  <!-- If true (non-zero) we write to the output file the feature points.-->
  <Write_DetectedFeaturePoints>1</Write_DetectedFeaturePoints>
  <!-- If true (non-zero) we write to the output file the extrinsic camera parameters.-->
  <Write_extrinsicParameters>1</Write_extrinsicParameters>
  <!-- If true (non-zero) we show after calibration the undistorted images.-->
  <Show_UndistortedImage>1</Show_UndistortedImage>

</Settings>
</opencv_storage>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

标定结果: 
标定前 
标定后

前后的差异可以看清了吧

值得一提的是工程目录下生成了一个out_camera_data.xml文件,里面记录摄像头标定的一些参数,以后可以直接使用。我们用它略去标定的步骤,直接校正摄像机,这样标定好一次就可以一直使用了。 
将生成的out_camera_data.xml放到你的工程目录下就可以使用了。 
下面是一个简单的调用摄像头并用已有的参数进行标定的程序,可以直接使用。

#include <opencv2/opencv.hpp>
#include <opencv2/calib3d/calib3d.hpp>
using namespace std;
using namespace cv;
int main(){
    VideoCapture capture;
    capture.open(1);
    while (1){
        Mat frame;
        capture.read(frame);
        Mat undistort_frame = frame.clone();
        Mat camera_matrix = Mat(3, 3, CV_32FC1);
        Mat distortion_coefficients;


        //导入相机内参和畸变系数矩阵
        FileStorage file_storage("out_camera_data.xml", FileStorage::READ);
        file_storage["Camera_Matrix"] >> camera_matrix;
        file_storage["Distortion_Coefficients"] >> distortion_coefficients;
        file_storage.release();

        //矫正
        undistort(frame, undistort_frame, camera_matrix, distortion_coefficients);

        imshow("img", frame);
        imshow("undistort", undistort_frame);

        char c = waitKey(1);
        if (c == 'q' || c == 27) {
            return 0;
        }
        else if (c == ' '){
            waitKey();
        }
    }
from:http://lib.csdn.net/article/opencv/38356
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值