单目相机标定C++与Matlab实现

 

一、相机标定的原理

相机标定的目的?

找出三维空间与二维图像的对应关系。

1.坐标系

在这里总共涉及到四个坐标系的变化。这四个坐标系分别是:(1)像素坐标系;(2)成像坐标系;(3)相机坐标系;(4)世界坐标系。

1.像素坐标系

像素坐标系是一个直角坐标系,其坐标轴为(O_{0}-uv),其定义方式是:原点位于图像的左上角,u轴向右与x轴平行,v轴向下与y轴平行,其反映了相机CCD/CMOS芯片中像素的排列情况,在像素坐标系中单位是像素。像素坐标系与成像平面之间,相差了一个缩放和一个原点的平移

2.成像坐标系

成像坐标系是用来表示图像的物理位置的坐标系,定义此坐标轴为(O_{1}-XY),则此坐标系中的坐标(x,y)(x,y)表示图像上点的位置坐标。(x,y)对应的成像坐标系中的物理坐标的单位是毫米

3.相机坐标系

相机坐标系是一个三维直角坐标系,其坐标轴为(O_{c}-X_{c}Y_{c}Z_{c}),原点位于镜头光心处,其中Z_{c}轴称为相机的光轴,垂直于图像平面,X_{c}轴平行于成像坐标系的X轴,Y_{c}轴平行于成像坐标系的Y轴。

4.世界坐标系

世界坐标系作为一个基准,选择世界坐标系没有固定的方式,具体情况具体来考虑。其可以用来描述待测物体与相机的相对位置关系。其坐标轴为(O-X_{w}Y_{w}C_{w})

2.坐标系与坐标系之间的关系

1.世界坐标系与相机坐标系

设在相机坐标系下有一个点P,它的坐标为(X_{c},Y_{c},Z_{c}){_{}}^{T}P在世界坐标系下对应的坐标为(X_{w},Y_{w},Z_{w}){_{}}^{T}

因此,世界坐标系与相机坐标系中的坐标存在如下的关系:

\begin{bmatrix} X_{c} \\ Y_{c} \\ Z_{c} \\ 1 \end{bmatrix}=\begin{bmatrix}R& t\\ 0^{T}&1 \end{bmatrix}\begin{bmatrix} X_{w} \\ Y_{w} \\ Z_{w} \\ 1 \end{bmatrix}

其中,R是旋转矩阵,为3x3的正交单位矩阵;t是一个平移矩阵,t=(t_{1},t_{2},t_{3})^{T}

同时这里用了一个数学技巧(《视觉SLAM14讲》第43页):我们在一个三维向量的末尾添加1,将其变成了四维向量,称为齐次坐标。

其中\begin{bmatrix}R& t\\ 0^{T}&1 \end{bmatrix}称为外参数矩阵。

2.像素坐标系与成像坐标系

在二维成像平面坐标系中,相机光轴与图像平面的交点即为原点O_{1},该点称为图像的主点,如果我们不去考虑畸变,图像的主点就是图像的中心点,但是由于相机系统加工,外力作用等原因会产生一定的偏移。设主点O_{1}在像素坐标系中的坐标为(u_{0},v_{0}),则像素坐标系与成像坐标系对应关系如下:

\begin{bmatrix}u \\ v \\ 1 \end{bmatrix}=\begin{bmatrix}1/dx& 0&u_{0}\\ 0&1/dy&v_{0}\\0&0&1 \end{bmatrix}\begin{bmatrix} x\\ y\\ 1\end{bmatrix}

3.线性模型

相机的线性模型,即是设空间中的任意一点在图像上所成的像可以近似认为是通过小孔成像原理在像平面成像的,所以又称作针孔模型。用简单的针孔相机模型来对这种映射关系进行建模。同时,由于相机镜头上的透镜的存在,使得光线投影到成像平面的过程会产生畸变

按照这个模型,记空间中的一点P在相机坐标系中的坐标为(X_{c},Y_{c},Z_{c}),在成像平面坐标系中的坐标为(x,y),相机的焦距为f,则根据比例关系:

x=f*(x_{c}/z_{c})

y=f*(y_{c}/z_{c})

可以得到投影矩阵:

