2024年最新OpenCV相机标定全过程_opencv棋盘格标定过程,2024年最新【工作感悟

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

void cornerSubPix( InputArray image,
InputOutputArray corners,
Size winSize,
Size zeroZone,
TermCriteria criteria );


image源图像  
 corners,提供角点的初始坐标,返回更加精确的点  
 winSize,搜索窗口的一般尺寸,如果winSize=Size(5,5),则search windows为11\*11  
 winSize,死区的一般尺寸,用来避免自相关矩阵的奇点,(-1,-1)表示没有死区  
 criteria,控制迭代次数和精度


### calibrateCamera() 求解摄像机的内在参数和外在参数



double calibrateCamera( InputArrayOfArrays objectPoints,
InputArrayOfArrays imagePoints,
Size imageSize,
InputOutputArray cameraMatrix,
InputOutputArray distCoeffs,
OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
int flags = 0,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT +
TermCriteria::EPS, 30, DBL_EPSILON) );


objectPoints,世界坐标,用vector<vector>,输入x,y坐标,z坐标为0  
 imagePoints,图像坐标,vector<vector>  
 imageSize,图像的大小用于初始化标定摄像机的image的size  
 cameraMatrix,内参数矩阵  
 distCoeffs,畸变矩阵  
 rvecs,位移向量  
 tvecs,旋转向量  
 flags,可以组合:  
 **CV\_CALIB\_USE\_INTRINSIC\_GUESS**:使用该参数时,将包含有效的fx,fy,cx,cy的估计值的内参矩阵cameraMatrix,作为初始值输入,然后函数对其做进一步优化。如果不使用这个参数,用图像的中心点初始化光轴点坐标(cx, cy),使用最小二乘估算出fx,fy(这种求法好像和张正友的论文不一样,不知道为何要这样处理)。注意,如果已知内部参数(内参矩阵和畸变系数),就不需要使用这个函数来估计外参,可以使用solvepnp()函数计算外参数矩阵。


**CV\_CALIB\_FIX\_PRINCIPAL\_POINT**:在进行优化时会固定光轴点,光轴点将保持为图像的中心点。当CV\_CALIB\_USE\_INTRINSIC\_GUESS参数被设置,保持为输入的值。


**CV\_CALIB\_FIX\_ASPECT\_RATIO**:固定fx/fy的比值,只将fy作为可变量,进行优化计算。当  
 CV\_CALIB\_USE\_INTRINSIC\_GUESS没有被设置,fx和fy的实际输入值将会被忽略,只有fx/fy的比值被计算和使用。


**CV\_CALIB\_ZERO\_TANGENT\_DIST**:切向畸变系数(P1,P2)被设置为零并保持为零。


**CV\_CALIB\_FIX\_K1**,…,CV\_CALIB\_FIX\_K6:对应的径向畸变系数在优化中保持不变。如果设置了CV\_CALIB\_USE\_INTRINSIC\_GUESS参数,就从提供的畸变系数矩阵中得到。否则,设置为0。


**CV\_CALIB\_RATIONAL\_MODEL**(理想模型):启用畸变k4,k5,k6三个畸变参数。使标定函数使用有理模型,返回8个系数。如果没有设置,则只计算其它5个畸变参数。


**CALIB\_THIN\_PRISM\_MODEL** (薄棱镜畸变模型):启用畸变系数S1、S2、S3和S4。使标定函数使用薄棱柱模型并返回12个系数。如果不设置标志,则函数计算并返回只有5个失真系数。


**CALIB\_FIX\_S1\_S2\_S3\_S4** :优化过程中不改变薄棱镜畸变系数S1、S2、S3、S4。如果cv\_calib\_use\_intrinsic\_guess设置,使用提供的畸变系数矩阵中的值。否则,设置为0。


**CALIB\_TILTED\_MODEL** (倾斜模型):启用畸变系数tauX and tauY。标定函数使用倾斜传感器模型并返回14个系数。如果不设置标志,则函数计算并返回只有5个失真系数。


**CALIB\_FIX\_TAUX\_TAUY** :在优化过程中,倾斜传感器模型的系数不被改变。如果cv\_calib\_use\_intrinsic\_guess设置,从提供的畸变系数矩阵中得到。否则,设置为0。


### initUndistortRectifyMap() 计算畸变参数



void initUndistortRectifyMap(InputArray cameraMatrix,
InputArray distCoeffs,
InputArray R,
InputArray newCameraMatrix,
Size size,
int m1type,
OutputArray map1,
OutputArray map2)


**cameraMatrix**,摄像机内参数矩阵  
 **distCoeffs**, 摄像机的5个畸变系数,(k1,k2,p1,p2[,k3[,k4,k5,k6]])  
 **R**,在客观空间中的转换对象  
 **newCameraMatrix**,新的3\*3的浮点型矩矩阵  
 **size**,为失真图像的大小  
 **m1type**,第一个输出的map,类型为CV\_32FC1或CV\_16SC2  
 **map1**,x映射函数  
 **map2**,y映射函数


