opencv_c++学习(二十八)

news2024/11/25 23:36:42

一、单目相机位姿估计

在这里插入图片描述
如上图所示,根据图像的情况反推相机的运动情况。
如实现上述功能则需要拍摄当前物体的图像,然后拍摄一段时间之后物体的图像,然后联合两张图像则可以获取两个时刻的相机位姿关系。
位姿估计函数:

bool cv:solvePnP( InputArray objectPoints, InputArray imagePoints, InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec, useExtrinsicGuess =, bool false, int flags = 5OLVEPNP_ITERATIVE)

objectPoints:前一时刻世界坐标系中的3D点的三维坐标。
imagePoints: 3D点在图像中对应的像素点的二维坐标。
cameraMatrix:相机的内参矩阵。
distCoeffs:相机的畸变系数矩阵。
rvec:世界坐标系变换到相机坐标系的旋转向量。
tvec:世界坐标系变换到相机坐标系的平移向量。
uscExtrinsicGuess:是否使用旋转向量初值和平移向量初值的标志。
flags:选择解算PnP问题方法的标志。
本节应用案例如下:

int main() {

	//读取图片
	Mat src = imread("left1.jpg");
	Mat gray;
	if (src.empty())
	{
		printf("不能打开空图片");
		return -1;
	}

	cvtColor(src, gray, COLOR_BGR2GRAY);
	vector<Point2f> imgpoints;
	Size boardSize = Size(9,6);
	//计算标定板的角点
	findChessboardCorners(gray, boardSize, imgpoints);
	//细化方格标定板角点坐标
	find4QuadCornerSubpix(gray, imgpoints, Size(5, 5));

	//棋盘格每个方格的真实尺寸
	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) << 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);

	//用PnP算法计算旋转和平移量
	Mat rvec, tvec;
	solvePnP(PointSets, imgpoints, cameraMatrix, distCoeffs, rvec, tvec);
	cout << "旋转向量为: " << rvec << endl;

	//旋转向量转换旋转矩阵
	Mat R;
	Rodrigues(rvec, R);
	cout << "旋转矩阵为:" << R << endl;

	//用PnP + Ransac算法计算旋转向量和平移向量
	Mat rvecRansac, tvecRansac;

	solvePnPRansac(PointSets, imgpoints, cameraMatrix, distCoeffs, rvecRansac, tvecRansac);
	Mat RRansac;
	Rodrigues(rvecRansac, RRansac);
	cout << "旋转矩阵" << RRansac << endl;
	waitKey(0);
	return 0;	 
}

二、插值法从视频中跟踪移动的物体

在这里插入图片描述
计算差值绝对值函数:

void cv::absdiff ( InputArray src1, InputArray src2, OutputArray dst)

srcl:第一个数组或者Mat类矩阵。
src2:第二个数组或者Mat类矩阵,需要与第一个参数具有相同的尺寸和数据类型。
dst:两个数据差值的绝对值,与输入数据具有相同的尺寸和数据类型。
本节应用案例如下:

int main() {

	//读取视频
	VideoCapture capture("1.mp4");
	if (!capture.isOpened())
	{
		printf("不能打开空图片");
		return -1;
	}

	//获取视频相关信息
	//帧率
	int fps = capture.get(CAP_PROP_FPS);
	//宽度
	int wideth = capture.get(CAP_PROP_FRAME_WIDTH);
	//高度
	int height = capture.get(CAP_PROP_FRAME_HEIGHT);
	//总帧数
	int num_of_frames = capture.get(CAP_PROP_FRAME_COUNT);

	//读取视频中第一幅图像作为前一帧图像,并进行灰度化
	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);

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

三、稠密光流法实现物体跟踪

在这里插入图片描述
在这里插入图片描述

void cv::calcOpticalFlowFarneback ( InputArray prev, InputArray  next, InputOutputArray flow,double pyr_scale, int levels, int winsize, int iterations, int poly_n. double poly_sigma, int flags)

prev:前一帧图像,必须是CV_8UC1类型。
next:当前帧图像,与前一帧图像具有相同的尺寸和数据类型。
flow:输出的光流图像,图像与前一帧图像具有相同的尺寸,为CV_32F双通道图像。
pyr_scale:图像金字塔两层之间尺寸缩放的比例。
levels:构建图像金字塔的层数。
winsize:均值窗口的尺寸。
iterations:算法在每个金字塔图层中迭代的次数。
poly_n:在每个像素中找到多项式展开的像素邻域的大小。
poly_sigma:高斯标准差。
flags:计算方法标志。
本节应用案例如下:

int main() {

	//读取视频
	VideoCapture capture("1.mp4");
	if (!capture.isOpened())
	{
		printf("不能打开空图片");
		return -1;
	}

	//读取视频中第一幅图像作为前一帧图像,并进行灰度化
	Mat preFrame, preGray;
	capture.read(preFrame);
	cvtColor(preFrame, preGray, COLOR_BGR2GRAY);

	while (true)
	{
		Mat nextFrame, nextGray;
		//视频中所有图像处理完成后退出循环
		if (!capture.read(nextFrame))
		{
			break;
		}

		imshow("input", nextFrame);

		//计算稠密光流
		cvtColor(nextFrame, nextGray, COLOR_BGR2GRAY);
		//两个方向的运动速度
		Mat_<Point2f> flow;
		calcOpticalFlowFarneback(preGray, nextGray, flow, 0.5, 3, 15, 3, 5, 1.2, 0);

		//x方向移动速度
		Mat xV = Mat::zeros(preFrame.size(), CV_32FC1);
		//y方向移动速度
		Mat yV = Mat::zeros(preFrame.size(), CV_32FC1);

		//获取两个方向的速度
		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(preFrame.size(), preFrame.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("result", rgbImg);

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

四、稀疏光流法实现物体跟踪

与稀疏光流法的计算方式相同,但唯一不同的地方就是稀疏光流法并不是计算整个图像的像素点,而是选取图像中有代表性的点来实现物体的跟踪。

void cv::calcOpticalFlowPyrLK ( InputArray previmg, InputArray nextlmg, InputArray prevPts, InputOutputArray nextPts, OutputArray status, OutputArray err, Size winSize = Size(21,21), int maxLevel = 3, criteria =, TermCriteria Termcriteria(TermCriteria: :COUNT+TermCriteria: : EPS,308.81), int flags =0, double minEligThreshold = 1e-4)

prevPts:前一帧图像的稀疏光流点坐标,必须是单精度浮点数。
nextPts:当前帧中与前一帧图像稀疏光流点匹配成功的稀疏光流点坐标,同样必须是单精度浮点数。
status:输出状态向量,如果在两帧图像中寻找到相对应的稀疏光流点,那么向量值为1,否则向量值为0。
err:输出误差向量,向量每个元素都设置为对应点的误差,度量误差的
标准可以在flags参数中设置。
winSize:每层金字塔中搜索窗口的大小,默认Size(21,21)。
maxLevel:构建图像金字塔层数,参数值为从0开始的整数。
criteria:迭代搜索的终止条件。
flags:寻找匹配光流点的操作标志。
minEig Threshold:响应的最小特征值。
本节应用案例如下:

//颜色查找表
vector<Scalar>color_lut;
void draw_lines(Mat &image, vector<Point2f> pt1, vector<Point2f> pt2)
{
	RNG rng(10000);
	if (color_lut.size() < pt1.size())
	{
		for (size_t t = 0; t < pt1.size(); t++)
		{
			color_lut.push_back(Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)));
		}
	}
	for (size_t t = 0; t < pt1.size(); t++)
	{
		line(image, pt1[t], pt2[t], color_lut[t], 2, 8, 0);
	}
}

int main() {

	//读取视频
	VideoCapture capture("1.mp4");
	Mat preframe, preImg;
	if (!capture.read(preframe))
	{
		printf("不能打开空图片");
		return -1;
	}

	//读取视频中第一幅图像作为前一帧图像,并进行灰度化
	cvtColor(preframe, preImg, COLOR_BGR2GRAY);

	//角点检测相关参数设置
	vector<Point2f> Points;
	double qualityLevel = 0.01;
	int minDistance = 10;
	int blockSize = 3;
	bool useHarrisDetector = false;
	double k = 0.04;
	int Corners = 5000;

	//开始角点检测
	vector<Point2f> prevPts;  //前一幅图像的角点坐标
	vector<Point2f> nextPts;  //当前帧图像的角点坐标
	vector<uchar> status; //检点检测到的状态
	vector<float> err;
	TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, 0.01);
	double derivlambda = 0.5;
	int flags = 0;

	//初始状态的角点
	vector<Point2f>initPoints;
	initPoints.insert(initPoints.end(), Points.begin(), Points.end());

	//前一帧图像中角点坐标
	prevPts.insert(prevPts.end(), Points.begin(), Points.end());

	while (true)
	{
		//读取视频
		Mat nextFrame, nextImg;
		if (!capture.read(nextFrame))
		{
			break;
		}


		//光流法跟踪
		cvtColor(nextFrame, nextImg, COLOR_BGR2GRAY);
		imshow("nextFrame", preImg);
		calcOpticalFlowPyrLK(preImg, nextImg, prevPts, nextPts, status, err, 
			Size(31, 31), 3, criteria, derivlambda, flags);

		//判断角点是否移动,如果不移动就删除
		size_t i, k;
		for (i = k = 0; i < nextPts.size(); i++)
		{
			//距离与状态测量
			double dist = abs(prevPts[i].x - nextPts[i].x + abs(prevPts[i].y - nextPts[i].y));
			if (status[i] && dist > 2)
			{
				prevPts[k] = prevPts[i];
				initPoints[k] = initPoints[i];
				nextPts[k++] = nextPts[i];
				circle(nextFrame, nextPts[i], 3, Scalar(0, 255, 0), -1, 8);
			}
		}

		//更新移动角点数目
		nextPts.resize(k);
		prevPts.resize(k);
		initPoints.resize(k);

		//绘制跟踪轨迹
		draw_lines(nextFrame, initPoints, nextPts);
		imshow("result", nextFrame);

		//延迟5毫秒延迟判断是否退出程序,按ESC退出
		char c = waitKey(50);

		//更新角点坐标和前一帧图像
		std::swap(nextPts, prevPts);
		nextImg.copyTo(preImg);

		//如果角点数目少于30,就重新检测角点
		if (initPoints.size() < 30)
		{
			goodFeaturesToTrack(preImg, Points, Corners, qualityLevel,
				minDistance, Mat(), blockSize, useHarrisDetector, k);
			initPoints.insert(initPoints.end(), Points.begin(), Points.end());
			prevPts.insert(prevPts.end(), Points.begin(), Points.end());
		}
	}
	return 0;
}

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

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

