首页 > 其他分享 >OpenCV获取相机的内参矩阵和畸变矩阵

OpenCV获取相机的内参矩阵和畸变矩阵

时间:2023-04-07 18:35:08浏览次数:33  
标签:函数 corners 矩阵 标定 内参 相机 OpenCV 坐标

实验室任务要截止了,赶紧来上传一下学习成果,终极目的是获取视频每帧的旋转矩阵和平移矩阵,但没办法一口吃个胖子,所以先写一下相机内参矩阵和畸变矩阵的求解办法
先上代码

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
 
int main(){
    // 棋盘格的行数与列数
    int row = 6, col = 9;
 
    // 准备用于标定的点坐标容器,每个元素表示一个标定板在3D空间中的坐标
    vector<Point3f> objp;
    for(int i=0;i<row;++i){
        for(int j=0;j<col;++j){
            objp.push_back(Point3f(j,i,0));
        }
    }
 
    // 存储所有图片的棋盘格角点坐标,以及相应的图像坐标
    vector<vector<Point3f>> objpoints; // 3D points in real world space
    vector<vector<Point2f>> imgpoints; // 2D points in image plane.
 
    // 枚举每张标定图片,获取棋盘格角点坐标
    vector<String> fn;
    glob("left*.jpg", fn, false);
    for(size_t i=0;i<fn.size();++i){
        Mat img = imread(fn[i]);
        Mat gray;
        cvtColor(img,gray,COLOR_BGR2GRAY);
 
        // 查找棋盘格角点
        vector<Point2f> corners;
        bool success = findChessboardCorners(gray, Size(row, col), corners);
 
        // 如果找到棋盘格角点,则存储这张图片的点信息
        if (success) {
            objpoints.push_back(objp);
            cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1),
                             TermCriteria(cv::TermCriteria::EPS+cv::TermCriteria::MAX_ITER, 30, 0.1));
            imgpoints.push_back(corners);
 
            // 显示角点信息
            drawChessboardCorners(img, Size(row, col), corners, success);
            imshow("corners",img);
            waitKey(500);
        }
    }
 
    // 获取相机原始尺寸
    Mat img = imread(fn[0]);
    Size img_shape = img.size();
 
    // 标定相机,并计算相机内参矩阵和畸变系数等参数
    Mat camera_matrix, dist_coeffs;
    vector<Mat> rvecs, tvecs;
    calibrateCamera(objpoints, imgpoints, img_shape, camera_matrix, dist_coeffs, rvecs, tvecs);
 
    // 保存相机内参矩阵和畸变系数等参数
    FileStorage fs("cam_params.yml", FileStorage::WRITE);
    fs << "camera_matrix" << camera_matrix;
    fs << "dist_coeffs" << dist_coeffs;
    fs.release();
 
    return 0;
}

担心大家和我一样都是小白,先讲解一些可能没见过的函数

(1)glob:

glob 函数是一个用于匹配文件名的函数,可以根据指定的模式匹配符合条件的文件名,并将其返回到指定的容器中。glob 函数通常在文件批量处理和数据读取等场景中使用,可以帮助我们快速地获取一组符合特定条件的文件名。
在 OpenCV 库中,glob 函数被封装在 cv::glob 函数中,可以方便地使用。

void glob(const String& pattern, std::vector<String>& result, bool recursive = false);
  • pattern:表示要匹配的文件名模式,可以是绝对路径或相对路径(相对于当前目录),支持通配符匹配。
  • result:表示匹配成功后将文件名保存到这个容器中。
  • recursive:是否递归搜索子目录,默认值为 false。
    在本次代码中用于分析多张标定图片,获取畸变矩阵和内参矩阵的准确值

(2)FileStorage:

FileStorage 是 OpenCV 库中用于序列化和反序列化数据的类,提供了将数据保存到 XML、JSON、YAML 等格式的文件中,以及从文件中读取数据到内存中的函数。FileStorage 可以用于从文件中读取或写入任意数据类型,包括图像、矩阵、数组、向量、标量、字符串等。
关于FileStorge函数的具体用法非常多,这里不展开讲,后续我会为其的用法专门写一篇博客,这里这要记住它能将我们的最终结果保存到一个文件中即可

(3)findChessboardCorners

findChessboardCorners 是 OpenCV 库中用于检测棋盘格角点的函数,该函数可以用于多种相机标定方法中。
findChessboardCorners 函数可以从一张包含了棋盘格图案的图像中找到所有的内角点坐标,以便后续进行相机标定。该函数通常与 drawChessboardCorners 函数一起使用,可视化地展示出检测到的内角点,以帮助用户确认是否正确检测到了所有的内角点。

