单目相机标定、图像校正、单目位姿估计、差值法检测移动物体、稠密光流法跟踪移动物体

news2024/11/27 10:26:56

目录

1、单目相机标定

2、图像校正

3、单目位姿估计

4、差值法检测移动物体

5、稠密光流法跟踪移动物体


1、单目相机标定

 

 

 

 

 

 

//单目相机标定
int test1()
{
	//读取所有图像
	vector<Mat> imgs;
	string imageName;
	ifstream fin("F:/testMap/calibdate.txt");
	while(getline(fin, imageName))
	{
		Mat img = imread(imageName);
		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);
		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));//摄像机内参数矩阵
	Mat distCoeffs = Mat(1, 5, CV_32FC1, Scalar::all(0));//摄像机的5个畸变系数:k1,k2,p1,p2, k3
	vector<Mat> rvecs;//每幅图像的旋转向量
	vector<Mat> tvecs;//每张图像的平移量
	calibrateCamera(objectPoints, imgsPoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, 0);
	cout << "相机的内参矩阵=" << endl << cameraMatrix << endl;
	cout << "相机畸变系数" << distCoeffs << endl;

	waitKey(0);
	return 0;
}

2、图像校正

 

 

//图像校正
//用undistort()函数直接计算校正图像
//所有原图像向量  计算得到的相机内参  计算得到的相机畸变系数 校正后的输出图像
void undist(vector<Mat> imgs, Mat cameraMatrix, Mat distCoeffs, vector<Mat> &undistImgs)
{
	for (int i = 0; i < imgs.size(); i++)
	{
		Mat undistImg;
		undistort(imgs[i], undistImg, cameraMatrix, distCoeffs);
		undistImgs.push_back(undistImg);
	}
}
int test2()
{
	//读取所有图像
	vector<Mat> imgs; 
	string imageName;
	ifstream fin("F:/testMap/calibdate.txt");
	while (getline(fin, imageName))
	{
		Mat img = imread(imageName);
		imgs.push_back(img);
	}

	//输入前文计算得到的内参矩阵
	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);

	vector<Mat> undistImgs;
	Size imageSize;
	imageSize.width = imgs[0].cols;
	imageSize.height = imgs[0].rows;

	//用undistort()函数直接计算校正图像,下一行代码取消注释即可
	undist(imgs, cameraMatrix, distCoeffs, undistImgs);

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

	waitKey(0);
	return 0;
}

3、单目位姿估计

 

 

//单目位姿估计
int test3()
{
	//读取所有图像
	Mat img = imread("F:/testMap/left01.png");
	Mat gray;
	cvtColor(img,gray,COLOR_BGR2GRAY); 
	vector<Point2f> imgPoints;
	Size boardSize = Size(9,6);
	findChessboardCorners(gray,boardSize, imgPoints);//计算方格标定板角点
	find4QuadCornerSubpix(gray,imgPoints,Size(5,5));//细化方格标定板角点坐r
	
	//生成棋盘格每个内角点的空间三维坐标
	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);
		}
	}

	//输入前文计算得到的内参矩阵和畸变矩阵
	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);
	
	//用PnP算法计算旋转和平移量
	Mat rvec,tvec ;
	solvePnP(PointSets, imgPoints,cameraMatrix, distCoeffs,rvec,tvec); 
	cout << "世界坐标系变换到相机坐标系的旋转向量:" << rvec << endl;
	
	//旋转向量转换旋转矩阵
	Mat R;
	Rodrigues(rvec,R);
	cout << "旋转向量转换成旋转矩阵:" << endl << R << endl;
	
	//用PnP+Ransac算法计算旋转向量和平移向量
	Mat rvecRansac, tvecRansac;
	solvePnPRansac(PointSets, imgPoints,cameraMatrix, distCoeffs,rvecRansac,tvecRansac);
	
	Mat RRansac;
	Rodrigues(rvecRansac,RRansac);
	cout << "旋转向量转换成旋转矩阵:" << endl << RRansac << endl;

	waitKey(0);
	return 0;
}

4、差值法检测移动物体

 

 