相关文章

Musl libc 库成功适配到 openEuler Embedded,推动欧拉嵌入式生态发展

近期&#xff0c;RISC-V SIG 在欧拉嵌入式操作系统上成功实现了 musl libc 的适配&#xff0c;完成了使用 musl libc 库替换 glibc 库构建镜像的工作。目前&#xff0c;以 musl libc 为基础库编译的镜像已在 Raspberry Pi4 开发板上可用&#xff0c;这一成果推动了 openEuler E…

C Primer Plus第十一章编程练习答案

学完C语言之后&#xff0c;我就去阅读《C Primer Plus》这本经典的C语言书籍&#xff0c;对每一章的编程练习题都做了相关的解答&#xff0c;仅仅代表着我个人的解答思路&#xff0c;如有错误&#xff0c;请各位大佬帮忙点出&#xff01; 1.设计并测试一个函数&#xff0c;从输…

《Opencv3编程入门》学习笔记—第二章

《Opencv3编程入门》学习笔记 记录一下在学习《Opencv3编程入门》这本书时遇到的问题或重要的知识点。 第二章 OpenCV 官方例程引导与赏析 openv官方提供的示例程序&#xff1a;具体位于..\opencv\sources\samples\cpp ..\opencv\sources\samples\cpp\tutorial_code路径下存…

sql优化常用的方法

文章目录 1、explain 输出执行计划2、in 和 not in 要慎用3、少用select *4、善用limit 15、 order by字段建索引6、count(*)推荐使用7、where 子句中避免is null /is not null8、应尽量避免在 where!或<>9、应尽量避免在 where 子句中使用 or10、尽量用union all代替uni…

了不起的互联网老男孩,在创业路上不掉队

“青春如同奔流的江河&#xff0c;一去不回来不及道别”&#xff0c;老男孩这首歌戳中了太多职场中年男人的心酸苦楚&#xff0c;面对经济下行压力、互联网行业变革以及中年职场危机&#xff0c;互联网人应该如何应对&#xff1f;如何建立和现实叫板的能力&#xff1f; 有2位在…

shiro入门实战

​​​​​​​Apache Shiro | Simple. Java. Security. java语言编写 架构 shiro认证流程 使用 添加shiro依赖 <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.4.0</version>&l…

V2.0-在记事本功能上添加fork和wait

第一篇只是简单使用了open&#xff0c;read,write,lseek实现了基本的记事本功能&#xff1b; 但是当前的系统是linux&#xff0c;应该发挥他的多进程&#xff0c;多线程的作用&#xff1b; 所以&#xff0c;本篇添加创建子进程和父进程等待子进程退出的功能。 有几个注意点&a…

如何创建新一代Web3企业

日前&#xff0c;我们对话了Sui基金会的增长负责人Koh Kim&#xff0c;对如何成功构建持续发展的企业等话题展开讨论。 您在Sui基金会的工作重点帮助开发者&#xff0c;让他们从产品开发的早期阶段成长为强大且具有潜力的企业领导者。可以简单分享一下您为此目标创建的计划吗&…

Linux进程地址空间——下篇