Z_{c}\begin{bmatrix}x \\ y \\ 1 \end{bmatrix}=\begin{bmatrix}f& 0&0&0\\ 0&f&0&0\\0&0&1&0 \end{bmatrix}\begin{bmatrix} X_{c}\\ Y_{c}\\ Z_{c}\\1\end{bmatrix}

根据世界坐标系与相机坐标系的坐标存在如下的关系:

\begin{bmatrix} X_{c} \\ Y_{c} \\ Z_{c} \\ 1 \end{bmatrix}=\begin{bmatrix}R& t\\ 0^{T}&1 \end{bmatrix}\begin{bmatrix} X_{w} \\ Y_{w} \\ Z_{w} \\ 1 \end{bmatrix}

可以推出

Z_{c}\begin{bmatrix}x \\ y \\ 1 \end{bmatrix}=\begin{bmatrix}f& 0&0&0\\ 0&f&0&0\\0&0&1&0 \end{bmatrix}\begin{bmatrix}R& t\\ 0^{T}&1 \end{bmatrix}\begin{bmatrix} X_{w} \\ Y_{w} \\ Z_{w} \\ 1 \end{bmatrix}

再根据像素坐标系与成像坐标系存在如下关系:

\begin{bmatrix}u \\ v \\ 1 \end{bmatrix}=\begin{bmatrix}1/dx& 0&u_{0}\\ 0&1/dy&v_{0}\\0&0&1 \end{bmatrix}\begin{bmatrix} x\\ y\\ 1\end{bmatrix}

可以推出

Z_{c}\begin{bmatrix}u \\ v \\ 1 \end{bmatrix}=Z_{c}\begin{bmatrix}1/dx& 0&u_{0}\\ 0&1/dy&v_{0}\\0&0&1 \end{bmatrix}\begin{bmatrix} x\\ y\\ 1\end{bmatrix}

=\begin{bmatrix}1/dx& 0&u_{0}\\ 0&1/dy&v_{0}\\0&0&1 \end{bmatrix}\begin{bmatrix}f& 0&0&0\\ 0&f&0&0\\0&0&1&0 \end{bmatrix}\begin{bmatrix}R& t\\ 0^{T}&1 \end{bmatrix}\begin{bmatrix} X_{w} \\ Y_{w} \\ Z_{w} \\ 1 \end{bmatrix}

f_{u}=f/dxf_{v}=f/dy

K=\begin{bmatrix}f/dx& 0&u_{0}\\ 0&f/dy&v_{0}\\0&0&1 \end{bmatrix},则有

Z_{c}\begin{bmatrix}u\\ v\\1\end{bmatrix}=K\begin{bmatrix}R& t\\ 0^{T}&1 \end{bmatrix}\begin{bmatrix} X_{w} \\ Y_{w} \\ Z_{w} \\ 1 \end{bmatrix}=KTP_{w}

其中,K为3x3矩阵称为相机内参数矩阵,包含4个未知数;T称为相机外参数矩阵包含了一个Rt

这里我们可以看到将一个3x4的矩阵记为了K,变成了一个3x3的矩阵。后面的T为一个4x4的矩阵,显然是不能进行计算的。那么,为什么我们这里会这样考虑呢?具体可以看高博十四讲中的一些数学技巧,主要是关于齐次坐标和非齐次坐标的转化。

二、Matlab具体标定步骤

在开始标定之前,需要准备好标定板。这个可以从网上下载打印。

我使用的Matlab版本是R2017b。打开Matlab后在APP中找到camera calibration。

注意:matlab打开camera calibration后可能找不到摄像头,这时候需要注册账号然后去安装驱动。我所使用的是罗技C270USB摄像头,如果只是为了理解其整个原理及标定的步骤,也可以使用笔记本电脑自带的摄像头进行操作。

安装好其驱动过后,就可以找到摄像头了。如下图所示。

下面开始添加照片,总共有两种办法,一种是直接从文件读取照片(这个也需要提前用准备标定的相机拍摄),另外一种办法是直接调用摄像头进行拍摄,然后再用照片。

标定的图片最少不能低于2张,最好控制在10到20张左右。张数比较少,可能存在的偏差比较大。按道理讲,张数越多也就是样本越多应该越准确才对。但是事实不是越多越好。据我猜测,应该是后面计算的畸变系数,涉及到有