bool findChessboardCorners(InputArray image, Size patternSize, OutputArray corners,
                           int flags = CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE);

  • image:输入图像,必须是灰度图。
  • patternSize:棋盘格内角点的尺寸,即内角点沿 x 和 y 方向的数量。
  • corners:输出参数,包含了检测到的内角点坐标。
  • flags:用于调整棋盘格检测的方法,包括下面几种:
    • CALIB_CB_ADAPTIVE_THRESH:使用自适应阈值来进行二值化。
    • CALIB_CB_NORMALIZE_IMAGE:将图像归一化到 0~255 的范围内。
    • CALIB_CB_FILTER_QUADS:通过考虑四边形质量来筛选掉不好的角点。

该函数将返回一个布尔类型的值,指示是否成功检测到所有的内角点。如果成功检测到, corners 中将包含所有内角点的坐标。

(4)drawChessboardCorners

这个和上个函数通常结合使用,简单来说结果就是把找到的内角点坐标选出来

void drawChessboardCorners(InputOutputArray image, Size patternSize, InputArray corners,
                            bool patternWasFound);
  • image:输入图像,输出绘制了角点的图像。
  • patternSize:棋盘格内角点的尺寸,即内角点沿 x 和 y 方向的数量。
  • corners:从 findChessboardCorners 函数得到的角点位置信息。
  • patternWasFound:布尔变量,表示棋盘格是否已被完全找到。

(5)consuubPix

cornerSubPix 是 OpenCV 库中用于亚像素级别的角点坐标精确化的函数,可以提高角点坐标的精度,从而更准确地进行相机标定和目标跟踪等应用。
在使用 findChessboardCorners 函数检测到棋盘格内角点的坐标后,这些坐标通常只是整数像素的位置。但是,实际上它们可能不是完全准确的位置,因此需要对其进行亚像素级别的精确化。
cornerSubPix 函数通过对图像局部区域进行拟合来计算出亚像素级别的角点坐标。该函数使用迭代方法,迭代次数由 criteria 参数指定。

cv::cornerSubPix(image, corners, winSize, zeroZone, criteria);
  • image:输入图像,单通道浮点类型。
  • corners:输入和输出变量,包含了待校正的角点坐标和输出精确化后的坐标。
  • winSize:搜索窗口大小。
  • zeroZone:搜索区域零区域大小,在搜索区域中心不计算梯度值,用于避免误差增大的情况。
  • criteria:迭代终止条件。

(6)标定图片

相机的旋转矩阵和平移矩阵是用于描述相机在空间中的姿态和位置的参数。在进行相机标定时,需要利用多张不同的图片来获取相机的内参矩阵和畸变系数等参数,并推导出旋转矩阵和平移矩阵。
为大多时候要使用标定图片对相机进行标定。举个例子
image


上面只是简单介绍用到函数和概念,具体用法并没有说明,想要深入了解可以自行搜索。

分步骤讲解一下代码思路

1. 准备标定的点坐标容器

    int row = 6, col = 9; //我这里的标定图片内部点的分布是6x9格式

    vector<Point3f> objp;
    for(int i=0;i<row;++i){
        for(int j=0;j<col;++j){
            objp.push_back(Point3f(j,i,0));  //记录图片里每个点的坐标,每个元素表示一个标定板在3D空间中的坐标
        }
    }

2.存储格角点坐标以及这些点在图像里的坐标

vector<vector<Point3f>> objpoints; // 3D points in real world space
vector<vector<Point2f>> imgpoints;

3.

vector<String> fn;
    glob("left*.jpg", fn, false); //我准备了14张图片,所以这里用glob把这些图像名称存储在fn变量里
    for(size_t i=0;i<fn.size();++i){
        Mat img = imread(fn[i]);
        Mat gray;
        cvtColor(img,gray,COLOR_BGR2GRAY);

        vector<Point2f> corners;
        bool success = findChessboardCorners(gray, Size(row, col), corners);//存储所有格角点的坐标在concern

        if (success) {
            objpoints.push_back(objp);
            cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1),
                     TermCriteria(cv::TermCriteria::EPS+cv::TermCriteria::MAX_ITER, 30, 0.1)); 

            imgpoints.push_back(corners);//存储这些图片的所有点信息

            drawChessboardCorners(img, Size(row, col), corners, success);//画出所以格角点
            imshow("corners",img);
            waitKey(500);
        }
    }

4.获取相机的内参矩阵和畸变矩阵

//通过图片获取相机尺寸
Mat img = imread(fn[0]);
Size img_shape = img.size();
 
// 标定相机,并计算相机内参矩阵和畸变系数等参数
Mat camera_matrix, dist_coeffs;
vector<Mat> rvecs, tvecs;
calibrateCamera(objpoints, imgpoints, img_shape, camera_matrix, dist_coeffs, rvecs, tvecs);

