目录
1、单目相机标定
2、图像校正
3、单目位姿估计
4、差值法检测移动物体
5、稠密光流法跟踪移动物体
//单目相机标定
int test1()
{
//读取所有图像
vector 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> imgsPoints;
//提取每张图像内角点坐标
for (int i = 0; i < imgs.size(); i++)
{
Mat img1 = imgs[i];
Mat gray1;
cvtColor(img1, gray1, COLOR_BGR2GRAY);
vector 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> objectPoints;
for (int i = 0; i < imgsPoints.size(); i++)
{
vector 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 rvecs;//每幅图像的旋转向量
vector tvecs;//每张图像的平移量
calibrateCamera(objectPoints, imgsPoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, 0);
cout << "相机的内参矩阵=" << endl << cameraMatrix << endl;
cout << "相机畸变系数" << distCoeffs << endl;
waitKey(0);
return 0;
}
//图像校正
//用undistort()函数直接计算校正图像
//所有原图像向量 计算得到的相机内参 计算得到的相机畸变系数 校正后的输出图像
void undist(vector imgs, Mat cameraMatrix, Mat distCoeffs, vector &undistImgs)
{
for (int i = 0; i < imgs.size(); i++)
{
Mat undistImg;
undistort(imgs[i], undistImg, cameraMatrix, distCoeffs);
undistImgs.push_back(undistImg);
}
}
int test2()
{
//读取所有图像
vector imgs;
string imageName;
ifstream fin("F:/testMap/calibdate.txt");
while (getline(fin, imageName))
{
Mat img = imread(imageName);
imgs.push_back(img);
}
//输入前文计算得到的内参矩阵
Mat cameraMatrix = (Mat_(3, 3) << 532.016297, 0, 332.172519,
0, 531.565159, 233.388075,
0, 0, 1);
//输入前文计算得到的畸变矩阵
Mat distCoeffs = (Mat_(1, 5) << -0.285188, 0.080097, 0.001274, -0.002415, 0.106579);
vector 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;
}
//单目位姿估计
int test3()
{
//读取所有图像
Mat img = imread("F:/testMap/left01.png");
Mat gray;
cvtColor(img,gray,COLOR_BGR2GRAY);
vector imgPoints;
Size boardSize = Size(9,6);
findChessboardCorners(gray,boardSize, imgPoints);//计算方格标定板角点
find4QuadCornerSubpix(gray,imgPoints,Size(5,5));//细化方格标定板角点坐r
//生成棋盘格每个内角点的空间三维坐标
Size squareSize = Size(10, 10);//棋盘格每个方格的真实尺寸
vector 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_(3,3) << 532.016297,0,332.172519,
0, 531.565159,233.388075,
0, 0,1);
Mat distCoeffs = (Mat_(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;
}
//差值法检测移动物体
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;
}
//稠密光流法跟踪移动物体
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_ 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(row,col);
xV.at(row, col) = flow_xy.x;
yV.at(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 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;
}