注意:在这里我犯了一个很笨的错误,我用自己的手机去拍摄标定板的照片,然后直接用手机拍摄的照片进行标定操作。这样导致最后得出来的标定结果是我自己手机的参数。

然后添加完图片之后会出来一个窗口,这里需要输入你的标定板真实的尺寸,由于实验室有一块非常大的标定板,在这里,我直接进行使用。该标定板的是9cmx9cm的正方形。

点击确定过后,会出现下面这张图。

 

然后点击Export Camera Parameters

点击确定。会看到如下结果。

cameraParams = 

  cameraParameters - 属性:

   Camera Intrinsics
                    IntrinsicMatrix: [3×3 double]
                        FocalLength: [813.8289 813.8800]
                     PrincipalPoint: [344.9927 248.5357]
                               Skew: 0
                   RadialDistortion: [0.0201 0.3590]
               TangentialDistortion: [0 0]
                          ImageSize: [480 640]

   Camera Extrinsics
                   RotationMatrices: [3×3×10 double]
                 TranslationVectors: [10×3 double]

   Accuracy of Estimation
              MeanReprojectionError: 0.2204
                 ReprojectionErrors: [99×2×10 double]
                  ReprojectedPoints: [99×2×10 double]

   Calibration Settings
                        NumPatterns: 10
                        WorldPoints: [99×2 double]
                         WorldUnits: 'millimeters'
                       EstimateSkew: 0
    NumRadialDistortionCoefficients: 2
       EstimateTangentialDistortion: 0

然后再Matlab中输入以下三行命令即可得到我们要标定的一些参数。

>> cameraParams.IntrinsicMatrix

ans =

  813.8289         0         0
         0  813.8800         0
  344.9927  248.5357    1.0000

>> cameraParams.RadialDistortion

ans =

    0.0201    0.3590

>> cameraParams.TangentialDistortion

ans =

     0     0

到这里,对罗技C270摄像头的标定就完成了。

三、C++实现

主要参考博客

张正友相机标定Opencv实现以及标定流程&&标定结果评价&&图像矫正流程解析(附标定程序和棋盘图)

代码参考:

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <fstream>
#include <string>
using namespace cv;
using namespace std;

