赞
踩
若该文为原创文章,转载请注明原文出处
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/136535848
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…(点击传送门)
上一篇:《OpenCV开发笔记(七十五):相机标定矫正中使用remap重映射进行畸变矫正》
下一篇:《OpenCV开发笔记(七十七):相机标定(二):通过棋盘标定计算相机内参矩阵矫正畸变摄像头图像》
知道图像畸变矫映射的原理之后,那么如何得到相机的内参是矫正的第一步,内参决定了内参矩阵(中心点、焦距等),用内参矩阵才能计算出投影矩阵,从而将原本畸变的图像矫正为平面投影图像。
本篇描述了相机成形的原理,并绘制出识别的角点。
得到矩阵计算原理:
得到计算过程:
相机的畸变是指相机镜头对物体所成的像相对于物体本身而言的失真程度,它是光学透镜的固有特性。畸变产生的原因主要是透镜的边缘部分和中心部分的放大倍率不一样。
畸变分为以下几类:
主要由透镜不同部位放大倍率不同造成,它又分为枕形畸变和桶形畸变两种。枕形畸变,也称为鞍形形变,视野中边缘区域的放大率远大于光轴中心区域的放大率,常用在远摄镜头中。桶形畸变则与枕形畸变相反,视野中光轴中心区域的放大率远大于边缘区域的放大率,常出现在广角镜头和鱼眼镜头中。
主要由透镜安装与成像平面不平行造成,类似于透视原理,如近大远小、圆变椭圆等。
由透镜设计缺陷和加工安装误差造成,又称为线性畸变。其影响较小,一般忽略不计。
采集一张棋盘图片,要确认他是可以被识别的。
读取图像,这里由于图片较大,我们重设大小为原来宽高的1/2:
// 使用图片
std::string srcFilePath = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/chessboard.png";
// std::string srcFilePath = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/24.jpg";
cv::Mat srcMat = cv::imread(srcFilePath);
int chessboardColCornerCount = 6;
int chessboardRowCornerCount = 9;
// 步骤一:读取文件
// cv::imshow("1", srcMat);
// cv::waitKey(0);
// 步骤二:缩放,太大了缩放下(可省略)
cv::resize(srcMat, srcMat, cv::Size(srcMat.cols / 2, srcMat.rows / 2));
cv::Mat srcMat2 = srcMat.clone();
cv::Mat srcMat3 = srcMat.clone();
// cv::imshow("2", srcMat);
// cv::waitKey(0);
先灰度化,然后输入预制的纵向横向角数量,使用棋盘角点函数提取角点
// 步骤三:灰度化 cv::Mat grayMat; cv::cvtColor(srcMat, grayMat, cv::COLOR_BGR2GRAY); cv::imshow("3", grayMat); // cv::waitKey(0); // 步骤四:检测角点 std::vector<cv::Point2f> vectorPoint2fCorners; bool patternWasFound = false; patternWasFound = cv::findChessboardCorners(grayMat, cv::Size(chessboardColCornerCount, chessboardRowCornerCount), vectorPoint2fCorners, cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_FAST_CHECK | cv::CALIB_CB_NORMALIZE_IMAGE); /* enum { CALIB_CB_ADAPTIVE_THRESH = 1, // 使用自适应阈值将图像转化成二值图像 CALIB_CB_NORMALIZE_IMAGE = 2, // 归一化图像灰度系数(用直方图均衡化或者自适应阈值) CALIB_CB_FILTER_QUADS = 4, // 在轮廓提取阶段,使用附加条件排除错误的假设 CALIB_CB_FAST_CHECK = 8 // 快速检测 }; */ cvui::printf(srcMat, 0, 0, 1.0, 0xFF0000, "found = %s", patternWasFound ? "true" : "false"); cvui::printf(srcMat, 0, 24, 1.0, 0xFF0000, "count = %d", vectorPoint2fCorners.size()); qDebug() << __FILE__ << __LINE__ << vectorPoint2fCorners.size(); // 步骤五:绘制棋盘点 cv::drawChessboardCorners(srcMat2, cv::Size(chessboardColCornerCount, chessboardRowCornerCount), vectorPoint2fCorners, patternWasFound);
// 步骤六:进一步提取亚像素角点
cv::TermCriteria criteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, // 类型
30, // 参数二: 最大次数
0.001); // 参数三:迭代终止阈值
/*
#define CV_TERMCRIT_ITER 1 // 终止条件为: 达到最大迭代次数终止
#define CV_TERMCRIT_NUMBER CV_TERMCRIT_ITER //
#define CV_TERMCRIT_EPS 2 // 终止条件为: 迭代到阈值终止
*/
qDebug() << __FILE__ << __LINE__ << vectorPoint2fCorners.size();
cv::cornerSubPix(grayMat,
vectorPoint2fCorners,
cv::Size(11, 11),
cv::Size(-1, -1),
criteria);
OpenCV 中用于检测图像中棋盘角点的函数。
bool cv::findChessboardCorners(InputArray image,
Size patternSize,
OutputArray corners,
int flags=CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE)
参数解释:
函数返回值是一个布尔值,如果找到足够的角点以形成一个棋盘模式,则返回 true;否则返回 false。
findChessboardCorners 函数通常用于相机标定,通过检测棋盘角点来确定图像与真实世界之间的对应关系。一旦角点被检测到,就可以使用这些点来估计相机的内参(如焦距、主点)和外参(如旋转和平移矩阵)。
OpenCV中的一个函数,用于在检测到的棋盘角点周围绘制方框。这对于相机标定、图像对齐等应用非常有用。
void cv::drawChessboardCorners(InputOutputArray image,
Size patternSize,
InputArray corners,
bool patternWasFound)
参数解释:
TermCriteria是OpenCV中用于指定迭代算法终止条件的模板类。它取代了之前的CvTermCriteria,并且在许多OpenCV算法中作为迭代求解的结构被使用。
struct TermCriteria {
enum { COUNT=1, MAX_ITER=COUNT, EPS=2 };
TermCriteria();
TermCriteria(int type, int maxCount, double epsilon);
TermCriteria(const CvTermCriteria& criteria);
};
构造时需要三个参数:
OpenCV中用于精确化角点位置,其函数原型如下:
void cv::cornerSubPix(InputArray image,
InputOutputArray corners,
Size winSize,
Size zeroZone,
TermCriteria criteria);
参数解释:
cornerSubPix函数用于在初步提取的角点信息上进一步提取亚像素信息,从而提高相机标定的精度。在相机标定、目标跟踪和三维重建等应用中,精确的角点位置是非常重要的,因此cornerSubPix函数在这些领域有广泛的应用。
void OpenCVManager::testFindChessboardCorners() { #define FindChessboardCornersUseCamera 1 #if !FindChessboardCornersUseCamera // 使用图片 std::string srcFilePath = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/chessboard.png"; // std::string srcFilePath = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/24.jpg"; cv::Mat srcMat = cv::imread(srcFilePath); #else // 使用摄像头 cv::VideoCapture capture; // 插入USB摄像头默认为0 if(!capture.open(0)) { qDebug() << __FILE__ << __LINE__ << "Failed to open camera: 0"; }else{ qDebug() << __FILE__ << __LINE__ << "Succeed to open camera: 0"; } while(true) { cv::Mat srcMat; capture >> srcMat; #endif int chessboardColCornerCount = 6; int chessboardRowCornerCount = 9; // 步骤一:读取文件 // cv::imshow("1", srcMat); // cv::waitKey(0); // 步骤二:缩放,太大了缩放下(可省略) cv::resize(srcMat, srcMat, cv::Size(srcMat.cols / 2, srcMat.rows / 2)); cv::Mat srcMat2 = srcMat.clone(); cv::Mat srcMat3 = srcMat.clone(); // cv::imshow("2", srcMat); // cv::waitKey(0); // 步骤三:灰度化 cv::Mat grayMat; cv::cvtColor(srcMat, grayMat, cv::COLOR_BGR2GRAY); cv::imshow("3", grayMat); // cv::waitKey(0); // 步骤四:检测角点 std::vector<cv::Point2f> vectorPoint2fCorners; bool patternWasFound = false; patternWasFound = cv::findChessboardCorners(grayMat, cv::Size(chessboardColCornerCount, chessboardRowCornerCount), vectorPoint2fCorners, cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_FAST_CHECK | cv::CALIB_CB_NORMALIZE_IMAGE); /* enum { CALIB_CB_ADAPTIVE_THRESH = 1, // 使用自适应阈值将图像转化成二值图像 CALIB_CB_NORMALIZE_IMAGE = 2, // 归一化图像灰度系数(用直方图均衡化或者自适应阈值) CALIB_CB_FILTER_QUADS = 4, // 在轮廓提取阶段,使用附加条件排除错误的假设 CALIB_CB_FAST_CHECK = 8 // 快速检测 }; */ cvui::printf(srcMat, 0, 0, 1.0, 0xFF0000, "found = %s", patternWasFound ? "true" : "false"); cvui::printf(srcMat, 0, 24, 1.0, 0xFF0000, "count = %d", vectorPoint2fCorners.size()); qDebug() << __FILE__ << __LINE__ << vectorPoint2fCorners.size(); // 步骤五:绘制棋盘点 cv::drawChessboardCorners(srcMat2, cv::Size(chessboardColCornerCount, chessboardRowCornerCount), vectorPoint2fCorners, patternWasFound); #if FindChessboardCornersUseCamera cv::imshow("0", srcMat); cv::imshow("4", srcMat2); if(!patternWasFound) { cv::imshow("5", srcMat3); cv::waitKey(1); continue; } #endif // 步骤六:进一步提取亚像素角点 cv::TermCriteria criteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, // 类型 30, // 参数二: 最大次数 0.001); // 参数三:迭代终止阈值 /* #define CV_TERMCRIT_ITER 1 // 终止条件为: 达到最大迭代次数终止 #define CV_TERMCRIT_NUMBER CV_TERMCRIT_ITER // #define CV_TERMCRIT_EPS 2 // 终止条件为: 迭代到阈值终止 */ qDebug() << __FILE__ << __LINE__ << vectorPoint2fCorners.size(); cv::cornerSubPix(grayMat, vectorPoint2fCorners, cv::Size(11, 11), cv::Size(-1, -1), criteria); // 步骤七:绘制棋盘点 cv::drawChessboardCorners(srcMat3, cv::Size(chessboardColCornerCount, chessboardRowCornerCount), vectorPoint2fCorners, patternWasFound); cv::imshow("5", srcMat3); // cv::waitKey(0); #if FindChessboardCornersUseCamera cv::waitKey(1); } // cv::imshow(_windowTitle.toStdString(), dstMat); #else cv::waitKey(0); #endif }
检测角点失败
输入棋牌横向竖向角点的数量入函数,而不是输入行数和列数。
输入正确的横向纵向角点数量即可。
检测亚像素角点函数崩溃
输入要是灰度mat
将灰度图输入即可。
上一篇:《OpenCV开发笔记(七十五):相机标定矫正中使用remap重映射进行畸变矫正》
下一篇:《OpenCV开发笔记(七十七):相机标定(二):通过棋盘标定计算相机内参矩阵矫正畸变摄像头图像》
若该文为原创文章,转载请注明原文出处
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/136535848
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。