opencv_c++学习(二十七)

这篇具有很好参考价值的文章主要介绍了opencv_c++学习(二十七)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、单目相机模型

opencv_c++学习(二十七)
上图为针孔相机成像原理,蓝色坐标中的O即为镜头光心。成像原理与小孔成像相同。
opencv_c++学习(二十七)
单目相机映射关系如下:
opencv_c++学习(二十七)
将上式进行变换,就可以从三位空间映射到2维平面的公式。
opencv_c++学习(二十七)
相机的畸变公式如下:
opencv_c++学习(二十七)

二、模型投影函数

void cv:projectPoints ( InputArray objectPoints, InputArray rvec, InputArray tvec, InputArray cameraMatrix,InputArray distCoeffs,outputArray imagePolints, jacobian =, OutputArray naArray(), double aspectRatio = 0)

objectPoints:世界坐标系中3D点的三维坐标。
rvec:世界坐标系变换到相机坐标系的旋转向量。
tvec:世界坐标系变换到相机坐标系的平移向量。
cameraMatrix:相机的内参矩阵。
distCoeffs:相机的畸变系数矩阵。
imagcPoints:三维坐标点在像素坐标系中估计的坐标。
jacobian:可选输出的雅可比矩阵。
aspectRatio:是否固定“宽高比”参数标志。
本节应用案例如下:

int main() {

	//输入计算的内参矩阵和畸变矩阵(在相机厂家说明或者标定获得)
	Mat cameraMatrix = (Mat_<float>(3, 3) << 532.016297, 0, 332.172519,
		0, 531.565159, 233.388075,
		0, 0, 1);

	Mat distCoeffs = (Mat_<float>(1, 5) << -0.285188, 0.080097, 0.001274,
		0.002415, 0.106579);

	//图像相机坐标系与世界坐标系之间的关系
	Mat rvec = (Mat_<float>(1, 3) << -1.977853, -2.002220, 0.130029);
	Mat tvec = (Mat_<float>(1, 3) << -26.88155, -42.79936, 159.19703);

	//生成第一张图像中内角点的三位世界坐标
	Size boardSize = Size(9,6);
	//棋盘格每个方格的真实尺寸
	Size squareSize = Size(10, 10);

	vector<Point3f> PointSets;
	for (int j = 0; j < boardSize.height; j++)
	{
		for (int k = 0; k < boardSize.width; k++)
		{
			Point3f realPoint;

			//假设标定板为世界坐标系的Z平面,及z=0
			realPoint.x = j * squareSize.width;
			realPoint.y = k * squareSize.height;
			realPoint.z = 0;
			PointSets.push_back(realPoint);
		}
	}

	//根据三维坐标和相机与世界坐标系时间的关系估计内角点像素坐标
	vector<Point2f> imagePoints;
	projectPoints(PointSets, rvec, tvec, cameraMatrix, distCoeffs, imagePoints);

	for (int i = 0; i < imagePoints.size(); i++)
	{
		cout << imagePoints[i] << endl;
	}

	waitKey(0);
	return 0;

}

三、单目相机标定

标定原理:
opencv_c++学习(二十七)
从上图中可以看出,相机坐标系可以通过世界坐标系进行平移变换来得到。具体的变换矩阵如相机坐标系右侧的公式。
标定板的图例如下:
opencv_c++学习(二十七)
上图中为两种类型的标定板,左侧为常用标定板,在提取的时候是内角点。而右侧标定板中不存在内角点,所以我们提取的是每个圆的中心点。
内角点提取函数如下:

bool cv:.findChessboardCorners ( InputArray image, Size patternSize, OutputArray corners, int flags = CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORNALIZE_IPAGE)

image:含有棋盘标定板的图像,图像必须是CV_8U的灰度图像或者彩色图像。
patternSize:图像中棋盘内角点行数和列数
corners:检测到的角点坐标
flags:检测角点方式的标志
圆形标定板中心提取:

bool cv::findCirclesGrid ( InputArray image, Size patternSize, OutputArray centers, int flags, const Ptr< FeatureDetector > & blolbDetector, const CirclesGridFinderParameters & parameters)

