基于OpenCV的相机标定
目录
任务
相机标定的目标
查找棋盘的2D坐标
查找棋盘角点
优化棋盘角点
校准相机
采集图片
标定图片
任务
标定一个相机,标定完后使用cv::undistort方法去除相机的畸变。
相机标定的目标
输入:具有已知二维图像坐标和三维世界坐标的点的图像集合。
输出:3×3相机内参矩阵,每幅图像的旋转和平移。
查找棋盘的2D坐标
查找棋盘角点
OpenCV中的findChessboardCorners内置函数
bool findChessboardCorners(InputArray image, Size patternSize, OutputArray corners, int flags = CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE )
参数:
image: 8位灰度或彩色图像
pattenSize: 每个棋盘行和列的内角点数( patternSize = cvSize (points_per_row, points_per_colum) = cvSize(columns,rows))
corners: 检测到的角点的输出数组
flags: 各种操作标志
输出:
是否检测到角点
优化棋盘角点
cornersubix函数
void cornerSubPix(InputArray image, InputOutputArray corners, Size winSize, Size zeroZone, TermCriteria criteria)
参数:
image: 输入图像
corners: 输入角的初始坐标和为输出提供的精确坐标
WinSize: 搜索窗口边长的一半
zeroZone: 搜索区域中间零区大小的一半,在该零区上不进行下式求和。它有时用于避免自相关矩阵的可能奇点。(-1,-1)的值表示没有这样的大小
criteria: 角点精化迭代过程的终止准则。也就是说,在criteria.maxCount迭代之后或在某些迭代中角位置移动小于criteria.epsilon时,角位置求精过程停止
校准相机
calibrateCamera函数
double calibrateCamera(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, Size imageSize, InputOutputArray cameraMatrix, InputOutputArray distCoeffs, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs)
参数:
objectPoints: 三维图像点的矢量
imagePoints: 二维图像点的矢量
imageSize: 图像大小
cameraMatrix: 内参矩阵
distCoeffs: 透镜畸变系数
rvecs: 用于表达旋转的3×1矢量。矢量的方向指定旋转轴,矢量的大小指定旋转角度
tvecs: 用于表达位移的3×1矢量,与rvecs类似
采集图片
这里我用平板来当棋盘
#include "opencv2/opencv.hpp" #include#include using namespace cv; using namespace std; int main() { VideoCapture inputVideo(0); if (!inputVideo.isOpened()) { cout << "Could not open the input video " << endl; return -1; } Mat frame; string imgname; int f = 1; while (1) { inputVideo >> frame; if (frame.empty()) break; imshow("Camera", frame); char key = waitKey(1); if (key == 'c' || key == 'C')break; //按c结束 if (key == 'q' || key == 'Q') //按q截取图片 { imgname = to_string(f++) + ".jpg"; //以数字.jpg的格式保存图片 imwrite(imgname, frame); } } cout << "Finished writing" << endl; return 0; }
浅浅地拍了几张
大概就是这样hhh
标定图片
#include
#include
#include
using namespace std;
using namespace cv;
// 定义棋盘格的尺寸
int CHECKERBOARD[2]{7, 10};
int main()
{
// 创建矢量以存储每个棋盘图像的三维点矢量
std::vector> objpoints;
// 创建矢量以存储每个棋盘图像的二维点矢量
std::vector> imgpoints;
// 为三维点定义世界坐标系
std::vector objp;
for (int i{0}; i < CHECKERBOARD[1]; i++)
{
for (int j{0}; j < CHECKERBOARD[0]; j++)
{
objp.push_back(cv::Point3f(j, i, 0));
}
}
// 提取存储在给定目录中的单个图像的路径
std::vector images;
// 包含棋盘图像的文件夹的路径
std::string path = "C:/Users/86139/Documents/OpenCV/build/Debug/*.jpg";
// 使用glob函数读取所有图像的路径
cv::glob(path, images);
cv::Mat frame, gray;
// 存储检测到的棋盘转角像素坐标的矢量
std::vector corner_pts;
bool success;
// 循环读取图像
for (int i{0}; i < images.size(); i++)
{
frame = cv::imread(images[i]);
if (frame.empty())
{
continue;
}
if (i == 40)
{
int b = 1;
}
cout << "the current image is " << i << "th" << endl;
cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);
// 寻找角点
// 如果在图像中找到所需数量的角,则success = true
success = cv::findChessboardCorners(gray, cv::Size(CHECKERBOARD[0], CHECKERBOARD[1]), corner_pts, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK | CALIB_CB_NORMALIZE_IMAGE);
// 如果检测到所需数量的角点,我们将细化像素坐标并将其显示在棋盘图像上
if (success)
{
cv::TermCriteria criteria(TermCriteria::EPS | TermCriteria::Type::MAX_ITER, 30, 0.001);
// 为给定的二维点细化像素坐标
cv::cornerSubPix(gray, corner_pts, cv::Size(11, 11), cv::Size(-1, -1), criteria);
// 在棋盘上显示检测到的角点
cv::drawChessboardCorners(frame, cv::Size(CHECKERBOARD[0], CHECKERBOARD[1]), corner_pts, success);
objpoints.push_back(objp);
imgpoints.push_back(corner_pts);
}
}
cv::destroyAllWindows();
cv::Mat cameraMatrix, distCoeffs, R, T;
// 通过传递已知3D点(objpoints)的值和检测到的角点(imgpoints)的相应像素坐标来执行相机校准
cv::calibrateCamera(objpoints, imgpoints, cv::Size(gray.rows, gray.cols), cameraMatrix, distCoeffs, R, T);
// 内参矩阵
std::cout << "cameraMatrix : " << cameraMatrix << std::endl;
// 透镜畸变系数
std::cout << "distCoeffs : " << distCoeffs << std::endl;
// rvecs
std::cout << "Rotation vector : " << R << std::endl;
// tvecs
std::cout << "Translation vector : " << T << std::endl;
// 当摄像头打开时,实时矫正图片,并实时输出;
VideoCapture capture(0);
Mat original, undistorted;
while(capture.isOpened()){
capture >> original;
undistort(original, undistorted, cameraMatrix,distCoeffs);
imshow("original", original);
waitKey(30);
imshow("undistorted", undistorted);
waitKey(30);
}
return 0;
}
因为电脑的摄像头质量太好了其实根本不需要矫正,导致图像差不多