int main()
{
    ifstream fin("calibdata.txt"); /* 标定所用图像文件的路径 */
    ofstream fout("caliberation_result.txt");  /* 保存标定结果的文件 */
    //读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
    cout<<"开始提取角点………………";
    int image_count=0;  /* 图像数量 */
    Size image_size;  /* 图像的尺寸 */
    Size board_size = Size(7,7);    /* 标定板上每行、列的角点数 */
    vector<Point2f> image_points_buf;  /* 缓存每幅图像上检测到的角点 */
    vector<vector<Point2f> > image_points_seq; /* 保存检测到的所有角点 */
    string filename;
    int count= -1 ;//用于存储角点个数。
    cv::namedWindow("test",CV_WINDOW_AUTOSIZE);
    while (getline(fin,filename))
    {
        image_count++;
        // 用于观察检验输出
        cout<<"image_count = "<<image_count<<endl;
        /* 输出检验*/
        cout<<"-->count = "<<count;
//        Mat haha=imread("/home/zzn/projects/qt59-c or c++/calib/build-calib-Desktop-Default/chess1.jpg");
//        imshow("test",haha);
//        waitKey(0);
        string filename1="/home/zzn/projects/qt59-c or c++/calib/build-calib-Desktop-Default/"+filename;
        std::cout<<"filename1: "<<filename1<<std::endl;
        Mat imageInput=imread("/home/zzn/projects/qt59-c or c++/calib/build-calib-Desktop-Default/chess1.jpg");
        imshow("test",imageInput);
        if (image_count == 1)  //读入第一张图片时获取图像宽高信息
        {
            image_size.width = imageInput.cols;
            image_size.height =imageInput.rows;
            cout<<"image_size.width = "<<image_size.width<<endl;
            cout<<"image_size.height = "<<image_size.height<<endl;
        }

        /* 提取角点 */
        if (0 == findChessboardCorners(imageInput,board_size,image_points_buf))
        {
		cout<<"size: "<<image_points_buf.size()<<endl;
            cout<<"can not find chessboard corners!\n"; //找不到角点
            exit(1);
        }
        else
        {
            Mat view_gray;
            cvtColor(imageInput,view_gray,CV_RGB2GRAY);
            /* 亚像素精确化 */
            find4QuadCornerSubpix(view_gray,image_points_buf,Size(5,5)); //对粗提取的角点进行精确化
            //cornerSubPix(view_gray,image_points_buf,Size(5,5),Size(-1,-1),TermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.1));
            image_points_seq.push_back(image_points_buf);  //保存亚像素角点
            /* 在图像上显示角点位置 */
            drawChessboardCorners(view_gray,board_size,image_points_buf,false); //用于在图片中标记角点
            imshow("Camera Calibration",view_gray);//显示图片
            waitKey(500);//暂停0.5S
        }
    }
    int total = image_points_seq.size();
    cout<<"total = "<<total<<endl;
    int CornerNum=board_size.width*board_size.height;  //每张图片上总的角点数
    for (int ii=0 ; ii<total ;ii++)
    {
        if (0 == ii%CornerNum)// 24 是每幅图片的角点个数。此判断语句是为了输出 图片号,便于控制台观看
        {
            int i = -1;
            i = ii/CornerNum;
            int j=i+1;
            cout<<"--> 第 "<<j <<"图片的数据 --> : "<<endl;
        }
        if (0 == ii%3)	// 此判断语句,格式化输出,便于控制台查看
        {
            cout<<endl;
        }
        else
        {
            cout.width(10);
        }
        //输出所有的角点
        cout<<" -->"<<image_points_seq[ii][0].x;
        cout<<" -->"<<image_points_seq[ii][0].y;
    }
    cout<<"角点提取完成!\n";

    //以下是摄像机标定
    cout<<"开始标定………………";
    /*棋盘三维信息*/
    Size square_size = Size(18,18);  /* 实际测量得到的标定板上每个棋盘格的大小 */
    vector<vector<Point3f> >object_points; /* 保存标定板上角点的三维坐标 */
    /*内外参数*/
    Mat cameraMatrix=Mat(3,3,CV_32FC1,Scalar::all(0)); /* 摄像机内参数矩阵 */
    vector<int> point_counts;  // 每幅图像中角点的数量
    Mat distCoeffs=Mat(1,5,CV_32FC1,Scalar::all(0)); /* 摄像机的5个畸变系数:k1,k2,p1,p2,k3 */
    vector<Mat> tvecsMat;  /* 每幅图像的平移向量 */
    vector<Mat> rvecsMat; /* 每幅图像的旋转向量 */
    /* 初始化标定板上角点的三维坐标 */
    int i,j,t;
    for (t=0;t<image_count;t++)
    {
        vector<Point3f> tempPointSet;
        for (i=0;i<board_size.height;i++)
        {
            for (j=0;j<board_size.width;j++)
            {
                Point3f realPoint;
                /* 假设标定板放在世界坐标系中z=0的平面上 */
                realPoint.x = i*square_size.width;
                realPoint.y = j*square_size.height;
                realPoint.z = 0;
                tempPointSet.push_back(realPoint);
            }
        }
        object_points.push_back(tempPointSet);
    }
    /* 初始化每幅图像中的角点数量,假定每幅图像中都可以看到完整的标定板 */
    for (i=0;i<image_count;i++)
    {
        point_counts.push_back(board_size.width*board_size.height);
    }
    /* 开始标定 */
    calibrateCamera(object_points,image_points_seq,image_size,cameraMatrix,distCoeffs,rvecsMat,tvecsMat,0);
    cout<<"标定完成!\n";
    //对标定结果进行评价
    cout<<"开始评价标定结果………………\n";
    double total_err = 0.0; /* 所有图像的平均误差的总和 */
    double err = 0.0; /* 每幅图像的平均误差 */
    vector<Point2f> image_points2; /* 保存重新计算得到的投影点 */
    cout<<"\t每幅图像的标定误差:\n";
    fout<<"每幅图像的标定误差:\n";
    for (i=0;i<image_count;i++)
    {
        vector<Point3f> tempPointSet=object_points[i];
        /* 通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点 */
        projectPoints(tempPointSet,rvecsMat[i],tvecsMat[i],cameraMatrix,distCoeffs,image_points2);
        /* 计算新的投影点和旧的投影点之间的误差*/
        vector<Point2f> tempImagePoint = image_points_seq[i];
        Mat tempImagePointMat = Mat(1,tempImagePoint.size(),CV_32FC2);
        Mat image_points2Mat = Mat(1,image_points2.size(), CV_32FC2);
        for (int j = 0 ; j < tempImagePoint.size(); j++)
        {
            image_points2Mat.at<Vec2f>(0,j) = Vec2f(image_points2[j].x, image_points2[j].y);
            tempImagePointMat.at<Vec2f>(0,j) = Vec2f(tempImagePoint[j].x, tempImagePoint[j].y);
        }
        err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
        total_err += err/=  point_counts[i];
        std::cout<<"第"<<i+1<<"幅图像的平均误差:"<<err<<"像素"<<endl;
        fout<<"第"<<i+1<<"幅图像的平均误差:"<<err<<"像素"<<endl;
    }
    std::cout<<"总体平均误差:"<<total_err/image_count<<"像素"<<endl;
    fout<<"总体平均误差:"<<total_err/image_count<<"像素"<<endl<<endl;
    std::cout<<"评价完成!"<<endl;
    //保存定标结果
    std::cout<<"开始保存定标结果………………"<<endl;
    Mat rotation_matrix = Mat(3,3,CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */
    fout<<"相机内参数矩阵:"<<endl;
    fout<<cameraMatrix<<endl<<endl;
    fout<<"畸变系数:\n";
    fout<<distCoeffs<<endl<<endl<<endl;
    for (int i=0; i<image_count; i++)
    {
        fout<<"第"<<i+1<<"幅图像的旋转向量:"<<endl;
        fout<<rvecsMat[i]<<endl;
        /* 将旋转向量转换为相对应的旋转矩阵 */
        Rodrigues(rvecsMat[i],rotation_matrix);
        fout<<"第"<<i+1<<"幅图像的旋转矩阵:"<<endl;
        fout<<rotation_matrix<<endl;
        fout<<"第"<<i+1<<"幅图像的平移向量:"<<endl;
        fout<<tvecsMat[i]<<endl<<endl;
    }
    std::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);
    std::cout<<"保存矫正图像"<<endl;
    string imageFileName;
    std::stringstream StrStm;
    for (int i = 0 ; i != image_count ; i++)
    {
        std::cout<<"Frame #"<<i+1<<"..."<<endl;
        initUndistortRectifyMap(cameraMatrix,distCoeffs,R,cameraMatrix,image_size,CV_32FC1,mapx,mapy);
        StrStm.clear();
        imageFileName.clear();
        string filePath="chess";
        StrStm<<i+1;
        StrStm>>imageFileName;
        filePath+=imageFileName;
        filePath+=".bmp";
        Mat imageSource = imread(filePath);
        Mat newimage = imageSource.clone();
        //另一种不需要转换矩阵的方式
        //undistort(imageSource,newimage,cameraMatrix,distCoeffs);
        remap(imageSource,newimage,mapx, mapy, INTER_LINEAR);
        StrStm.clear();
        filePath.clear();
        StrStm<<i+1;
        StrStm>>imageFileName;
        imageFileName += "_d.jpg";
        imwrite(imageFileName,newimage);
    }
    std::cout<<"保存结束"<<endl;
    return 0;
}

