opencv_c++学习(二十八)

news/2024/12/23 7:18:32/

一、单目相机位姿估计

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

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=0realPoint.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-255normalize(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颜色转换为RGBMat 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.ppmy.cn/news/102609.html

相关文章

01.GATK肿瘤基因变异最佳实践SnakeMake流程:WorkFlow简介

<~生~信~交~流~与~合~作~请~关~注~公~众~号生信探索> 代码地址 https://jihulab.com/BioQuest/smkhsshttps://github.com/BioQuestX/smkhss GATK best practices workflow Pipeline summary SnakeMake workflow for Human Somatic short variants (SNPINDEL) Expected fa…

JavaScript中几个不常用的绑定事件

目录 一、fullscreenchange事件 二、pagehide事件 三、pageshow事件 四、hashchange事件 五、online事件 六、offline事件 七、popstate事件 八、devicemotion事件 九、deviceorientation事件 一、fullscreenchange事件 fullscreenchange 事件是一个浏览器事件&#…

使用 LSSVM 的 Matlab 演示求解反常微分方程问题(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【人脸识别】insightface 使用记录和搭建服务注意点 从0到1

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言1.开始1.1 前置1.2 再次运行&#xff0c;人脸检测跑通 前言 人脸识别项目&#xff0c;再走一遍。之前是公司老人留下的&#xff0c;没部署过&#xff0c;没交付…

virtualbox安装干净的 ubuntu22.04

http://old-releases.ubuntu.com/releases/ 在上边这个网站下载 20.04 的 ubuntu &#xff08;老版本 ubuntu 都在这里&#xff09; 发现这里下载的 20.04 没法调出终端&#xff0c;决定下载 22.04 下载完后&#xff0c;按照 virtualbox 7.0 的步骤去创建虚拟机就完事了

四站精彩回顾 | Fortinet Accelerate 2023·中国区巡展火热进行中

Fortinet Accelerate 2023中国区巡展 上周&#xff0c;Fortinet Accelerate 2023中国区巡展分别走过青岛、南京、长沙、合肥四站&#xff0c;Fortinet携手太平洋电信、亚马逊云科技、中企通信等云、网、安合作伙伴&#xff0c;与各行业典型代表客户&#xff0c;就网安融合、网…

Hadoop学习---11、HA高可用

1、Hadoop HA高可用 1.1 HA概述 1、所谓HA&#xff08;High Availablity&#xff09;&#xff0c;即高可用&#xff08;7 * 24小时不中断服务&#xff09;。 2、实现高可用最关键的策略是消除单点故障。HA严格来说应该分成各个组件的HA机制&#xff1a;HDFS的HA和YARN的HA。 …

华为设备这14个广域网命令,值得网工收藏

华为设备广域网命令是网络管理员在运维过程中常用的一类命令。该命令集涵盖了DCC配置命令、PPP配置命令、MP配置命令、PPPoE命令、ATM配置命令、帧中继配置命令、HDLC配置命令、LAPB配置命令、X.25配置命令、IP-Trunk配置命令、ISDN配置命令、Modem配置命令、RTC终端接入配置命…