Ressource guarding multithreading
This commit is contained in:
parent
b46898a506
commit
b5811dbbcb
@ -4,19 +4,52 @@
|
||||
int main(void)
|
||||
{
|
||||
//Disable opencv logging messages
|
||||
cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_WARNING);
|
||||
//cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_WARNING);
|
||||
|
||||
const int thresholdBinary = 140;
|
||||
const int videoHeight = 720;
|
||||
const int videoWidth = 1280;
|
||||
const int gaussKernelSize = 11;
|
||||
|
||||
LFR lfr(videoHeight, videoWidth, thresholdBinary, gaussKernelSize);
|
||||
lfr.saveOutputFlag = false;
|
||||
lfr.videoFlag = true;
|
||||
std::mutex mutex;
|
||||
|
||||
LFR lfr(videoHeight, videoWidth, thresholdBinary, gaussKernelSize, [&](std::exception const &ex)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
std::cerr<<"camera exception:"<<ex.what()<<std::endl;
|
||||
return true;
|
||||
});
|
||||
|
||||
//To calculate the frame rate
|
||||
std::chrono::milliseconds last = duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
std::chrono::milliseconds now = duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
|
||||
cv::Mat img;
|
||||
lfr.addListener([&](LFR_Result result)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
if (!result.rawImage.empty())
|
||||
{
|
||||
cv::resize(result.rawImage, img, cv::Size(128, 64+32));
|
||||
|
||||
//Calculate frame rate
|
||||
now = duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
unsigned int deltaMs = (now-last).count();
|
||||
float delta = static_cast<float>(deltaMs) / 1000.0;
|
||||
float frameRate = 1.0 / static_cast<float>(delta);
|
||||
|
||||
//std::cout << "Frame rate: " << frameRate << std::endl;
|
||||
last = now;
|
||||
}
|
||||
}, &mutex);
|
||||
|
||||
lfr.startLoop();
|
||||
//To end the video stream, write any char in the console.
|
||||
char a;
|
||||
std::cin >> a;
|
||||
lfr.endLoop();
|
||||
|
||||
for(int finished = false; finished != 'q';){
|
||||
finished = std::tolower(cv::waitKey(66));
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
if(!img.empty()){
|
||||
cv::imshow("frame", img);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,63 +3,114 @@
|
||||
#define right false
|
||||
#define left true
|
||||
|
||||
LFR::LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize)
|
||||
: iAmLooping(false), input(videoHeight, videoWidth), processing(), controlModule(), interpreter(), intersectionHandler()
|
||||
LFR::LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize, ExceptionCallback cb):
|
||||
stop(false),
|
||||
input(videoHeight, videoWidth),
|
||||
processing(),
|
||||
controlModule(),
|
||||
interpreter(),
|
||||
intersectionHandler(),
|
||||
cb(cb)
|
||||
{
|
||||
this->iAmLooping = false;
|
||||
this->thresholdBinary = thresholdBinary;
|
||||
this->gaussKernelSize = gaussKernelSize;
|
||||
|
||||
this->videoFlag = false;
|
||||
this->saveOutputFlag = false;
|
||||
this->outputFileName = "";
|
||||
}
|
||||
|
||||
LFR::~LFR()
|
||||
{
|
||||
if(iAmLooping)
|
||||
endLoop();
|
||||
thread->join();
|
||||
}
|
||||
|
||||
void LFR::removeListener(LFR::ListenerKey key)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
auto it = std::find_if(std::begin(listeners), std::end(listeners), [&](auto const &val){
|
||||
return val.first == key;
|
||||
});
|
||||
if(it != std::end(listeners))
|
||||
{
|
||||
this->endLoop();
|
||||
listeners.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void LFR::loop()
|
||||
void LFR::addListener(LFR::ListenerCallback cb, LFR::ListenerKey key)
|
||||
{
|
||||
if(this->videoFlag) {namedWindow("Display window");}
|
||||
while(iAmLooping)
|
||||
{
|
||||
Mat originalImage = input.readWebcam();
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
listeners.emplace_back(key, std::move(cb));
|
||||
}
|
||||
|
||||
Point roiOrigin(0, int(originalImage.rows*(3.25/6.0)));
|
||||
Rect roi(roiOrigin.x, roiOrigin.y, originalImage.cols, originalImage.rows/6);
|
||||
//Mat processedImage = originalImage(roi);
|
||||
Mat processedImage = originalImage;
|
||||
void LFR::setStop(bool val)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
stop = val;
|
||||
}
|
||||
|
||||
processing.processImage(processedImage, this->thresholdBinary, this->gaussKernelSize);
|
||||
//processedImage = processedImage(roi);
|
||||
FrameData data = processing.calculateLineSegments(processedImage, roi);
|
||||
processing.filterReflections(data);
|
||||
processing.calcAngles(data, originalImage.cols, originalImage.rows, left);
|
||||
this->provideOutput(originalImage, processedImage, data, roi);
|
||||
}
|
||||
if(this->videoFlag) {destroyWindow("Display window");}
|
||||
input.freeWebcam();
|
||||
void LFR::createThread()
|
||||
{
|
||||
thread = std::make_unique<std::thread>([this](){
|
||||
while(true)
|
||||
{
|
||||
LFR_Result result;
|
||||
if(!stop && !listeners.empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
Mat originalImage = input.readWebcam();
|
||||
|
||||
Point roiOrigin(0, int(originalImage.rows*(3.25/6.0)));
|
||||
Rect roi(roiOrigin.x, roiOrigin.y, originalImage.cols, originalImage.rows/6);
|
||||
Mat processedImage = originalImage;
|
||||
|
||||
processing.processImage(processedImage, this->thresholdBinary, this->gaussKernelSize);
|
||||
FrameData data = processing.calculateLineSegments(processedImage, roi);
|
||||
processing.filterReflections(data);
|
||||
processing.calcAngles(data, originalImage.cols, originalImage.rows, left);
|
||||
|
||||
processedImage = provideOutput(originalImage, processedImage, data, roi);
|
||||
|
||||
result.rawImage = originalImage;
|
||||
result.processedImage = processedImage;
|
||||
result.data = data;
|
||||
}
|
||||
catch(std::exception const &ex)
|
||||
{
|
||||
cb(ex);
|
||||
}
|
||||
|
||||
//Invoke the callback method (ListenerPair second -> ListenerCallback)
|
||||
for(auto &val : listeners)
|
||||
{
|
||||
val.second(result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void LFR::startLoop()
|
||||
{
|
||||
iAmLooping = true;
|
||||
this->loopThread=thread(&LFR::loop, this);
|
||||
if(thread)
|
||||
{
|
||||
//Restart thread if it is running
|
||||
setStop(true);
|
||||
thread->join();
|
||||
setStop(false);
|
||||
}
|
||||
createThread();
|
||||
}
|
||||
|
||||
void LFR::endLoop()
|
||||
{
|
||||
iAmLooping = false;
|
||||
this->loopThread.join();
|
||||
return;
|
||||
setStop(true);
|
||||
}
|
||||
|
||||
void LFR::provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi)
|
||||
cv::Mat LFR::provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi)
|
||||
{
|
||||
for(int i = 0; i < frameData.contours.size(); i++)
|
||||
{
|
||||
@ -83,14 +134,5 @@ void LFR::provideOutput(Mat originalImage, Mat processedImage, const FrameData&
|
||||
P2.y = (int)round(P1.y + length * sin(frameData.angle * CV_PI / 180.0));
|
||||
cv::arrowedLine(originalImage, P1, P2, Scalar(0,0,255), 2, 8);
|
||||
}
|
||||
if(this->videoFlag)
|
||||
{
|
||||
imshow("Display window", originalImage);
|
||||
imshow("processed:", processedImage);
|
||||
char c = (char)waitKey(25);
|
||||
}
|
||||
if (this->saveOutputFlag && !(this->outputFileName.empty()))
|
||||
{
|
||||
imwrite(this->outputFileName, originalImage);
|
||||
}
|
||||
return originalImage;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <iostream>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
@ -15,34 +16,52 @@
|
||||
|
||||
using namespace cv;
|
||||
|
||||
struct LFR_Result
|
||||
{
|
||||
cv::Mat rawImage;
|
||||
cv::Mat processedImage;
|
||||
FrameData data;
|
||||
};
|
||||
|
||||
class LFR
|
||||
{
|
||||
public:
|
||||
using ListenerKey = void const*;
|
||||
using ExceptionCallback = std::function<bool(std::exception const &ex)>;
|
||||
using ListenerCallback = std::function<void(LFR_Result)>;
|
||||
|
||||
private:
|
||||
using ListenerPair = std::pair<ListenerKey, ListenerCallback>;
|
||||
using ListenerVector = std::vector<ListenerPair>;
|
||||
|
||||
Input input;
|
||||
Processing processing;
|
||||
ControlModule controlModule;
|
||||
Interpreter interpreter;
|
||||
IntersectionHandler intersectionHandler;
|
||||
volatile bool iAmLooping;
|
||||
void loop();
|
||||
thread loopThread;
|
||||
|
||||
int thresholdBinary;
|
||||
int gaussKernelSize;
|
||||
|
||||
void provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi);
|
||||
ListenerVector listeners;
|
||||
ExceptionCallback cb;
|
||||
bool stop;
|
||||
std::unique_ptr<std::thread> thread;
|
||||
mutable std::mutex mutex;
|
||||
|
||||
//void provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi);
|
||||
void createThread();
|
||||
void setStop(bool val);
|
||||
|
||||
public:
|
||||
|
||||
LFR() = delete;
|
||||
LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize);
|
||||
LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize, ExceptionCallback cb);
|
||||
~LFR();
|
||||
|
||||
void startLoop();
|
||||
void endLoop();
|
||||
|
||||
|
||||
bool videoFlag;
|
||||
bool saveOutputFlag;
|
||||
|
||||
std::string outputFileName;
|
||||
|
||||
void addListener(ListenerCallback cv, ListenerKey key);
|
||||
void removeListener(ListenerKey key);
|
||||
void isStopped() const noexcept;
|
||||
Mat provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi);
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user