image:输入含有圆形网格的图像,图像必须是CV_8U的灰度图像或者彩色图像。
patternSize:图像中每行和每列圆形的数目。
corners:输出的圆形中心坐标。
flags:检测圆心的操作标志。
blobDetector:在浅色背景中寻找黑色圆形斑点的特征探测器。
角点位置优化函数:

bool cv.find4QuadCornerSubpix ( InputArray img, InputOutputArray corners, size region_size)

img:计算出内角点的图像。
patternSize:内角点坐标。
corners:优化坐标时考虑的邻域范围。

绘制内角点提取的结果:

void cv::drawChessboardCorners ( InputOutputArray image, size patternSize, InputArray corners, bool patternWasFound)

image:需要绘制角点的目标图像,必须是CU_8U的彩色图像。patternSize:标定板每行和每列角点的数目。
corners:检测到的角点坐标数组。
pattern WasFound:是否显示找到完成的标定板标志。

相机标定函数:

double cv::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:棋盘格内角点的三维坐标。
imagePoints:棋盘格内角点在图像中的二维坐标。
imageSize:图像的像素尺寸大小。
cameraMatrix:相机的内参矩阵。
distCoeffs:相机的畸变系数矩阵。
rvecs:相机坐标系与世界坐标系之间的旋转向量。
tvecs:相机坐标系与世界坐标系之间的平移向量。
flags:选择标定算法的标志。
本节应用案例如下:
本案例中采用了两张标定板的提取图像:
opencv_c++学习(二十七)
opencv_c++学习(二十七)
并将两个图片的路径存放到ca.txt文件中
opencv_c++学习(二十七)

int main() {

	//读取图像
	vector<Mat>imgs;
	string imgName;

	//读取存放图片路径的txt文件
	ifstream fin("ca.txt");
	//挨个读取图片
	while(getline(fin, imgName))
	{
		Mat img = imread(imgName);
		imgs.push_back(img);
	}

	//方格标定板内角点的数目(行,列)
	Size board_size = Size(9, 6);

	//存放内角点坐标
	vector<vector<Point2f>> imgsPoints;

	//开始内角点提取
	for (int i = 0; i < imgs.size(); i++)
	{
		Mat img1 = imgs[i];
		Mat gray1;
		cvtColor(img1, gray1, COLOR_BGR2GRAY);
		vector<Point2f> img1_points;

		//计算标定板的角点
		findChessboardCorners(gray1, board_size, img1_points);
		//细化方格标定板角点坐标
		find4QuadCornerSubpix(gray1, img1_points, Size(5, 5));

		bool pattern = true;

		drawChessboardCorners(img1, board_size, img1_points, pattern);
		namedWindow("img1", WINDOW_NORMAL);
		imshow("img1", img1);
		waitKey(0);
		imgsPoints.push_back(img1_points);
	}

	//生成每个内角点的空间坐标
	Size squareSize = Size(10, 10);
	vector<vector<Point3f>> objectPoints;
	for (int i = 0; i < imgsPoints.size(); i++)
	{
		vector<Point3f> tempPointSet;
		for (int j = 0; j < board_size.height; j++)
		{
			for (int k = 0; k < board_size.width; k++)
			{
				Point3f realPoint;
				//设标定板为世界坐标系的z平面,即z=0
				realPoint.x = j * squareSize.width;
				realPoint.y = k * squareSize.height;
				realPoint.z = 0;
				tempPointSet.push_back(realPoint);
			}
		}
		objectPoints.push_back(tempPointSet);
	}

	//图像尺寸
	Size imageSize;
	imageSize.width = imgs[0].cols;
	imageSize.height = imgs[0].rows;

	//摄像机内参数矩阵
	Mat cameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));

	//摄像机的5个畸变系数:k1,k2,p1,p2,k3
	Mat distCoeffs = Mat(1, 5, CV_32FC1, Scalar::all(0));

	//每幅图像的旋转向量、平移量
	vector<Mat>  rvecs, tvecs;

	calibrateCamera(objectPoints, imgsPoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, 0);
	cout << "相机的内参矩阵:" << cameraMatrix << endl;
	cout << "相机畸变系数:" << distCoeffs << endl;
	waitKey(0);
	return 0;
}

