背景:在上一篇文章中 寫到了我第一次使用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;嘛,我的操作不夠專業。
現在終于把這個實現兩個線程之間數據傳輸的代碼實現了,雖然簡單,但對我來說是一次進步,我不需要跟別人比較,只要我今天跟昨天相比有進步,我就感覺這一天過的有意義,我很開心。
?
?