Compare commits
No commits in common. "b5811dbbcb44d7c914e54342c371e48c9cf696d7" and "aad6de3687aa3fc3d00b557fbf5756dd2e825662" have entirely different histories.
b5811dbbcb
...
aad6de3687
@ -1,8 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.1.0)
|
cmake_minimum_required(VERSION 3.1.0)
|
||||||
project(lfr_image_processing VERSION 0.1.0)
|
project(lfr_image_processing VERSION 0.1.0)
|
||||||
|
|
||||||
set (CMAKE_CXX_STANDARD 20)
|
|
||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
|
@ -4,52 +4,19 @@
|
|||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
//Disable opencv logging messages
|
//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 thresholdBinary = 140;
|
||||||
const int videoHeight = 720;
|
const int videoHeight = 720;
|
||||||
const int videoWidth = 1280;
|
const int videoWidth = 1280;
|
||||||
const int gaussKernelSize = 11;
|
const int gaussKernelSize = 11;
|
||||||
|
|
||||||
std::mutex mutex;
|
LFR lfr(videoHeight, videoWidth, thresholdBinary, gaussKernelSize);
|
||||||
|
lfr.saveOutputFlag = false;
|
||||||
LFR lfr(videoHeight, videoWidth, thresholdBinary, gaussKernelSize, [&](std::exception const &ex)
|
lfr.videoFlag = true;
|
||||||
{
|
|
||||||
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();
|
lfr.startLoop();
|
||||||
|
//To end the video stream, write any char in the console.
|
||||||
for(int finished = false; finished != 'q';){
|
char a;
|
||||||
finished = std::tolower(cv::waitKey(66));
|
std::cin >> a;
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
lfr.endLoop();
|
||||||
if(!img.empty()){
|
|
||||||
cv::imshow("frame", img);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,114 +3,63 @@
|
|||||||
#define right false
|
#define right false
|
||||||
#define left true
|
#define left true
|
||||||
|
|
||||||
LFR::LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize, ExceptionCallback cb):
|
LFR::LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize)
|
||||||
stop(false),
|
: iAmLooping(false), input(videoHeight, videoWidth), processing(), controlModule(), interpreter(), intersectionHandler()
|
||||||
input(videoHeight, videoWidth),
|
|
||||||
processing(),
|
|
||||||
controlModule(),
|
|
||||||
interpreter(),
|
|
||||||
intersectionHandler(),
|
|
||||||
cb(cb)
|
|
||||||
{
|
{
|
||||||
|
this->iAmLooping = false;
|
||||||
this->thresholdBinary = thresholdBinary;
|
this->thresholdBinary = thresholdBinary;
|
||||||
this->gaussKernelSize = gaussKernelSize;
|
this->gaussKernelSize = gaussKernelSize;
|
||||||
|
|
||||||
|
this->videoFlag = false;
|
||||||
|
this->saveOutputFlag = false;
|
||||||
|
this->outputFileName = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
LFR::~LFR()
|
LFR::~LFR()
|
||||||
{
|
{
|
||||||
endLoop();
|
if(iAmLooping)
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
listeners.erase(it);
|
this->endLoop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LFR::addListener(LFR::ListenerCallback cb, LFR::ListenerKey key)
|
void LFR::loop()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex);
|
if(this->videoFlag) {namedWindow("Display window");}
|
||||||
listeners.emplace_back(key, std::move(cb));
|
while(iAmLooping)
|
||||||
}
|
{
|
||||||
|
Mat originalImage = input.readWebcam();
|
||||||
|
|
||||||
void LFR::setStop(bool val)
|
Point roiOrigin(0, int(originalImage.rows*(3.25/6.0)));
|
||||||
{
|
Rect roi(roiOrigin.x, roiOrigin.y, originalImage.cols, originalImage.rows/6);
|
||||||
std::lock_guard<std::mutex> lock(mutex);
|
//Mat processedImage = originalImage(roi);
|
||||||
stop = val;
|
Mat processedImage = originalImage;
|
||||||
}
|
|
||||||
|
|
||||||
void LFR::createThread()
|
processing.processImage(processedImage, this->thresholdBinary, this->gaussKernelSize);
|
||||||
{
|
//processedImage = processedImage(roi);
|
||||||
thread = std::make_unique<std::thread>([this](){
|
FrameData data = processing.calculateLineSegments(processedImage, roi);
|
||||||
while(true)
|
processing.filterReflections(data);
|
||||||
{
|
processing.calcAngles(data, originalImage.cols, originalImage.rows, left);
|
||||||
LFR_Result result;
|
this->provideOutput(originalImage, processedImage, data, roi);
|
||||||
if(!stop && !listeners.empty())
|
}
|
||||||
{
|
if(this->videoFlag) {destroyWindow("Display window");}
|
||||||
try
|
input.freeWebcam();
|
||||||
{
|
|
||||||
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()
|
void LFR::startLoop()
|
||||||
{
|
{
|
||||||
if(thread)
|
iAmLooping = true;
|
||||||
{
|
this->loopThread=thread(&LFR::loop, this);
|
||||||
//Restart thread if it is running
|
|
||||||
setStop(true);
|
|
||||||
thread->join();
|
|
||||||
setStop(false);
|
|
||||||
}
|
|
||||||
createThread();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LFR::endLoop()
|
void LFR::endLoop()
|
||||||
{
|
{
|
||||||
setStop(true);
|
iAmLooping = false;
|
||||||
|
this->loopThread.join();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cv::Mat LFR::provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi)
|
void LFR::provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < frameData.contours.size(); i++)
|
for(int i = 0; i < frameData.contours.size(); i++)
|
||||||
{
|
{
|
||||||
@ -134,5 +83,14 @@ cv::Mat LFR::provideOutput(Mat originalImage, Mat processedImage, const FrameDat
|
|||||||
P2.y = (int)round(P1.y + length * sin(frameData.angle * CV_PI / 180.0));
|
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);
|
cv::arrowedLine(originalImage, P1, P2, Scalar(0,0,255), 2, 8);
|
||||||
}
|
}
|
||||||
return originalImage;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include <opencv2/opencv.hpp>
|
#include <opencv2/opencv.hpp>
|
||||||
|
|
||||||
@ -16,52 +15,34 @@
|
|||||||
|
|
||||||
using namespace cv;
|
using namespace cv;
|
||||||
|
|
||||||
struct LFR_Result
|
|
||||||
{
|
|
||||||
cv::Mat rawImage;
|
|
||||||
cv::Mat processedImage;
|
|
||||||
FrameData data;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LFR
|
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;
|
Input input;
|
||||||
Processing processing;
|
Processing processing;
|
||||||
ControlModule controlModule;
|
ControlModule controlModule;
|
||||||
Interpreter interpreter;
|
Interpreter interpreter;
|
||||||
IntersectionHandler intersectionHandler;
|
IntersectionHandler intersectionHandler;
|
||||||
|
volatile bool iAmLooping;
|
||||||
|
void loop();
|
||||||
|
thread loopThread;
|
||||||
int thresholdBinary;
|
int thresholdBinary;
|
||||||
int gaussKernelSize;
|
int gaussKernelSize;
|
||||||
|
|
||||||
ListenerVector listeners;
|
void provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi);
|
||||||
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:
|
public:
|
||||||
|
|
||||||
LFR() = delete;
|
LFR() = delete;
|
||||||
LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize, ExceptionCallback cb);
|
LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize);
|
||||||
~LFR();
|
~LFR();
|
||||||
|
|
||||||
void startLoop();
|
void startLoop();
|
||||||
void endLoop();
|
void endLoop();
|
||||||
void addListener(ListenerCallback cv, ListenerKey key);
|
|
||||||
void removeListener(ListenerKey key);
|
|
||||||
void isStopped() const noexcept;
|
bool videoFlag;
|
||||||
Mat provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi);
|
bool saveOutputFlag;
|
||||||
|
|
||||||
|
std::string outputFileName;
|
||||||
|
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user