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

目录

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

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zhang丶&|!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值