opencv_c++学习(二十八)

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

一、单目相机位姿估计

opencv_c++学习(二十八)
如上图所示,根据图像的情况反推相机的运动情况。
如实现上述功能则需要拍摄当前物体的图像,然后拍摄一段时间之后物体的图像,然后联合两张图像则可以获取两个时刻的相机位姿关系。
位姿估计函数:

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;	 
}

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

opencv_c++学习(二十八)
计算差值绝对值函数:

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;
}

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

opencv_c++学习(二十八)
opencv_c++学习(二十八)

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:响应的最小特征值。
本节应用案例如下:文章来源地址https://www.toymoban.com/news/detail-468322.html

//颜色查找表
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;
}

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

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

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

相关文章

  • opencv_c++学习(二十五)

    1、海瑞斯角点不可能出现在图像平滑的区域(上图1); 2、图像边缘的支线出不可能出现海瑞斯角点(上图2); 3、海瑞斯角点会出现在顶点处。(上图3); 上图中的下半部分红色圆圈内就是海瑞斯角点常出现的地方。 如上图第一个式子,海瑞斯角点就是将窗口移动后的数

    2024年02月07日
    浏览(37)
  • OpenCV(二十八):连通域分割

    目录 1.介绍连通域分割 2.像素领域介绍 3.两遍法分割连通域 4.连通域分割函数 1.介绍连通域分割        连通域分割是一种图像处理技术,用于将图像中的相邻像素组成的区域划分为不同的连通域。这些像素具有相似的特性,如相近的灰度值或颜色。连通域分割可以用于物体

    2024年02月09日
    浏览(46)
  • opencv_c++学习(一)

    本人所用环境为: win10 opencv3.4.16 VScode2017 opencv的官网为: https://opencv.org/ 点开之后我们选择library,下图红框 进入之后我们选择自已要搭建的opencv版本,我这里选择的3.4.16,Windows版本。 下载完成之后我们就可以用下载的文件进行自解压了: 选择自己要安装的位置 安装完成后我

    2023年04月08日
    浏览(40)
  • opencv_c++学习(三)

    CV Assert(mylmage.depth() == CV 8U); CV_Assert()函数判断图像数据的类型是否为uchar类型,不满足则抛出异常。 Mat.ptr(int i=0)获取像素矩阵的指针,索引i表示第几行,从0开始计行数。 Mat.ptr(int i=0)获取像素矩阵的指针,索引i表示第几行,从0开始计行数。 获取当前像素点P(row, col)的像素值

    2024年02月03日
    浏览(29)
  • opencv_c++学习(三十)

    model:模型文件名称 config:配置文件名称 framework:框架种类 Net类中的函数名称以及作用: 向网络层中添加数据: blob:新的输入数据,数据类型为CV_32F或CV_8U。 name:输入网络层的名称。 scalefactor:可选的标准化比例(尺寸缩放)。 mean:可选的减数数值(平移)。 opencv调用深度学习模

    2024年02月06日
    浏览(37)
  • opencv_c++学习(六)

    对以上实例解释如下: 若读取的为本地视频,则filename为视频名称,若读取的是摄像头数据,则为int类型的摄像头id。 视频属性可以通过get()函数获取。 见文末案例 对以上实例进行解释: filename:保存视频的地址和文件名,包含视频格式; fourcc:压缩帧的4字符编解码器代码,

    2024年02月03日
    浏览(34)
  • opencv_c++学习(十三)

    trackbarname:滑动条的名称。 winname:创建滑动条窗口的名称。 value:指向整数变量的指针,该指针指向的值反映滑块的位置,创建后,滑块位置由此变量定义。 count:滑动条的最大取值。 onChange:每次滑块更改位置时要调用的函数的指针。该函数应该原型为void Foo (int,void *) ;,其中

    2024年02月05日
    浏览(83)
  • OpenCV入门(二十八)快速学会OpenCV 27 图像匹配

    作者:Xiou 如果说SIFT还很年轻,SURF更年轻,那么ORB就还处于婴儿期。ORB首次发布于2011年,作为SIFT和SURF的一个快速代替品。该算法发表在论文“ORB:an efficient alternative to SIFT or SURF”上,可以在 http://www.willowgarage.com/sites/default/files/orb_final.pdf 处找到PDF格式的论文。ORB融合了FAS

    2023年04月09日
    浏览(41)
  • 文献学习-37-动态场景中任意形状针的单目 3D 位姿估计:一种高效的视觉学习和几何建模方法

    Authors: Bin Li,† , Student Member, IEEE, Bo Lu,† , Member, IEEE, Hongbin Lin, Yaxiang Wang, Fangxun Zhong, Member, IEEE, Qi Dou, Member, IEEE and Yun-Hui Liu, Fellow, IEEE Source: IEEE TRANSACTIONS ON MEDICAL ROBOTICS AND BIONICS Keywords: Surgical Robotics, Pose Estimation, Geometry Modeling, Vision-based Manipulation Abstract: 导向图像的针具姿

    2024年04月17日
    浏览(39)
  • python爬虫学习第二十八天-------了解scrapy(二十八天)

    🎈🎈作者主页: 喔的嘛呀🎈🎈 🎈🎈所属专栏:python爬虫学习🎈🎈 ✨✨谢谢大家捧场,祝屏幕前的小伙伴们每天都有好运相伴左右,一定要天天开心哦!✨✨  hello,兄弟姐妹们!我是喔的嘛呀。今天我们首先来了解scrapy。为后面的学习打下基础。 一、scrapy是什么?

    2024年04月25日
    浏览(40)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包