5.保存得到的矩阵

FileStorage fs("cam_params.yml", FileStorage::WRITE);
fs << "camera_matrix" << camera_matrix;
fs << "dist_coeffs" << dist_coeffs;
fs.release();

效果:
image

标签:函数,corners,矩阵,标定,内参,相机,OpenCV,坐标
From: https://www.cnblogs.com/nobodyx/p/17297074.html

相关文章

  • 用 Go 剑指 Offer 29. 顺时针打印矩阵
    给你一个m行n列的矩阵 matrix,请按照顺时针螺旋顺序,返回矩阵中的所有元素。 示例1:  输入:matrix=[[1,2,3],[4,5,6],[7,8,9]]输出:[1,2,3,6,9,8,7,4,5]示例2:  输入:matrix=[[1,2,3,4],[5,6,7,8],[9,10,11,12]]输出:[1,2,3,4,8,12,11,10,9,5,6,7] 提示:m......
  • opencv-python 4.15. 基于分水岭算法的图像分割
    理论任何灰度图像都可以看作是地形表面,其中高强度表示峰和丘陵,而低强度表示山谷。你开始用不同颜色的水(标签)填充每个孤立的山谷(局部最小值)。随着水的上升,取决于附近的峰值(梯度),来自不同山谷的水,明显具有不同的颜色将开始融合。为避免这种情况,你需要在水合并的位置建立障碍。你继续......
  • OpenCV图像像素读写操作
    常用类型介绍uchar类型typedefunsigneduint;typedefsignedcharschar;typedefunsignedcharuchar;typedefunsignedshortushort;Vec系列Vec+数字+字母:C++STLvector容器类似数字:Vec的长度字母:类型b:uchars:shortw:ushorti:intf:floatd:doubletypedefVec<uch......
  • UVA - 108 Maximum Sum 求子矩阵的最大和
    题目大意:给出一个矩阵,求出这个矩阵中的子矩阵的最大和解题思路:和UVA507的题目类似,只不过这次是个矩阵了,换个角度思考,将这个二维数组转换成一维数组思考,用sum存储该列的前N个数字的和,如,sum[3][1]就是第一列的前三个数字的和,这样就可以将其想象成一维的最大连续和了,在枚举行,求其最大的和......
  • opencv-python 4.14. 霍夫圆变换
    基础知识铺垫通过检索相关资料,学习到了霍夫圆检测的一点点皮毛知识,它的基本内容是认为图像上任何一个非零像素点,都有可能是一个潜在圆形上的一点。通过投票计算,生成累计坐标平面,然后在设置一个累计权重,去定位圆。在笛卡尔坐标系中圆的方程为(x-a)^2+(y-b)^2=r^2,其中(a,b......
  • 剑指 Offer 12. 矩阵中的路径
    题目链接:剑指Offer12.矩阵中的路径方法:DFS解题思路根据\(word\)中的第一个字母,从\(board\)网格中开始查找,通过\(DFS\)算法思想实现。注意:在每一轮开始查找前,每个位置的标记应该清除;每一个位置有上下左右四个方向可以选择;\(DFS\)查找进入下一步时要将位置标记......
  • 861. 翻转矩阵后的得分
    题目描述给了一个二维矩阵,矩阵的元素不是0就是1你可以进行任意次操作,让某行或者某列进行翻转元素的得分是每一行二进制的和问怎么操作可以让总得分最大?f1贪心+计算增量基本分析为啥可以贪心?(1)对每行来说,首位肯定是1最好,遮掩某些行需要翻转,某些不翻;(2)对同一列来说,大家的优先......
  • 题目 1024: [编程入门]矩阵对角线求和
    求一个3×3矩阵对角线元素之和。 解题思路和注意事项: 这道题还是蛮简单,首先要求求一个矩阵的主副对角线的元素和,那肯定要用到的就是多维数组。        多维数组的形式应该为:array[i][j]; 知道这个后我们开始分析题目:        先是主对角线,就是从左上到......
  • opencv-python 4.13. 霍夫线变换
    前言霍夫变换是一种特征检测(featureextraction),被广泛应用在图像分析(imageanalysis)、计算机视觉(computervision)以及数位影像处理(digitalimageprocessing)。霍夫变换(HoughTransform)是图像处理中的一种特征提取技术,它通过一种投票算法检测具有特定形状的物体。该过程......
  • C++,OpenCV-颜色模型转换(4)
    HSV颜色模型HSV模型HSV(Hue,Saturation,Value)根据颜色直观特性创建的一种颜色空间,也称六角锥体模型(HexconeModel),参数分别为色调(H),饱和度(S),明度(V)色调H用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°......