C++中的类加多线程代码修炼之二

背景:在上一篇文章中 写到了我第一次使用C++使用多个类多个线程进行编程,由于是第一接手“这么大一个工程”,所以还是要有个参照物的,由于我呢之前好几年一直在看的一个C++代码工程就是ORB-SLAM了,这个工程使用C++语言,工程内有三个线程,多个类,代码风格很好,通俗易懂,有很多值得我借鉴和学习的地方,所以我就按照ORB-SLAM工程的思路来组织我的代码。

前情回顾:

我首先创建了四个类:

(1). Capturing类主要专注于相机相关的操作,比如相机的初始化,图像获取,开始,暂停等。

(2). Tracking类主要专注于目标跟踪相关操作。

(3). System类相当于是一个管理者,就像ORB-SLAM中的System类,完成一些系统初始化的任务,其中我主要让他完成,两个线程的创建以及线程之间指针变量的设置(这一点很重要,我刚开始没做相关设置,导致两个线程之间数据传输时出了问题,下面会讲到,嘻嘻)

(4). Frame类,这个类是我后来添加的,目前暂时封装了“图像本身”以及图像的“时间戳”属性。

两个线程:我把主线程先保留了出来,又单独创建了两个线程

(1). 将Capturing中Run函数(用来实现连续从相机去图像的工作)作为CaptureThread线程的线程入口。

(2). 将Tracking中Run函数(用来实现目标跟踪的工作)作为TrackThread线程的线程入口。

我在上一篇文章中https://blog.csdn.net/weixin_38636815/article/details/112848772中讲到了我完成了类的创建和线程的创建,并且测试两个线程可以正常的同步工作,在这片文章中我主要解决的是我在两个线程之间的数据传输过程中遇到的问题。

首先,我要明确我想要的什么,我需要将CaptureThread线程中从相机获取的图像传给TrackingThread线程中去,继续目标跟踪处理,两个线程,CaptureThread线程只负责获取图像数据,TrackingThread线程只负责目标跟踪。但是最重点的是我要把CaptureThread线程中获取的图像传给TrackingThread线程。

我学着ORB-SLAM的样子,在Tracking类中创建了一个list变量,在Capturing中将获取的图像都插入到list中来,这样在TrackingThread中就可以处理这些图像了。

System.h

#ifndef SYSTEM_H
#define SYSTEM_H
#include <thread>
#include "../include/Tracking.h"
#include "../include/Capturing.h"namespace FDSST
{
class Tracking;
class CaptureThread;
class System {
public:System();~System();
private:Tracking* mpTracker;Capturing* mpCapturer;bool mbCameraInited;//定义两个线程std::thread* mptTrackThread;std::thread* mptCaptureThread;
};
}
#endif

System.cpp

