通过分析一系列(至少三张)包含棋盘格图案的图像,来计算相机的内参数矩阵(包括焦距、主点坐标等)和畸变系数,以及每幅图像对应的外参数(旋转和平移向量)。下面是代码的详细步骤:
1、包含头文件和命名空间定义:引入必要的OpenCV库头文件和Windows API头文件,以及定义了使用的命名空间。
2、定义棋盘格角点查找函数:定义了findChessboardCornersFunc函数,该函数利用OpenCV的findChessboardCorners查找图像中的棋盘格角点,并使用cornerSubPix函数进一步精确这些角点的位置。
主函数流程:
2、初始化参数:定义了棋盘格的规格(行数、列数)、每个格子的实际宽度和高度,以及用于存储角点的世界坐标、图像坐标、图像名称和图像数据的向量。
读取图像文件名:通过Windows API遍历指定路径下的.jpg和.png格式的图像文件,将文件路径添加到imageNames向量中。
初始化世界坐标系中的棋盘格角点:根据棋盘格的规格和格子的实际尺寸,计算所有角点的三维坐标并存储在objp 向量中。
处理每个图像:遍历所有图像,读取图像并将其转换为灰度图,然后尝试在图像中查找棋盘格角点。如果找到,将角点图像坐标、对应的角点世界坐标和图像本身分别存储在imagePoints、objectPoints和images向量中。
相机标定:使用calibrateCamera函数,根据找到的所有图像角点及其对应的世界坐标,以及图像的尺寸,计算出相机的内参数矩阵、畸变系数、旋转矩阵和平移向量。
输出结果:打印出计算得到的相机内参数矩阵和畸变系数。
图像去畸变展示:选取第一张图像,使用undistort函数对其进行去畸变处理,并显示原始图像和去畸变后的图像,等待用户按键后关闭窗口。
#include <opencv2/opencv.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <windows.h>
#include <iostream>
#include <vector>
#include <filesystem>
using namespace cv;
using namespace std;
// 函数用于寻找并标记图像中的棋盘格角点
bool findChessboardCornersFunc(const Mat& image, Size patternSize, vector<Point2f>& corners)
{
bool found = findChessboardCorners(image, patternSize, corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_FAST_CHECK + CALIB_CB_NORMALIZE_IMAGE);
if (found)
cornerSubPix(image, corners, Size(11, 11), Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.01));
return found;
}
int main()
{
// 标定板的规格
Size patternSize(11, 8); // 棋盘格内角点
float squareSizeWidth = 30.0f; // 棋盘格格子大小
float squareSizeHeight = 30.0f; // 棋盘格格子大小
vector<vector<Point3f>> objectPoints;
vector<vector<Point2f>> imagePoints;
vector<String> imageNames;
vector<Mat> images;
// 读取所有图像文件名
string path = "E:\\vsifle\\image\\image\\camera_L"; // 替换为你的图像文件夹路径
WIN32_FIND_DATAA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
hFind = FindFirstFileA((path + "\\*.jpg").c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
hFind = FindFirstFileA((path + "\\*.png").c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
printf("No JPG or PNG files found.\n");
return EXIT_FAILURE;
}
}
do
{
imageNames.push_back(path + "\\" + ffd.cFileName);
} while (FindNextFileA(hFind, &ffd) != 0);
FindClose(hFind);
// 初始化世界坐标系中的棋盘格角点
vector<Point3f> objp;
// 初始化世界坐标系中的棋盘格角点,考虑实际尺寸
for (int i = 0; i < patternSize.height; i++)
for (int j = 0; j < patternSize.width; j++)
objp.push_back(Point3f(j*squareSizeWidth, i*squareSizeHeight, 0.0f));
// 对每个图像进行处理
for (const String& name : imageNames)
{
Mat img = imread(name, IMREAD_GRAYSCALE);
if (img.empty())
{
cout << "Can't read image " << name << endl;
continue;
}
//提取图像中的角点
vector<Point2f> corners;
if (findChessboardCornersFunc(img, patternSize, corners))
{
imagePoints.push_back(corners);
objectPoints.push_back(objp);
images.push_back(img);
}
else
{
cout << "Chessboard not found in " << name << endl;
}
}
//根据标定板的世界坐标和图像角点坐标完成相机标定
Mat cameraMatrix, distCoeffs, rvecs, tvecs;
vector<vector<Point2f>> allImagePoints = imagePoints;
vector<vector<Point3f>> allObjectPoints = objectPoints;
calibrateCamera(allObjectPoints, allImagePoints, images[0].size(), cameraMatrix, distCoeffs, rvecs, tvecs);
// 输出结果
cout << "Camera matrix:" << endl << cameraMatrix << endl;
cout << "Distortion coefficients:" << endl << distCoeffs << endl;
// 可选:使用得到的参数对一张图片进行去畸变演示
Mat undistorted;
undistort(images[0], undistorted, cameraMatrix, distCoeffs); //相机去畸变
imshow("Original Image", images[0]);
imshow("Undistorted Image", undistorted);
waitKey(0);
return 0;
}