最终的运行结果如下图:
opencv_c++学习(二十七)
这里只放一张图像。最终的输出结果为:

相机的内参矩阵:[120.8643306554273, 0, 94.55565247064737;
 0, 119.979406894919, 55.48571212317609;
 0, 0, 1]
相机畸变系数:[-0.5559208449775317, 3.15840209023594, -0.001816753642197531, -0.01817901488786, -7.629569308066959]

四、图像矫正

opencv_c++学习(二十七)
如上图(左)可以看出,相机采集的数据造成了一定的畸变,尤其是在边缘部分。

去畸变函数:

void cv::undistort ( InputArray src, OutputArray dst, InputArray cameraMatrix, InputArray  distCoeffs, InputArray newCameraMatrix = noArray())

src:含有畸变的输入图像。
dst:去畸变后的输出图像,与输入图像具有相同的尺寸和数据类型。
cameraMatrix:相机内参矩阵(上节中相机标定获得)。
distCoeffis:相机的畸变矩阵,根据近似模型不同,参数数量可以为4、5、8、12或者14,如果是空矩阵表示没有畸变。
newCameraMatrix:畸变图像的相机内参矩阵,一般情况下与第三个参数相同或者使用默认值。
本节应用案例如下:文章来源地址https://www.toymoban.com/news/detail-462694.html

//用undiststort()函数直接计算校正图像
void undist(vector<Mat> imgs, //原有图像向量
	Mat cameraMatrix, //计算得到的相机内存
	Mat distCoeffs, //计算得到的相机畸变系数
	vector<Mat> &undistImgs //校正后的输出图像
)
{
	for (int i = 0; i < imgs.size(); i++)
	{
		Mat undisImg;
		undistort(imgs[i], undistImgs, cameraMatrix, distCoeffs);
		undistImgs.push_back(undisImg);
	}
}

int main() {

	//读取图像
	vector<Mat>imgs;
	string imgName;

	//读取存放图片路径的txt文件
	ifstream fin("ca.txt");
	//挨个读取图片
	while (getline(fin, imgName))
	{
		Mat img = imread(imgName);
		imgs.push_back(img);
	}

	//输入计算的内参矩阵和畸变矩阵(在相机厂家说明或者标定获得)
	Mat cameraMatrix = (Mat_<float>(3, 3) << 120.8643306554273, 0, 94.55565247064737,
	0, 119.979406894919, 55.48571212317609,
	0, 0, 1);

	Mat distCoeffs = (Mat_<float>(1, 5) << -0.5559208449775317, 3.15840209023594, -0.001816753642197531, -0.01817901488786, -7.629569308066959);

	//去畸变图像存放变量
	vector<Mat> undistImags;

	Size imageSize;

	imageSize.width = imgs[0].cols;
	imageSize.height = imgs[0].rows;

	undist(imgs, cameraMatrix, distCoeffs, undistImags);

	//显示校正后的图像
	for (int i = 0; i < imgs.size(); i++)
	{
		string windowNumber = to_string(i);
		imshow("矫正后的图像" + windowNumber, undistImags[i]);
		waitKey(0);
		destroyWindow("矫正后的图像" + windowNumber);
	}
	waitKey(0);
	return 0;
}