目录 一.深入了解进程地址空间&#xff1a; 单个进程与进程地址空间与物理内存之间的联系图&#xff1a; 多个进程与进程地址空间与物理内存之间的联系图&#xff1a; 二.为什么会存在进程地址空间呢&#xff1f; 作用1&#xff1a;进程地址空间的存在&#xff0c;保证了其他…

Flutter 笔记 | Flutter 文件IO、网络请求、JSON、日期与国际化

文件IO操作 Dart的 IO 库包含了文件读写的相关类&#xff0c;它属于 Dart 语法标准的一部分&#xff0c;所以通过 Dart IO 库&#xff0c;无论是 Dart VM 下的脚本还是 Flutter&#xff0c;都是通过 Dart IO 库来操作文件的&#xff0c;不过和 Dart VM 相比&#xff0c;Flutte…

6.1 进程的创建和回收

目录 进程概念 程序 进程 进程内容 进程控制块 进程类型 进程状态 常用命令 查看进程信息 进程相关命令 进程的创建和结束 子进程概念 子进程创建-fork 父子进程 进程结束-exit/_exit 进程结束-exit-示例1 进程结束-exit-示例2 进程回收 进程回收-wait 进程回…

企业数字化转型,为什么会加快商业智能BI的发展

对于企业数字化转型来说&#xff0c;数据是其中提到最多的词汇。当今世界&#xff0c;随着人们认识到数据的重要性&#xff0c;明白了数据发挥价值的方式及其意义&#xff0c;数据资产就成为数字化转型企业需要掌握利用的关键。 数据可视化 - 派可数据商业智能BI可视化分析平台…

服务windows服务+辅助角色服务

1、vs2022新建一个windows服务项目 2、修改服务参数 &#xff08;1&#xff09;AutoLog: 是否将事件写入到windows的事件日志中。 &#xff08;2&#xff09;canpauseandContinue:服务是否可以暂停和继续 3、添加服务安装程序 在界面内右击鼠标 新建一个服务、新建后如下图&a…

【运维】speedtest测试

目录 docker 布署 布署云端 docker布署 云端放置于已有容器里 librespeed/speedtest: Self-hosted Speedtest for HTML5 and more. Easy setup, examples, configurable, mobile friendly. Supports PHP, Node, Multiple servers, and more (github.com) docker 布署 获取…

探讨生产环境下缓存雪崩的几种场景及解决方案

本文首发自「慕课网」&#xff08;www.imooc.com&#xff09;&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"或慕课网公众号&#xff01; 作者&#xff1a;大能 | 慕课网讲师 缓存我们经常使用&#xff0c;但是有时候我们…

如何撤消 Git 中最新的本地提交?

在使用Git进行版本控制时&#xff0c;有时我们可能会犯下错误或者想要撤销最新的本地提交。Git提供了一些强大的工具和命令&#xff0c;使我们能够轻松地撤消最近的提交并修复错误。 本文将详细介绍如何在Git中撤消最新的本地提交。 步骤1&#xff1a;查看提交历史 在撤消最新…

Centos7安装Java8(在线安装避坑详细安装)

开篇语&#xff1a; 喜欢在一个明媚阳光的午后 坐在那夕阳斑驳的南墙下 听着风起 闻着花香 望着远山 身边是你 如此便觉得很好 1.查看目前环境 rpm -qa|grep jdk在这里我们会发现&#xff0c;原有系统安装有jdk&#xff0c;如果对于jdk有要求&#xff0c;我们就需要重新安装jdk…

Liunx网络基础(3)传输层(TCP/UDP)可靠传输、字节流传输等

传输层协议 传输层协议解析: 负责两端之间的数据传输; TCP/ UDP 1. UDP UDP: 用户数据报协议&#xff0c;无连接&#xff0c;不可靠&#xff0c;面向数据报传输 重点: 协议格式&#xff0c;协议特性&#xff0c;特性对于编程的影响 协议格式&#xff1a; 16位源端口 & 16位…

2023-05-29 用 fltk gui库编写一个打字练习程序

用 fltk gui库编写一个打字练习程序 前言一、FLTK GUI 库二、使用步骤1.引入库2.使用代码 总结 前言 给孩子练习键盘打字, 发现终端还是欠点意思, 研究了一下gui, 最终用 fltk库弄了一个. 对于没有接触过gui的人, 发现, 编程的逻辑和终端区别很大, 很繁琐, 可能需要适应适应,…

Windows远程Centos7图形化界面

一、centos7服务器安装tigervnc 1、更新yum源 yum update 2、安装tigervnc yum -y install tigervnc* 3、启动vnc vncserver &#xff08;1&#xff09;执行命令后需要输入密码 &#xff08;2&#xff09;再次输入密码 注意&#xff1a;密码一定要记住&#xff0c;方便以…