//差值法检测移动物体
int test4()
{
	//加载视频文件,并判断是否加载成功
	VideoCapture capture("F:/testMap/lolTFT.mp4");
	if (!capture.isOpened())
	{
		cout << "请确认视频文件是否正确" << endl;
		return -1;
	}
	//输出视频相关信息
	int fps = capture.get(CAP_PROP_FPS);
	int width = capture.get(CAP_PROP_FRAME_WIDTH);
	int height = capture.get(CAP_PROP_FRAME_HEIGHT);
	int num_of_frames = capture.get(CAP_PROP_FRAME_COUNT);
	cout << "视频宽度:" << width << "视频高度:" << height << "视频帧率 : "
		<< fps << "视频总帧数*" << num_of_frames << endl;

	//读取视频中第一帧图像作为前一帧图像,并进行灰度化
	Mat preFrame, preGray;
	capture.read(preFrame);
	cvtColor(preFrame, preGray, COLOR_BGR2GRAY);
	//对图像进行高斯滤波,减少噪声干扰
	GaussianBlur(preGray, preGray, Size(0, 0), 15);

	Mat binary;
	Mat frame, gray;
	//形态学操作的矩形模板
	Mat k = getStructuringElement(MORPH_RECT, Size(7, 7), Point(-1, -1));
	while (true)
	{
		//视频中所有图像处理完后推出循环
		if (!capture.read(frame))
		{
			break;
		}
		//对当前帧进行灰度化
		cvtColor(frame, gray, COLOR_BGR2GRAY);
		GaussianBlur(gray, gray, Size(0, 0), 15);

		//计算当前帧与前一帧的差值的绝对值
		absdiff(gray, preGray, binary);

		//对计算结果二值化并进行开运算,减少噪声的干扰
		threshold(binary, binary, 10, 255, THRESH_BINARY | THRESH_OTSU);
		morphologyEx(binary, binary, MORPH_OPEN, k);

		//显示处理结果
		imshow("input", frame); imshow("result", binary);

		//将当前帧变成前一倾,准备下一个循环,注释掉这句话为固定背景
		//gray.copyTo(preGray) ;

		//5毫秒延时判断是否推出程序,按ESC键退出
		char c = waitKey(5);
		if (c == 27)
		{
			break;
		}
	}
	waitKey(0);
	return 0;
}

5、稠密光流法跟踪移动物体

 

 

 