到了这里,关于opencv_c++学习(二十七)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • opencv_c++学习(二十二)

    图中左侧为边缘检测的效果,中间为图像经过二值化的效果,右图为凸包检测效果。 points:输入的2D点集。 hull:输出凸包的顶点。 clockwise:方向标志,当参数为true时,凸包顺序为顺时针方向,否则为逆时针方向。 returnPoints:输出数据的类型标志,当参数为true时第二个参数输出的

    2024年02月06日
    浏览(69)
  • OpenCV实现单目相机检测物体尺寸

    目录 步骤: Canny边缘检测算法介绍: 多边形逼近 代码实现: 效果展示: 导入必要的库: cv2 用于图像处理, numpy 用于数组操作。 定义了一个函数 preprocess ,用于对图像进行预处理。首先将图像转换为灰度图,然后进行高斯模糊来平滑图像。接着使用腐蚀操作进一步去除噪

    2024年02月07日
    浏览(44)
  • OpenCV实现求解单目相机位姿

            单目相机通过对极约束来求解相机运动的位姿。参考了ORBSLAM中单目实现的代码,这里用opencv来实现最简单的位姿估计.    首先通过ORB特征提取,获取两幅图像的匹配度,我将其连线出来的效果:   RANSAC的算法原理可以google,很容易理解。先看看ORBSLAM中的实现:

    2024年02月06日
    浏览(46)
  • 棋盘格测距-单目相机(OpenCV/C++)

    1’ 通过cv::findChessboardCorners寻找棋盘格角点 2‘ 用cv::solvePnP计算旋转向量rvec和平移向量tvec 3’ 通过公式计算相机到棋盘格的距离   已完成单目相机标定的情况下: (可以参考  虽然是我很久之前写的python的,但实现是没啥问题) 需要以下内容: 1、已知相机的内参矩阵 c

    2024年02月08日
    浏览(49)
  • opencv 单目相机pnp测距(Cpp)

    单目相机pnp测距是通过单目相机拍摄的一张2d图片,来测量图片中某物与相机的距离。 需要知道被测物的实际尺寸 测距前 需要先 相机标定 ,需要使用哪个相机进行测距就标定哪个。一旦换成了其他相机, 就要重新标定最终相机。 为什么要相机标定? 相机标定是为了得到从

    2024年02月04日
    浏览(41)
  • Python OpenCV 单目相机标定、坐标转换相关代码(包括鱼眼相机)

      本文不讲原理,只关注代码,有很多博客是讲原理的,但是代码最多到畸变矫正就结束了,实际上就是到 OpenCV 官方示例涉及的部分。   在官方示例中使用黑白棋盘格求解了相机的内外参和畸变系数,并对图像做了畸变矫正,但在实际使用时还缺少很多功能,以下是本

    2024年02月02日
    浏览(36)
  • 基于OpenCV的单目相机标定与三维定位

           相机是产生图像数据的硬件,广泛应用于消费电子、汽车、安防等领域。围绕着相机衍生出一系列的研究与应用领域,包括传统的图像处理和基于深度学习的智能应用等。目前大火的自动驾驶中相机也是重要的硬件组成,如环视用鱼眼相机,adas用周视相机。    

    2024年02月09日
    浏览(37)
  • OpenCV快速入门:相机标定——单目视觉和双目视觉

    在当今科技日益发展的时代,计算机视觉作为人工智能的重要分支,已经深入到我们生活的各个领域。在这个广阔的领域中,相机标定是一个基础且关键的步骤,它直接影响到视觉系统的精度和效能。尤其是在单目视觉和双目视觉的应用中,准确的相机标定成为了实现高效和

    2024年02月05日
    浏览(49)
  • 【计算机视觉】OpenCV实现单目相机标定

    文章目录 单目相机标定(基于Python OpenCV) 1.上期填坑 2.单目相机标定 2.1 数据采集 2.2 角点提取 2.3 参数求解 2.4 参数评估(重投影误差) 2.5 相机位姿(棋盘位姿)可视化 2.6 同Matlab标定结果比较 在开始本篇博客之前,先填一下上一篇博客【计算机视觉】基于ORB角点+RANSAC算法实现图像

    2023年04月18日
    浏览(62)
  • 视觉相机模型以及投影原理推导——(单目)

    参考文献:视觉SLAM十四讲、视觉惯性SLAM理论与源码分析、该博客、文中的公式直接引用上面的文章,如有侵权请联系本人删除 投影过程 三维世界中的物体(目标点)P反射光线,通过相机光心,投影到相机的感光平面(物理成像平面/像素成像平面),一个个的光线投影点汇

    2024年02月09日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包