背景:在上一篇文章中 写到了我第一次使用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;嘛,我的操作不够专业。
现在终于把这个实现两个线程之间数据传输的代码实现了,虽然简单,但对我来说是一次进步,我不需要跟别人比较,只要我今天跟昨天相比有进步,我就感觉这一天过的有意义,我很开心。