使用CMake的编译方法

CMakelists编写

cmake_minimum_required(VERSION 2.8)

project(calib)
set(OpenCV_DIR /opt/ros/kinetic/share/OpenCV-3.3.1-dev)

find_package(OpenCV REQUIRED)
INCLUDE_DIRECTORIES(${OpenCV_INCLUDE_DIRS})

add_executable(${PROJECT_NAME} "main.cpp")

TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${OpenCV_LIBS})

终端输入 

cmake .
make

经过调试发现与输入的图片格式无关,可能编译不成功和IDE有关,故采取CMake的方法,编译成功。

 

 

以上有的地方理解的并不是特别深刻,所以难免会有错误。

大家多多交流,相互学习。

参考资料

  • 0
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
### 回答1: QT是一个开源的跨平应用程序开发框架,OpenCV是一套用于计算机视觉和机器学习的开源库,而单目相机标定是指通过对单个相机的内外参数进行估计的过程。 在使用QT和OpenCV实现单目相机标定的过程中,可以先创建一个QT应用程序窗口来进行图像显示和交互操作。通过OpenCV库中的函数,可以读取相机采集的图像,并将其显示在QT窗口中。同时,还可以在QT窗口中添加一些按钮或者滑动条等用于选择标定模式、设置标定参数以及展示结果等。 为了进行相机标定,首先需要采集一组不同角度和位置的图像。其中包括了用于标定的棋盘格图像。接着,通过OpenCV库中的相机标定函数,可以根据这些图像计算出相机的内参矩阵和畸变系数。这些参数将用于校正图像中的畸变。 在QT窗口中,可以显示标定结果以及标定参数的相关信息。通过调整滑动条或按钮进行参数的设置和标定的执行。同时,还可以添加一些自定义的功能,例如保存标定结果、计算图像中特定物体的三维坐标等。 总结来说,通过QT和OpenCV的结合,可以实现单目相机的标定功能,并在QT窗口中显示结果和进行交互操作。这样可以在相机标定过程中提供更加灵活和友好的界面,方便用户进行操作和观察结果。 ### 回答2: Qt是一种跨平的应用程序开发框架,OpenCV是一个广泛应用于计算机视觉领域的开源库,单目相机标定是一种通过计算相机内外参数来获得准确图像测量结果的技术,而"C"则表示使用C语言进行编程。 在使用Qt进行OpenCV的单目相机标定时,首先需要通过相机拍摄多幅已知的标定图像。为了准确标定相机,这些标定图像应该包括多个不同的视角、不同的位置和不同的焦距。然后,使用OpenCV提供的函数和算法来计算相机的内外参数。 在Qt中,可以使用图形界面来实现相机标定的可视化操作,通过选择标定图像的文件路径来加载图像,并提供按钮来触发标定过程。在标定过程中,可以显示标定结果,例如相机矩阵、畸变系数和旋转矩阵等。同时,还可以计算并显示相机的投影模型、校正后的图像和立体视图等。 通过使用C语言编程,可以更好地与OpenCV的函数和算法进行集成,以便于实现各种相机标定相关的计算和处理。在编写程序时,可以使用Qt中的信号和槽机制来处理用户界面和相机标定之间的交互,通过调用OpenCV的函数来实现具体的标定功能。 总之,Qt和OpenCV可以很好地结合在一起实现单目相机的标定。Qt提供了界面设计和交互操作的便利性,而OpenCV则提供了强大的图像处理和计算功能。通过使用C语言进行编程,可以更好地与OpenCV集成,并实现各种相机标定相关的计算和处理。这样的组合可以帮助开发者更好地进行单目相机标定的应用开发。 ### 回答3: Qt是一种跨平的应用程序开发框架,可以用于开发图形用户界面(GUI)应用程序。OpenCV是一个开源的计算机视觉库,提供了丰富的图像处理和计算机视觉算法。单目相机标定是计算机视觉领域中的一个重要任务,用于估计相机的内部参数和畸变系数。 在使用Qt和OpenCV进行单目相机标定C++编程中,可以按照以下步骤进行: 1. 创建Qt应用程序,并添加OpenCV库文件和头文件的路径。 2. 导入相机标定所需的图像,图像应包含已知的校准板(通常使用棋盘格)。 3. 使用OpenCV的函数来检测校准板的角点,常用函数是`cv::findChessboardCorners`。 4. 使用OpenCV函数`cv::cornerSubPix`来进一步提高角点的准确性。 5. 通过提供校准板的实际尺寸和检测到的角点坐标,调用OpenCV的`cv::calibrateCamera`函数进行相机标定。 6. 标定完成后,可以使用标定后的相机矩阵来矫正图像,从而消除图像中的畸变。 7. 可以使用标定结果来进行立体视觉、目标检测、姿态估计等计算机视觉任务。 在Qt中,可以使用QFileDialog来选择图像文件,可以使用QImage和QPixmap来显示图像,可以使用QMessageBox来显示标定结果。 总之,使用Qt和OpenCV进行单目相机标定C++编程需要结合两个库的功能,按照一定的步骤进行操作,最终可以得到相机的内部参数和畸变系数,为后续的计算机视觉任务提供准确的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值