Opencv-光流算法-实战

0. 写在前面

        理论介绍篇在:图像处理算法--光流法-原理-CSDN博客

2. Main函数代码
#include "mainwindow.h"
#include "ui_mainwindow.h"#include <QFileDialog>
#include <QLabel>
#include <QDebug>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);//定时器showTimer = new QTimer(this);connect(showTimer,SIGNAL(timeout()),this,SLOT(ReadFrame()));//初始化状态栏QLabel *labelFile = new QLabel("暂时无文件",this);labelFile->setMinimumWidth(300);//将初始化的标签添加到底部状态上ui->statusBar->addWidget(labelFile);ui->centralWidget->setMouseTracking(true);this->setMouseTracking(true);}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::tracking(Mat &frame, Mat &output)
{cvtColor(frame, gray, COLOR_BGR2GRAY);frame.copyTo(output);//添加特征点if (addNewPoints()){goodFeaturesToTrack(gray, features, maxCount, qLevel, minDest);points[0].insert(points[0].end(), features.begin(), features.end());initial.insert(initial.end(), features.begin(), features.end());}if (gray_prev.empty()){gray.copyTo(gray_prev);}//l-k流光法运动估计calcOpticalFlowPyrLK(gray_prev, gray, points[0], points[1], status, err);//去掉一些不好的特征点int k = 0;for (size_t i = 0; i < points[1].size(); i++){if (acceptTrackedPoint(i)){initial[k] = initial[i];points[1][k++] = points[1][i];}}points[1].resize(k);initial.resize(k);//显示特征点和运动轨迹for (size_t i = 0; i < points[1].size(); i++){line(output, initial[i], points[1][i], Scalar(0, 0, 255));circle(output, points[1][i], 3, Scalar(0, 255, 0), -1);}//把当前跟踪结果作为下一次的参考swap(points[1],points[0]);swap(gray_prev,gray);imshow(window_name, output);
}bool MainWindow::addNewPoints()
{return points[0].size() <= 10;       //points.size()求行数     points.size()求列数
}bool MainWindow::acceptTrackedPoint(int i)
{return status[i] && ((abs(points[0][i].x - points[1][i].x) + abs(points[0][i].y - points[1][i].y)) > 2);
}//鼠标移动事件
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{//if(event->buttons() & Qt::LeftButton){QPoint sPoint1=event->globalPos();QPoint widgetPoint = ui->ShowLabel->mapFromGlobal(sPoint1);ui->TXTLabel_x->setNum((widgetPoint.x()));ui->TXTLabel_y->setNum((widgetPoint.y()));}
}Mat MainWindow::moveCheck(Mat &forntFrame, Mat &afterFrame)
{Mat frontGray,afterGray,diff;Mat resFrame=afterFrame.clone();//灰度处理cvtColor(forntFrame,frontGray,COLOR_BGR2GRAY);cvtColor(afterFrame,afterGray,COLOR_BGR2GRAY);//帧差处理 找到帧与帧之间运动物体差异absdiff(frontGray,afterGray,diff);//imshow("diff",diff);//二值化//threshold(diff,diff,15,255,THRESH_BINARY);adaptiveThreshold(diff,diff,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,5,5,5);imshow("threashold",diff);waitKey(25);//腐蚀处理:Mat element=cv::getStructuringElement(MORPH_RECT,Size(3,3));erode(diff,diff,element);//imshow("erode",diff);//膨胀处理Mat element2=cv::getStructuringElement(MORPH_RECT,Size(20,20));dilate(diff,diff,element2);//imshow("dilate",diff);//动态物体标记vector<vector<Point>>contours;//保存关键点findContours(diff,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE,Point(0,0));//提取关键点vector<vector<Point>>contour_poly(contours.size());vector<Rect>boundRect(contours.size());int x,y,w,h;int num=contours.size();for(int i=0;i<num;i++){approxPolyDP(Mat(contours[i]),contour_poly[i],3,true);boundRect[i]=boundingRect(Mat(contour_poly[i]));x=boundRect[i].x;y=boundRect[i].y;w=boundRect[i].width;h=boundRect[i].height;//绘制rectangle(resFrame,Point(x,y),Point(x+w,y+h),Scalar(0,255,0),2);}return resFrame;
}void MainWindow::on_pBtn_OpenFile_clicked()
{//打开图片文件,选择图片QString filename = QFileDialog::getOpenFileName(this,tr("Open File"),QDir::homePath(),tr("所有文件(*.avi *.mp4 *.h624 *.mkv)\n(*.jpg)\n(*.bmp)\n(*.png)"));capture.open(filename.toStdString()); //.toStdString()if(!capture.isOpened()){ui->statusBar->showMessage(tr("Open Video Failed!"));}else{ui->statusBar->showMessage(tr("Open Video Success!"));}Mat frame;Mat temp;Mat res;int count = 0;while(capture.read(frame)){//frame = frame(cv::Rect(440, 260,200,200));count = count + 60;if(count==0){res=moveCheck(frame,frame);}else{res=moveCheck(temp,frame);}temp=frame.clone();imshow("frame",frame);imshow("res",res);waitKey(2500);}#if 0Mat frame,gray;vector<Point2f> features;       //检测出来的角点集合vector<Point2f> inPoints;       //这个主要是为了画线用的vector<Point2f> fpts[2];        //[0],存入的是是二维特征向量,[1]输出的二维特征向量Mat pre_frame,pre_gray;vector<uchar> status;           //光流输出状态vector<float> err;              //光流输出错误//【2】循环读取视频while(capture.read(frame)){//循环读取视频中每一帧的图像//【3】将视频帧图像转为灰度图cvtColor(frame,gray,COLOR_BGR2GRAY);    //ps:角点检测输入要求单通道cv::Mat imageRIO = gray(cv::Rect(440, 260,200,200));cv::imshow("ROI",imageRIO);//【4】如果特征向量(角点)小于40个我们就重新执行角点检测if(fpts[0].size()<25){//如果小于40个角点就重新开始执行角点检测//执行角点检测goodFeaturesToTrack(imageRIO,features,1000,0.01,10,Mat(),3,false,0.04);//【5】将检测到的角点放入fpts[0]中作为,光流跟踪的输入特征向量//将检测到的角点插入vectorfpts[0].insert(fpts[0].begin(),features.begin(),features.end());inPoints.insert(inPoints.end(),features.begin(),features.end());qDebug()<<"角点检测执行完成,角点个数为:"<<features.size();}else{qDebug()<<"正在跟踪...";}//【6】初始化的时候如果检测到前一帧为空,这个把当前帧的灰度图像给前一帧if(pre_gray.empty()){//如果前一帧为空就给前一帧赋值一次imageRIO.copyTo(pre_gray);}//执行光流跟踪qDebug()<<"开始执行光流跟踪";//【7】执行光流跟踪,并将输出的特征向量放入fpts[1]中calcOpticalFlowPyrLK(pre_gray,imageRIO,fpts[0],fpts[1],status,err);qDebug()<<"光流跟踪执行结束";//【8】遍历光流跟踪的输出特征向量,并得到距离和状态都符合预期的特征向量。让后将其重新填充到fpts[1]中备用int k =0;for(size_t i=0;i<fpts[1].size();i++){                                                                                        //循环遍历二维输出向量double dist = abs(fpts[0][i].x - fpts[1][i].x) + abs(fpts[0][i].y - fpts[1][i].y);   //特征向量移动距离if(dist>1&&status[i]){                                                                                    //如果距离大于2,status=true(正常)inPoints[k] = inPoints[i];fpts[1][k++] = fpts[1][i];}}//【9】重置集合大小(由于有错误/不符合条件的输出特征向量),只拿状态正确的//重新设置集合大小inPoints.resize(k);fpts[1].resize(k);//【10】绘制光流线,这一步要不要都行//绘制光流线if(true){for(size_t i = 0;i<fpts[1].size();i++){line(imageRIO,inPoints[i],fpts[1][i],Scalar(0,255,0),1,8,0);circle(imageRIO, fpts[1][i], 2, Scalar(0, 0, 255), 2, 8, 0);}}qDebug()<<"特征向量的输入输出交换数据";//【11】交换特征向量的输入和输出,(循环往复/进入下一个循环),此时特征向量的值会递减std::swap(fpts[1],fpts[0]);//交换特征向量的输入和输出,此处焦点的总数量会递减//【12】将用于跟踪的角点绘制出来//将角点绘制出来for(size_t i = 0;i<fpts[0].size();i++){circle(imageRIO,fpts[0][i],2,Scalar(0,0,255),2,8,0);}//【13】重置前一帧图像(每一个循环都要刷新)imageRIO.copyTo(pre_gray);imageRIO.copyTo(pre_frame);//【14】展示最终的效果imshow("imageRIO",imageRIO);int keyValue = waitKey(100);if(keyValue==27){//如果用户按ese键退出播放break;}}
#endif#if 0//读取第一帧图像,进行初始化;Mat pre_image;capture.read(pre_image);cvtColor(pre_image, pre_image, COLOR_BGR2GRAY);//光流检测必须为浮点型坐标点vector<Point2f> prevPts;                    //定义上一帧图像的稀疏特征点集vector<Point2f> initpoint;                  //定义上一帧图像中保留的稀疏特征点集,用于绘制轨迹vector<Point2f> features;					//用于存放从图像中获得的特征角点goodFeaturesToTrack(pre_image, features, 100, 0.3, 10, Mat(), 3, false);				//获取第一帧图像的稀疏特征点集//insert(插入位置,插入对象的首地址,插入对象的尾地址)initpoint.insert(initpoint.end(), features.begin(), features.end());				//初始化当前帧的特征点集prevPts.insert(prevPts.end(), features.begin(), features.end());		//初始化第一帧的特征角点//Mat frame;while (capture.read(frame)){Mat next_image;flip(frame, frame, 1);cvtColor(frame, next_image, COLOR_BGR2GRAY);vector<Point2f> nextPts;			//下一帧图像检测到的对应稀疏特征点集vector<uchar> status;			//输出点的状态向量;如果某点在两帧图像之间存在光流,则该向量中对应该点的元素设置为1,否则设置为0。vector<float>err;					//输出错误的向量; 向量的每个元素都设置为相应特征点的错误calcOpticalFlowPyrLK(pre_image, next_image, prevPts, nextPts, status, err, Size(31,31));RNG rng;int k = 0;for (int i = 0; i < nextPts.size(); i++)		//遍历下一帧图像的稀疏特征点集{//计算两个对应特征点的(dx+dy)double dist = abs(double(prevPts[i].x) - double(nextPts[i].x)) + abs(double(prevPts[i].y) - double(nextPts[i].y));if (status[i] && dist > 2)				//如果该点在两帧图像之间存在光流,且两帧图像中对应点的距离大于2,即非静止点{//将存在光流的非静止特征点保留起来prevPts[k] = prevPts[i];nextPts[k] = nextPts[i];initpoint[k] = initpoint[i];k++;//绘制保留的特征点int b = rng.uniform(0, 256);int g = rng.uniform(0, 256);int r = rng.uniform(0, 256);circle(frame, nextPts[i], 3, Scalar(b, g, r), -1, 8, 0);}}//将稀疏特征点集更新为现有的容量,也就是保存下来的特征点数prevPts.resize(k);nextPts.resize(k);initpoint.resize(k);//在每一帧图像中绘制当前特征点走过的整个路径for (int j = 0; j < initpoint.size(); j++){int b = rng.uniform(0, 256);int g = rng.uniform(0, 256);int r = rng.uniform(0, 256);line(frame, initpoint[j], nextPts[j], Scalar(b, g, r), 1, 8, 0);}imshow("frame", frame);//swap()交换两个变量的数据swap(nextPts, prevPts);			//将下一帧图像的稀疏特征点集,变为上一帧swap(pre_image, next_image);			//将下一帧图像变为上一帧图像//当特征点的数量被筛选得低于阈值时,重新从下一帧图像中寻找特征角点;注意此时的上下两帧图像已经互换if (initpoint.size() < 10){goodFeaturesToTrack(pre_image, features, 100, 0.01, 10, Mat(), 3, false);initpoint.insert(initpoint.end(), features.begin(), features.end());prevPts.insert(prevPts.end(), features.begin(), features.end());}}
#endif
#if 0Mat prevgray, gray, rgb, frame;Mat flow, flow_uv[2];Mat flow_Farneback;Mat flow_uv_Farneback[2];Mat mag, ang;Mat mag_Farneback, ang_Farneback;Mat hsv_split[3], hsv;Mat hsv_split_Farneback[3], hsv_Farneback;Mat rgb_Farneback;Ptr<DenseOpticalFlow> algorithm = DISOpticalFlow::create(DISOpticalFlow::PRESET_MEDIUM);int idx = 0;while(true){capture >> frame;if (frame.empty())break;cv::resize(frame,frame,cv::Size(0.8*frame.cols,0.8*frame.rows),0,0,cv::INTER_LINEAR);idx++;cvtColor(frame, gray, COLOR_BGR2GRAY);cv::imshow("orig", frame);if (!prevgray.empty()){/*DISOpticalFlow*//*main function of DISOpticalFlow*/algorithm->calc(prevgray, gray, flow);split(flow, flow_uv);multiply(flow_uv[1], -1, flow_uv[1]);cartToPolar(flow_uv[0], flow_uv[1], mag, ang, true);normalize(mag, mag, 0, 1, NORM_MINMAX);hsv_split[0] = ang;hsv_split[1] = mag;hsv_split[2] = Mat::ones(ang.size(), ang.type());merge(hsv_split, 3, hsv);cvtColor(hsv, rgb, COLOR_HSV2BGR);cv::Mat rgbU;rgb.convertTo(rgbU, CV_8UC3,  255, 0);cv::imshow("DISOpticalFlow", rgbU);Mat rgbU_b = rgbU.clone();Mat split_dis[3];split(rgbU_b, split_dis);split_dis[2] = prevgray;Mat merge_dis;merge(split_dis, 3, merge_dis);cv::imshow("DISOpticalFlow_mask", merge_dis);/*Farneback*/cv::calcOpticalFlowFarneback(prevgray, gray, flow_Farneback, 0.5, 3,15, 3, 5, 1.2, 0);split(flow_Farneback, flow_uv_Farneback);multiply(flow_uv_Farneback[1], -1, flow_uv_Farneback[1]);cartToPolar(flow_uv_Farneback[0], flow_uv_Farneback[1], mag_Farneback, ang_Farneback, true);normalize(mag_Farneback, mag_Farneback, 0, 1, NORM_MINMAX);hsv_split_Farneback[0] = ang_Farneback;hsv_split_Farneback[1] = mag_Farneback;hsv_split_Farneback[2] = Mat::ones(ang_Farneback.size(), ang_Farneback.type());merge(hsv_split_Farneback, 3, hsv_Farneback);cvtColor(hsv_Farneback, rgb_Farneback, COLOR_HSV2BGR);cv::Mat rgbU_Farneback;rgb_Farneback.convertTo(rgbU_Farneback, CV_8UC3,  255, 0);cv::imshow("FlowFarneback", rgbU_Farneback);Mat rgbU_Farneback_b = rgbU_Farneback.clone();Mat split_Fb[3];split(rgbU_Farneback_b, split_Fb);split_Fb[2] = prevgray;Mat merge_Fb;merge(split_Fb, 3, merge_Fb);cv::imshow("FlowFarneback_mask", merge_Fb);cv::waitKey(1);}std::swap(prevgray, gray);}
#endif//showTimer->start(25);#if 0//TODO:后期优化,内部区分是读图片还是视频QImage image = QImage(filename);if(!image.isNull()){ui->statusBar->showMessage(tr("Open image Success!"));}else{ui->statusBar->showMessage(tr("Open image Failed!"));}
#endif}void MainWindow::ReadFrame()
{}void MainWindow::on_pBtn_CloseFile_clicked()
{showTimer->stop();capture.release();frame.release();}

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

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

相关文章

基于SSM+Jsp+Mysql的母婴用品网站

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

新能源汽车充电桩主板的常见故障及解决办法

电桩主板作为充电桩的核心组件&#xff0c;直接影响着充电桩运行的安全性与稳定性。然而&#xff0c;在使用过程中&#xff0c;充电桩主板会因多种原因而出现一些故障情况&#xff0c;了解这些原因并采取相应的应对方法对维护充电桩的正常运行起着至关重要的作用。接下来&#…

【LeetCode】合并两个有序数组

88. 合并两个有序数组 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递减顺序 排列。 注意&#xff1a;最终&am…

3-zookeeper之ZAB协议

Zookeeper ZAB协议 概述 ZAB(Zookeeper Automic Broadcast)是一套专门为Zookeeper设计的用于进行原子广播和崩溃恢复的协议ZAB协议主要包含了两个功能 原子广播&#xff1a;保证数据一致性崩溃恢复&#xff1a;保证集群的高可用 ZAB协议本身是基于2PC算法来进行的设计&#…

Redis 红锁:分布式锁的强大实现

在分布式系统中&#xff0c;多个进程或线程可能需要并发访问共享资源。为了确保数据的一致性和正确性&#xff0c;我们需要一种分布式锁机制来协调这些访问。Redis 红锁就是这样一种强大的分布式锁实现。 一、分布式锁的概念 分布式锁是一种用于在分布式系统中实现资源互斥访…

U盘位置不可用,如何轻松应对数据恢复难题

在日常工作和生活中&#xff0c;U盘作为一种便捷的存储设备&#xff0c;经常被用于数据传输和备份。然而&#xff0c;有时我们可能会遇到这样一个问题&#xff1a;当插入U盘时&#xff0c;系统提示“位置不可用”或“无法访问”&#xff0c;这让人倍感困扰。面对这种情况&#…

wpsword求和操作教程

wpsword求和怎么操作&#xff1a; 1、首先&#xff0c;单纯的数据是无法求和的&#xff0c;所以我们必须要“插入”一个“表格” 2、接着将需要求和的数据填入到表格中。 3、填完后&#xff0c;进入“布局”选项卡。 4、然后打开其中的“公式” 5、在其中选择求和公式“SUM”并…

Go、Java、C++语言实现多态的方式

Go、Java、C语言实现多态的方式各有特色&#xff0c;但都遵循面向对象编程的基本原则。以下是各自实现多态的主要手段&#xff1a; Go语言&#xff1a; 虽然Go语言本身并不直接支持类和传统的面向对象继承&#xff0c;但它通过接口&#xff08;Interface&#xff09;实现了多态…

php高精度数学计算 - bc函数

PHP中的bc函数是用于高精度计算的函数&#xff0c;可以处理大数运算&#xff0c;支持加、减、乘、除、幂运算等。bc函数的语法如下&#xff1a; bc***(string $num1,string $num2, int $scale 0) : string参数说明&#xff1a; $num1&#xff1a;要进行计算的数值&#xff0c…

从0到1部署私域NuGet库:实战指南,让你轻松掌握!

引言 私域NuGet包的重要性&#xff1a;代码复用和团队协同。通过将公共组件、库或工具打包成NuGet包&#xff0c;并在私域中共享&#xff0c;团队成员可以更方便地引用和使用这些资源。其次私域NuGet包有助于依赖管理。通过私域NuGet包&#xff0c;团队可以集中管理这些依赖&a…

案例研究|DataEase实现物业数据可视化管理与决策支持

河北隆泰物业服务有限责任公司&#xff08;以下简称为“隆泰物业”&#xff09;创建于2002年&#xff0c;总部设在河北省高碑店市&#xff0c;具有国家一级物业管理企业资质&#xff0c;通过了质量体系、环境管理体系、职业健康安全管理体系等认证。自2016年至今&#xff0c;隆…

启信宝商业大数据助力全国经济普查

近日&#xff0c;合合信息旗下启信宝收到中国青年创业就业基金会感谢信&#xff0c;对启信宝协同助力全国经济普查和服务青年创业就业研究表达感谢。 第五次全国经济普查是新时代新征程上一次重大国情国力调查&#xff0c;是对国民经济“全面体检”和“集中盘点”&#xff0c;…

virtualbox 设置虚拟机 centos 网络

在VirtualBox中为运行CentOS系统的虚拟机配置网络连接&#xff0c;您通常可以选择以下几种网络模式之一&#xff0c;以满足不同的网络需求&#xff1a; NAT (Network Address Translation): 功能&#xff1a;允许虚拟机通过宿主机的网络连接访问互联网&#xff0c;同时也可以从…

学习鸿蒙基础(10)

目录 一、轮播组件 Swiper 二、列表-List 1、简单的List 2、嵌套的List 三、Tabs容器组件 1、系统自带tabs案例 2、自定义导航栏&#xff1a; 一、轮播组件 Swiper Entry Component struct PageSwiper {State message: string Hello Worldprivate SwCon: SwiperControl…

Ribbon简介

目录 一 、概念介绍 1、Ribbon是什么 2、认识负载均衡 2.1 服务器端的负载均衡 2.2 客户端的负载均衡 3、Ribbon工作原理 4、Ribbon的主要组件 IClientConfig ServerList ServerListFilter IRule Iping ILoadBalancer ServerListUpdater 5、Ribbon支持…

为什么Redis设计成单线程

Redis是单线程却能支持高并发 1.Redis 将数据存储在内存中&#xff0c;读取速度非常快&#xff0c;而写入操作通常采用异步持久化的方式&#xff0c;将数据定期写入到磁盘&#xff0c;避免了磁盘IO成为性能瓶颈。这样一来&#xff0c;Redis 可以在高速内存中快速响应读取请求&…

BGP实训

BGP基础配置实训 实验拓扑 注&#xff1a;如无特别说明&#xff0c;描述中的 R1 或 SW1 对应拓扑中设备名称末尾数字为 1 的设备&#xff0c;R2 或 SW2 对应拓扑中设备名称末尾数字为2的设备&#xff0c;以此类推&#xff1b;另外&#xff0c;同一网段中&#xff0c;IP 地址的主…

2024四川省赛“信息安全管理与评估“--网络事件响应--应急响应(高职组)

2024四川省赛“信息安全管理与评估“(高职组)任务书 2024四川省赛“信息安全管理与评估“任务书第一阶段竞赛项目试题第二阶段竞赛项目试题任务 1 应急响应(40分)第三阶段竞赛项目试题2024四川省赛“信息安全管理与评估“任务书 第一阶段竞赛项目试题 先略 第二阶段竞赛…

DFS-蓝桥杯常用Python算法

DFS 蓝桥杯中的DFS主要有针对分配过程的DFS和图/树的DFS两种类型&#xff0c;基本是模板题&#xff0c;难度中等 类型一&#xff1a;针对分配过程的DFS 例题 1&#xff1a;飞机降落 题目描述&#xff1a; N 架飞机准备降落到某个只有一条跑道的机场。其中第 i 架飞机在 T …

vs右键在浏览器中查看报错

vs右键在浏览器中查看报错Visual studio 右键在浏览器中查看报错HTTP错误500.30——ANCM进程内启动失败——.NET Core HTTP Error 500.30 - ANCM In-Process Start Failure - .NET Core HTTP Error 500.30 - ANCM In-Process Start Failure Common solutions to this issue: …