## 二、绘制棋盘格,拍摄照片


这里自己画一个棋盘格用作标定,长度为1280像素,宽490像素,横向10方格,纵向7方格



std_cb = Vision::makeCheckerboard(1280, 490, 10, 7, 0,
(char *)“…/blizzard/res/calibration/std_cb.png”);


效果如图  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20181030155734574.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2N6aHphc3Vp,size_16,color_FFFFFF,t_70)


Vision是我个人创建的视觉类,可以用来绘制标准的棋盘格。  
 头文件vision.h



//
// Created by czh on 18-10-16.
//

#ifndef OPENGL_PRO_VISION_H
#define OPENGL_PRO_VISION_H

#include “opencv2/opencv.hpp”
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>

#include “iostream”

class Vision {
public:
static cv::Mat read(std::string file_path, int flags = cv::IMREAD_ANYCOLOR | cv::IMREAD_ANYDEPTH);

static cv::Mat write(std::string file_path, int flags = cv::IMREAD_ANYCOLOR | cv::IMREAD_ANYDEPTH);

static void dispConfig(cv::Mat img);

static cv::Mat makeCheckerboard(int bkgWidth, int bkgHeight, int sqXnum, int sqYnum = 0, int borderThickness = 0, char *savePath = NULL);

private:

};

#endif //OPENGL_PRO_VISION_H


源文件vision.cpp



//
// Created by czh on 18-10-16.
//

#include “vision.h”
#include “string.h”

using namespace std;
using namespace cv;

const char *findName(const char *ch) {
const char *name = strrchr(ch, ‘/’);
return ++name;
}

cv::Mat Vision::read(std::string file_path, int flags) {
printf(“#Vision read\n”);
cv::Mat img;
img = cv::imread(file_path, flags);
if (img.data == NULL) {
printf(“\tError:vision read\n”);
} else {
dispConfig(img);
}
return img;
}

void Vision::dispConfig(cv::Mat img) {
printf(“\tpixel:%d*%d, channels:%d\n”, img.size().width, img.size().height, img.channels());
}

cv::Mat Vision::makeCheckerboard(int bkgWidth, int bkgHeight, int sqXnum, int sqYnum, int thickNum, char *savePath) {
if(sqYnum == 0){
sqYnum = sqXnum;
}
if(savePath == NULL){
char *defaultPath = (char *)“…/res/calibration/maths.png”;
savePath = defaultPath;
}
int checkboardX = 0;//棋盘x坐标
int checkboardY = 0;//棋盘y坐标
int xLen = bkgWidth / sqXnum;//x方格长度
int yLen = bkgHeight / sqYnum;//y方格长度
cv::Mat img(bkgHeight + thickNum * 2, bkgWidth + thickNum * 2, CV_8UC4, cv::Scalar(0, 255, 255, 255));
for (int i = 0; i < img.rows; i++) {

    for (int j = 0; j < img.cols; j++) {

        if (i < thickNum || i >= thickNum + bkgHeight || j < thickNum || j >= thickNum + bkgWidth) {
            img.at<Vec<uchar, 4>>(i, j) = cv::Scalar(0, 0, 0, 255);
            continue;
        }
        checkboardX = j - thickNum;
        checkboardY = i - thickNum;
        if (checkboardY / yLen % 2 == 0) {
            if ((checkboardX) / xLen % 2 == 0) {
                img.at<Vec<uchar, 4>>(i, j) = cv::Scalar(255, 255, 255, 255);
            } else {
                img.at<Vec<uchar, 4>>(i, j) = cv::Scalar(0, 0, 0, 255);
            }
        }
        else{
            if ((checkboardX) / xLen % 2 != 0) {
                img.at<Vec<uchar, 4>>(i, j) = cv::Scalar(255, 255, 255, 255);
            } else {
                img.at<Vec<uchar, 4>>(i, j) = cv::Scalar(0, 0, 0, 255);
            }
        }
    }
}
imwrite(savePath, img);    //保存生成的图片
printf("#makeCheckerboard %d*%d\n", bkgWidth + thickNum, bkgHeight + thickNum);
return img;

}


用A4纸打印棋盘格,相机拍摄照片。  
 我偷懒,拿了别人的标定照片  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20181030160047506.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2N6aHphc3Vp,size_16,color_FFFFFF,t_70)


## 三、相机标定


下面是相机标定代码



cv::imwrite(“…/blizzard/res/calibration/cb_source.png”, cb_source);

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

15661030441)]
[外链图片转存中…(img-BbQmQWqP-1715661030442)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值