//稠密光流法跟踪移动物体
int test5()
{
	VideoCapture capture("F:/testMap/lolTFT.mp4");
	Mat prevFrame,prevGray;
	if (!capture.read(prevFrame))
	{
		cout << "请确认视频文件名称是否正确" << endl;
		return -1;
	}
	//将彩色图像转换成灰度图像
    cvtColor(prevFrame, prevGray, COLOR_BGR2GRAY);

	while (true)
	{
		Mat nextFrame,nextGray;//所有图像处理完成后推出程序
		if (!capture.read(nextFrame))
		{
			break;
		}
		imshow("视频图像", nextFrame) ;
		
		//计算稠密光流
		cvtColor(nextFrame,nextGray,COLOR_BGR2GRAY); 
		Mat_<Point2f> flow;//两个方向的运动速度
		calcOpticalFlowFarneback(prevGray,nextGray,flow,0.5,3,15,3,5,1.2,0);
		
		Mat xV = Mat::zeros(prevFrame.size(),CV_32FC1);//x方向移动速度
		Mat yV = Mat::zeros(prevFrame.size(),CV_32FC1);//y方向移动速度
		
		//提取两个方向的速度
		for (int row = 0; row < flow.rows; row++)
		{
			for (int col = 0; col < flow.cols; col++)
			{
				const Point2f& flow_xy = flow.at<Point2f>(row,col); 
				xV.at<float>(row, col) = flow_xy.x;
				yV.at<float>(row, col) = flow_xy.y;
			}
		}

		//计算向量角度和幅值
		Mat magnitude,angle;
		cartToPolar(xV, yV, magnitude,angle);
		
		//角度转换成角度制
		angle = angle * 180.0 / CV_PI / 2.0;//把幅值归一化到0-255区间便于显示结果
		normalize(magnitude,magnitude,0,255,NORM_MINMAX);
		
		//计算角度和幅值的绝对值
		convertScaleAbs(magnitude,magnitude); convertScaleAbs(angle, angle);
		
		//运动的幅值和角度生成HSV颜色空间的图像
		Mat HSV = Mat::zeros(prevFrame.size(), prevFrame.type());
		vector<Mat> result;
		split(HSV,result); 
		result[0] = angle; //决定颜色
		result[1] = Scalar(255);
		result[2] = magnitude;//决定形态
		
		//将三个多通道图像合并成三通道图像
		merge(result,HSV);

		//讲HSV颜色空间图像转换到RGB颜色空间中
		Mat rgbImg;
		cvtColor(HSV,rgbImg,COLOR_HSV2BGR);//显示检测结果
		imshow("运动检测结果", rgbImg);
		int ch = waitKey(5);
		if (ch == 27)
		{
			break;
		}
	}

	waitKey(0);
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/759840.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AtCoder Regular Contest 159

B - GCD Subtraction 题意&#xff1a; 给定两个正整数 A , B A,B A,B&#xff0c;给定一个操作&#xff1a;令 g g c d ( A , B ) ggcd(A, B) ggcd(A,B)&#xff0c;令 A A − g , B B − g AA-g, BB-g AA−g,BB−g。问最少经过多少次操作之后其中一个数变为0. 思路&…

APPScan介绍以及安装方式【附带链接】

AppScan介绍和安装 请务必下载绑定的链接&#xff0c;避免环境错误 1.简介 Appscan 10中文版是是全新网络安全漏洞扫描软件&#xff0c;软件可以直接可以对OS命令、SSRF和XXE攻击等漏洞进行检测&#xff0c;使得漏洞检测更加容易&#xff0c;提高漏洞的扫描效率。软件同时支…

[LeetCode周赛复盘] 第 354 场周赛20230716

[LeetCode周赛复盘] 第 354 场周赛20230716 一、本周周赛总结6889. 特殊元素平方和1. 题目描述2. 思路分析3. 代码实现 6929. 数组的最大美丽值1. 题目描述2. 思路分析3. 代码实现 6927. 合法分割的最小下标1. 题目描述2. 思路分析3. 代码实现 6924. 最长合法子字符串的长度1.…

Go语言之重要数组类型map(映射)类型

通过切片&#xff0c;我们可以动态灵活存储管理学生姓名、年龄等信息&#xff0c;比如 names : []string{"张三","李四","王五"} ages : []int{23,24,25} fmt.Println(names) fmt.Println(ages)但是如果我想获取张三的年龄&#xff0c;这是一个…

概率论的学习和整理17:EXCEL的各种期望,方差的公式

目录 1 总结 1.1 本文目标总结方法 1.2 总结一些中间关键函数 2 均值和期望 2.1 求均值的公式 2.2 求随机变量期望的公式 2.3 求随机变量期望的朴素公式 3 方差 3.1 确定数的方差 3.2 统计数的方差公式 3.3 随机变量的方差公式 3.4 EXCEL提供的直接计算方差的公式 …

Ant Design Vue组件,a-select标签

a-select标签是组件里的选择框&#xff0c;具体使用可以查看官网&#xff0c;这里记录一下在使用中遇到的问题。 最近在做项目的时候有一个需求在 a-modal 标签中加入 a-select 标签&#xff0c;a-modal 是模态对话框&#xff0c;意思就是在模态对话框里面添加选择框&#xff0…

Cglib 动态代理实现

每天看看新东西,心情也要好上许多 问题 cglib是如何实现动态代理的cglib如何支持类的代理cglib和jdk的动态代理有什么区别 使用方式 cglib不属于jdk的一部分,因此要使用需要先引入相应的包,maven依赖如下 <dependency><groupId>cglib</groupId><artif…

TortoiseGit 入门指南09:合并

前面章节讲了 分支&#xff0c;提到一种常用的工作流&#xff1a;将默认分支&#xff08;master&#xff09;设置为主分支&#xff0c;保存最新的、随时可以发布的版本&#xff0c;所有的新特性、BUG都在另一个称为特性分支上增加或修改&#xff0c;然后在一个合适点&#xff0…

Ubuntu下搭建Redis主从集群

目录 准备实例和配置 开启主从关系 测试配置 搭建的主从集群结构&#xff0c;只有主服务器与客户端进行写操作&#xff0c;通过主从同步数据&#xff0c;从服务器向客户端提供读操作 共包含三个节点&#xff0c;一个主节点&#xff0c;两个从节点。 这里我们会在同一台虚拟机…

【C++】多线程编程二(std::thread详解)

目录 std::thread详解 &#xff08;1&#xff09;启动线程 ①无参无返回的函数作为入参 ②函数对象&#xff08;仿函数&#xff09;作为入参 &#xff08;2&#xff09;不等待线程detch() &#xff08;3&#xff09;等待线程完成join() &#xff08;4&#xff09;向线程…

CANoe如何配置Master/Slave模式

系列文章目录 文章目录 系列文章目录前言一、CANoe配置端口二、CANoe配置Master模式三、CANoe配置Slave模式前言 随着智能电动汽车的行业的发展,车载以太网的应用越来越广泛,最近很多朋友在问CANoe Master/Slave模式如何设置,车载以太网物理层也有一项是测试Master/Slave模式…

springcloud整合nacos实现注册发现中心

文章目录 微服务为什么需要服务注册发现中心怎么使用注册发现中心1.本示例环境2.nacos 安装3.pom.xml4.application.yml5.NacosDiscoveryDemoController6.ServerConfig7.NacosNacosDiscoveryServiceImpl8.启动用http工具测试结果 如果需要完整源码请关注公众号"架构殿堂&q…

2023.7.16-偶数(奇数)的枚举

功能&#xff1a;输入一个整数&#xff0c;结果打印出所有不大于这个整数的偶数。 程序&#xff1a; #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main() {int a, b;printf("请输入一个整数&#xff1a;");scanf("%d",&a);print…

Android之Intent

意图介绍 一个意图(Intent)对象包含了目标组件、动作、数据、类别、附加数据、标志六个部分。 目标组件 目标组件可以帮助应用发送显式意图调用请求。在创建Intent时&#xff0c;可以通过setComponent方法来设置一个组件&#xff0c;如&#xff1a; //设置组件 intent.setC…

19.基于XML的自动装配

基于XML的自动装配 自动装配&#xff1a; 根据指定的策略&#xff0c;在IOC容器中匹配某一个bean&#xff0c;自动为指定的bean中所依赖的类类型或接口类型属性赋值 使用bean标签的autowire属性设置自动装配效果(默认为no和defalse不进行装配——bean中的属性不会自动匹配某个b…

Nodejs的字节操作(Buffer)

Hi I’m Shendi Nodejs的字节操作&#xff08;Buffer&#xff09; 字节操作是一个编程语言中必不可少的&#xff0c;而在NodeJs中也可以很方便的进行字节操作。 Buffer类 在 js 中没有二进制数据类型&#xff0c;但在一些情况下必须使用到二进制数据类型&#xff0c;比如网络通…

ModaHub魔搭社区:AI原生云向量数据库Zilliz Cloud与 OpenAI 集成搭建相似性搜索系统

目录 准备工作 检索图书 本文将讨论如何使用 OpenAI 的 Embedding API 与 Zilliz Cloud 搭建相似性搜索系统。 在本篇中你将看到如何使用 OpenAI 的 Embedding API 和 Zilliz Cloud 完成图书检索。当前,很多的图书检索方案,包括公共图书馆里使用的那些方案,都是使用关键词…

简单认识MySQL数据库事务

文章目录 一、MySQL事务的概念1、简介2、事务的ACID特点1.原子性&#xff08;Atomicity&#xff09;2.一致性&#xff08;Consistency&#xff09;3.隔离性&#xff08;lsolation&#xff09;4.持久性&#xff08;Durability) 3、并发访问表的一致性问题和事务的隔离级别1.并发…

C# Modbus通信从入门到精通(6)——Modbus RTU(0x04功能码)

1、04(0x04)读输入寄存器 使用该功能码能从远程地址中读取1到125个输入寄存器的值,每个输入寄存器都占两个字节,读取的输入寄存器数量由主站读取时指定。 2、发送报文格式 更详细的格式如下: 从站地址+功能码+起始地址高位+起始地址低位+寄存器数量高位+寄存器数量低位+…

备战求战 | 笔试强训6

目录 一、选择题 二、编程题 三、选择题题解 四、编程题题解 一、选择题 1、十进制变量i的值为100&#xff0c;那么八进制的变量i的值为&#xff08;&#xff09; A. 146 B. 148 C. 144 D. 142 2、执行下面语句后的输出为 int I1; if(I<0)printf("****\n") …