#include <thread>
#include "../include/System.h"
namespace FDSST {System::System(){mbCameraInited = false;//创建相机获取图像线程mpCapturer = new Capturing();mptCaptureThread = new std::thread(&FDSST::Capturing::Run, mpCapturer);std::cout << "Capture thread has been created" << std::endl;//创建目标跟踪线程mpTracker = new Tracking();mptTrackThread = new std::thread(&FDSST::Tracking::Run, mpTracker);std::cout << "Tracking thread has been created" << std::endl;}System::~System(){}
}

Capturing.h

#ifndef Capturing_H
#define Capturing_H
#include <iostream>#include <opencv2/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>#include <list>
#include "../include/Tracking.h"
#include "../include/Frame.h"using namespace std;
using namespace cv;namespace FDSST {
class System;
class Tracking;
class Frame;
class Capturing {
public:Capturing();~Capturing();void Run();void Stream();void Pause();void Stop();bool quit;public:Frame mCurrentFrame;
protected:Tracking* mpTracker;
};
}

Capturing.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <windows.h>#include "../include/Capturing.h"namespace FDSST
{
Capturing::Capturing(){}
Capturing::~Capturing(){}void Capturing::Run()
{//从本地读入视频来模拟从相机获取图像,要换成自己的视频路径呦std::string videoPath = "F:\\Programme\\object_detection\\fdsst\\data\\012.avi";cv::VideoCapture cap(videoPath);if (!cap.isOpened()){std::cout << "视频打开失败" << std::endl;return;}while (1){cv::Mat currentImg;double timestamp = (double)cv::getTickCount();cap >> currentImg;if (currentImg.rows <= 0 || currentImg.cols <= 0){break;}//将获取的图像实例化为Frame类的对象。Frame* pFrame = new Frame(currentImg, timestamp);//将Frame的指针对象插到在Tracking线程中创建的mlNewFrame的list中mpTracker->InsertFrames(pFrame);cv::imshow("test1", currentImg);cv::waitKey(1);}return;
}
void Capturing::Stream()
{pause_status = false;
}void Capturing::Pause()
{pause_status = true;
}void Capturing::Stop()
{pause_status = true;quit = true;
}

Tracking.h

#ifndef TRACKING_H
#define TRACKING_H
#include <mutex>#include "../include/Frame.h"
#include "../include/Capturing.h"namespace FDSST
{
class Capturing;
class Tracking {
public:Tracking();~Tracking();void Run();void InsertImages(Frame* frame);int FramesInQueue() {std::unique_lock<std::mutex> lock(mMutexNewFrame);return mlNewFrames.size();}void SetCapturer(Capturing* pCapturer);protected://定义互斥锁变量,确保在TrackThread线程中,在list中取图像数据时,CaptureThread停止插入操作std::mutex mMutexNewFrame;//定义list变量,存储从CaptureThread中传递的图像数据。std::list<Frame*> mlNewFrames;Frame* mCurrentFrame;Capturing* mpCapturer;void ProcessNewFrames();bool CheckNewFrames();};
}
#endif

Tracking.cpp

#include <iostream>
#include <windows.h>
#include <mutex>
#include "../include/Capturing.h"
#include "../include/Tracking.h"
namespace FDSST
{Tracking::Tracking(){}Tracking::~Tracking(){}void Tracking::Run(){while (1){if (CheckNewFrames()){ProcessNewFrames();}}}void Tracking::InsertFrames(Frame* frame){std::unique_lock<std::mutex> lock(mMutexNewFrame);mlNewFrames.push_back(frame);}void Tracking::ProcessNewFrames(){std::unique_lock<std::mutex> lock(mMutexNewFrame);mCurrentFrame = mlNewFrames.front();cv::Mat img = mCurrentFrame->mImage;mlNewFrames.pop_front();cv::imshow("test", img);cv::waitKey(1);	}bool Tracking::CheckNewFrames(){std::unique_lock<std::mutex> lock(mMutexNewFrame);return (!mlNewFrames.empty());}
}

Frame.h

#ifndef FRAME_H
#define FRAME_H
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core.hpp>
namespace FDSST
{class Frame{public:Frame();Frame(const cv::Mat& image, const double &timeStamp);private:cv::Mat mImage;double mTimeStamp;};
}
#endif

我写完上面的代码进行测试,发现我的mpTracker为空,无法操作。

 于是我就在Capturing类的构造函数new了一个Tracking指针对象。mpTracker = new Tracking;

然后继续编译,发现代码可以通过了,但是我从Tracking类中查看mlNewFrames变量长度,发现一只是0,也就是图像没有被插进来,我就很纳闷,然后我就又回来研究ORB-SLAM 代码,对比一下,我哪个地方没有做好,找来找去,终于发现了,原来是忘了下面这里的设置。

于是我在Captureing类中添加了下面函数

void Capturing::SetTracker(Tracking* pTracker)
{mpTracker = pTracker;
}

在Tracking类中添加下面函数

void Tracking::SetCapturer(Capturing* pCapturer)
{mpCapturer = pCapturer;
}

在System的构造函数中添加下面语句

System::System()
{//创建相机获取图像线程mpCapturer = new Capturing();mptCaptureThread = new std::thread(&FDSST::Capturing::Run, mpCapturer);std::cout << "Capture thread has been created" << std::endl;//创建目标跟踪线程mpTracker = new Tracking();mptTrackThread = new std::thread(&FDSST::Tracking::Run, mpTracker);std::cout << "Tracking thread has been created" << std::endl;//Set pointers between threadsmpTracker->SetCapturer(mpCapturer);mpCapturer->SetTracker(mpTracker);}

经过以上改进CpatureThread中的Frame可以传送到TrackThread中来了。

感觉好像是他们在互相交换信息。但是我还是不太清楚这样操作的目的,经过Set函数之后,将mpTracker就不是空了,而是将mpTracker赋值给他,而mpTracker = new Tracking(),这不很像我刚才的补救措施mpTracker = new Tracking;嘛,我的操作不够专业。

现在终于把这个实现两个线程之间数据传输的代码实现了,虽然简单,但对我来说是一次进步,我不需要跟别人比较,只要我今天跟昨天相比有进步,我就感觉这一天过的有意义,我很开心。

 

 

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

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

相关文章

Primer c++ 第5版pdf

下载地址&#xff1a;网盘下载 内容简介 这本久负盛名的 C经典教程&#xff0c;时隔八年之久&#xff0c;终迎来史无前例的重大升级。除令全球无数程序员从中受益&#xff0c;甚至为之迷醉的——C 大师 Stanley B. Lippman 的丰富实践经验&#xff0c;C标准委员会原负责…

eclispe修改project Explorer字体大小

切换到Eclipse目录下: D:\JAVA\spring-tool-suite\sts-4.0.2.RELEASE\plugins\org.eclipse.ui.themes_1.2.200.v20180828-1350 找到下面的这个css文件 打开找到下面的位置在下面添加代码:CTabFolder Tree{font-size: 15px;} 复制代码重启Eclipse,就可以看到效果 修改前 修改后…

3-4 第三天 Generator生成器

Generator是ES6里面的新增规范&#xff0c;ES6其实就是ES2015。ES5、ES6、ES7这些术语大家上网一查就都明白了。JavaScript是一个范程&#xff0c;就是我们说的JS。ES就是ECMA Script&#xff0c;是JavaScript标准的书面说法。ES4、5、6、7其实是JS这门语言发展中的不同的版本。…

神奇的事情--长见识了

背景&#xff1a;我的这个工程里有多个命名空间&#xff0c;之所以是这样是因为&#xff0c;有一个跟踪算法他本身有几个namespace,然后我在他的基础上进行整合代码&#xff0c;将其作为一个功能接口&#xff0c;供其他函数调用&#xff0c;我在整合代码时&#xff0c;将我新加…

箭头函数的使用用法(一)

1 //箭头函数的一个好处是简化回调函数2 //箭头函数没有参数&#xff0c;就使用圆刮号代表参数部分&#xff1b;3 var f () >5;4 console.log(f());5 //两个参数的情况&#xff0c;代码块只有一条语句&#xff0c;可以省略{}6 var f (a,b)> console.log(ab);7 f(1,3);8…

LinkedList中查询(contains)和删除(remove)源码分析

一、contains源码分析 本文分析双向链表LinkedList的查询操作源码实现。jdk中源程序中&#xff0c;LinkedList的查询操作&#xff0c;通过contains(Object o)函数实现。具体见下面两部分程序&#xff1a;① public boolean contains(Object o) {return indexOf(o) ! -1; } ② p…

分块入门

我貌似和所有的数据结构都有些误会。。。。。。 在处理一些修改查询问题的时候&#xff0c;我们可以利用分治的思想&#xff0c;比如说把一个线性的数据不断分成一棵二叉树&#xff0c;也就是我们所说的线段树&#xff0c;这样我们就可以在logn的时限里做到修改和查询。同理我们…

开始使用gitlab

不得不说&#xff0c;我真不是一个合格的程序猿&#xff0c;工作马上两年了&#xff0c;github和gitlab用的一点也不熟练&#xff0c;每次兴致来了就搞几下&#xff0c;可是每次都浅尝辄止&#xff0c;不求甚解&#xff0c;时间一长&#xff0c;上一次练习的步骤就都记不起来了…

Spark 2.2.0 文档中文版 Collaborative Filtering 协同过滤 JAVA推荐系统

协同过滤常用于推荐系统&#xff0c;这项技术旨在填补 丢失的user-item关联矩阵 的条目&#xff0c;spark.ml目前支持基于模型的协同过滤&#xff08;用一些丢失条目的潜在因素在描述用户和产品&#xff09;。spark.ml使用ALS&#xff08;交替最小二乘法&#xff09;去学习这些…

淘宝top平台调用接口响应时间优化

我的专栏地址&#xff1a;我的segmentfault,欢迎浏览 一、背景 调用top接口的响应时间长&#xff08;160ms左右&#xff09;&#xff0c;超时和连接异常频繁发生。导致消息组件消费工程的tps遇到瓶颈&#xff08;单实例单消息队列250tps&#xff09;&#xff0c;只能通过增加实…

树上倍增一些理解和写法

树上倍增可以比较容易求得i节点的第k个父亲&#xff0c;我们定义一个二维数组fa[i][j]代表节点i的第2^j个父亲&#xff0c;关于有什么用我们等会再说&#xff0c;现在先学会怎么去求这个fa数组 我们可以通过从根节点开始一遍dfs求得所有fa数组&#xff0c;首先我们发现fa数组有…

图像去畸变和添加畸变

背景&#xff1a;最近的项目中用到的图像去畸变的知识&#xff0c;刚开始是直接调用opencv中提供的函数cv::initUndistortRectifyMap()和cv::remap()函数&#xff0c;实现图像的全局去畸变&#xff0c;但是由于图像的分辨率很高&#xff0c;再加上&#xff0c;实际过程中我们只…

win10上编译libharu库

背景&#xff1a; 最近的项目需要自动的生成pdf文件&#xff0c;我在网上查看相关的资料&#xff0c;发现目前比较流行的生成pdf文件的库有两个&#xff0c;一个是libpdf&#xff0c;另一个是libharu。libpdf个人使用时免费的但是商业使用就需要收费了&#xff0c;否则得到的p…

爬虫——正则表达式re模块

为什么要学习正则表达式 实际上爬虫一共就四个主要步骤&#xff1a; 明确目标&#xff1a;需清楚目标网站爬&#xff1a;将所有的目标网站的内容全部爬下来取&#xff1a;在爬下来的网站内容中去掉对我们没有用处的数据&#xff0c;只留取我们需要的数据处理数据&#xff1a;按…

深入Spring Boot:快速集成Dubbo + Hystrix

2019独角兽企业重金招聘Python工程师标准>>> 背景 Hystrix 旨在通过控制那些访问远程系统、服务和第三方库的节点&#xff0c;从而对延迟和故障提供更强大的容错能力。Hystrix具备拥有回退机制和断路器功能的线程和信号隔离&#xff0c;请求缓存和请求打包&#xff…

BZOJ2333 [SCOI2011]棘手的操作 【离线 + 线段树】

题目 有N个节点&#xff0c;标号从1到N&#xff0c;这N个节点一开始相互不连通。第i个节点的初始权值为a[i]&#xff0c;接下来有如下一些操作&#xff1a; U x y: 加一条边&#xff0c;连接第x个节点和第y个节点 A1 x v: 将第x个节点的权值增加v A2 x v: 将第x个节点所在的连通…

opencv图像仿射变换和普通旋转

背景&#xff1a;今天需要对程序生成的图像进行旋转90度和下采样操作&#xff0c;当然还有改变图像类型的操作&#xff0c;就是把原来.png的图像转换为.jpg的图像&#xff0c;主要是我目前使用libharu库&#xff0c;无法成功从本地加载png图像到pdf中去&#xff0c;不得不使用j…

讨厌麻烦的ora 01722无效数字

webservice开发过程中&#xff0c;数据库由原来的oracle改为现在的sql server。然后重新调试&#xff0c;结果报出ora 01722无效数字的错误。 由于连接oracle数据库的时候并没有问题&#xff0c;所以一开始我以为是数据库不同&#xff0c;导致部分数据类型差异&#xff0c;&…

CSS样式:覆盖规则

规则一&#xff1a;由于继承而发生样式冲突时&#xff0c;最近祖先获胜。 CSS的继承机制使得元素可以从包含它的祖先元素中继承样式&#xff0c;考虑下面这种情况: <html><head><title>rule 1</title><style>body {color:black;}p {color:blue;}…

try{}里有一个 return 语句,那么紧跟在这个 try 后的 finally {}里的 code 会 不会被执行,什么时候被执行,在 return 前还是后?...

这是一道面试题&#xff0c;首先finally{}里面的code肯定是会执行的&#xff0c;至于在return前还是后&#xff0c; 看答案说的是在return后执行&#xff0c;我觉得不对&#xff0c;百度了一下&#xff0c;有说return前的&#xff0c;有说return后的&#xff0c;还有return中间…