Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
1f66795bb1
@ -1,10 +1,15 @@
|
|||||||
#include "control_module.h"
|
#include "control_module.h"
|
||||||
|
|
||||||
ControlModule::ControlModule(){
|
ControlModule::ControlModule(): ControlModule(1.0, 1.0, 1.0)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlModule::ControlModule(float forwardSpeed, float rotateSpeed, float moveSideSpeed)
|
ControlModule::ControlModule(float forwardSpeed, float rotateSpeed, float moveSideSpeed)
|
||||||
{
|
{
|
||||||
|
motors[0] = 0.0;
|
||||||
|
motors[1] = 0.0;
|
||||||
|
motors[2] = 0.0;
|
||||||
|
motors[3] = 0.0;
|
||||||
this->forwardSpeed = forwardSpeed;
|
this->forwardSpeed = forwardSpeed;
|
||||||
this->rotateSpeed = rotateSpeed;
|
this->rotateSpeed = rotateSpeed;
|
||||||
this->moveSideSpeed = moveSideSpeed;
|
this->moveSideSpeed = moveSideSpeed;
|
||||||
@ -15,13 +20,13 @@ ControlModule::~ControlModule()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ControlModule::moveForward(){
|
void ControlModule::moveForward(){
|
||||||
for(int i = 0; i <= sizeof(motors)/sizeof(int); i++){
|
for(int i = 0; i < 4; i++){
|
||||||
motors[i] += forwardSpeed;
|
motors[i] += forwardSpeed;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void ControlModule::moveSide(int imageColumsMiddle, int contourColumsMiddle){
|
void ControlModule::moveSide(int imageColumsMiddle, int contourColumsMiddle){
|
||||||
float speed = moveSideSpeed * (contourColumsMiddle - imageColumsMiddle)/imageColumsMiddle;
|
float speed = moveSideSpeed * static_cast<float>(contourColumsMiddle - imageColumsMiddle)/static_cast<float>(imageColumsMiddle);
|
||||||
motors[0] += speed;
|
motors[0] += speed;
|
||||||
motors[1] -= speed;
|
motors[1] -= speed;
|
||||||
motors[2] -= speed;
|
motors[2] -= speed;
|
||||||
@ -29,7 +34,7 @@ void ControlModule::moveSide(int imageColumsMiddle, int contourColumsMiddle){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ControlModule::rotate(int angle){
|
void ControlModule::rotate(int angle){
|
||||||
float speed = rotateSpeed * (angle + 90)/90;
|
float speed = rotateSpeed * (static_cast<float>(angle) + 90.0f)/90.0f;
|
||||||
motors[0] += speed;
|
motors[0] += speed;
|
||||||
motors[1] -= speed;
|
motors[1] -= speed;
|
||||||
motors[2] += speed;
|
motors[2] += speed;
|
||||||
@ -37,19 +42,32 @@ void ControlModule::rotate(int angle){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ControlModule::unit(){
|
void ControlModule::unit(){
|
||||||
float max = 10E-12;
|
float max = 1.0E-6;
|
||||||
for(int i = 0; i <= sizeof(motors)/sizeof(int); i++){
|
for(int i = 0; i <= sizeof(motors)/sizeof(int); i++){
|
||||||
if(motors[i] > max)
|
if(motors[i] > max)
|
||||||
max = motors[i];
|
max = motors[i];
|
||||||
}
|
}
|
||||||
for(int i = 0; i <= sizeof(motors)/sizeof(int); i++){
|
|
||||||
motors[i] /= max;
|
//Avoid dividing by zero
|
||||||
|
if (max > 0.001)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 4; i++){
|
||||||
|
motors[i] /= max;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlModule::calcSpeeds(int imageColumsMiddle, int contourColumsMiddle, int angle){
|
void ControlModule::calcSpeeds(int imageColumsMiddle, int contourColumsMiddle, int angle){
|
||||||
|
std::unique_lock<std::mutex> lock(mtx);
|
||||||
moveForward();
|
moveForward();
|
||||||
moveSide(imageColumsMiddle, contourColumsMiddle);
|
moveSide(imageColumsMiddle, contourColumsMiddle);
|
||||||
rotate(angle);
|
rotate(angle);
|
||||||
unit();
|
unit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<float> ControlModule::readMotors()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mtx);
|
||||||
|
return std::vector<float> {motors[0], motors[1], motors[2], motors[3]};
|
||||||
|
}
|
@ -1,8 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
class ControlModule
|
class ControlModule
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
mutable std::mutex mtx;
|
||||||
float motors[4]; //LeftFront; RightFront; LeftBack; RightBack
|
float motors[4]; //LeftFront; RightFront; LeftBack; RightBack
|
||||||
float forwardSpeed;
|
float forwardSpeed;
|
||||||
float rotateSpeed;
|
float rotateSpeed;
|
||||||
@ -17,4 +21,5 @@ public:
|
|||||||
void unit(); //Brings the max Value to 1.0
|
void unit(); //Brings the max Value to 1.0
|
||||||
|
|
||||||
void calcSpeeds(int imageColumsMiddle, int contourColumsMiddle, int angle); //Funktion to be called
|
void calcSpeeds(int imageColumsMiddle, int contourColumsMiddle, int angle); //Funktion to be called
|
||||||
|
std::vector<float> readMotors();
|
||||||
};
|
};
|
@ -1,9 +1,10 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
|
||||||
// TODO: Wenn ihr in die Zeile den Pfad zum Testvideo statt der 0 packt, benmutzt er das Testvideo.
|
// TODO: Wenn ihr in die Zeile den Pfad zum Testvideo statt der 0 packt, benmutzt er das Testvideo.
|
||||||
Input::Input(int videoHeight, int videoWidth) : cap("C:\\Line-Following-Robot\\AutonomousMode\\Test_data\\video1.h264"), videoHeight(videoHeight), videoWidth(videoWidth)
|
Input::Input(int videoHeight, int videoWidth) : cap("C:\\Line-Following-Robot\\AutonomousMode\\Test_data\\video1.h264"), videoHeight(videoHeight), videoWidth(videoWidth)//Input::Input(int videoHeight, int videoWidth) : cap(0), videoHeight(videoHeight), videoWidth(videoWidth)
|
||||||
//Input::Input(int videoHeight, int videoWidth) : cap(0), videoHeight(videoHeight), videoWidth(videoWidth)
|
//Input::Input(int videoHeight, int videoWidth) : cap(0), videoHeight(videoHeight), videoWidth(videoWidth)
|
||||||
{
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mtx);
|
||||||
this->cap.set(CAP_PROP_FRAME_HEIGHT, videoHeight);
|
this->cap.set(CAP_PROP_FRAME_HEIGHT, videoHeight);
|
||||||
this->cap.set(CAP_PROP_FRAME_WIDTH, videoWidth);
|
this->cap.set(CAP_PROP_FRAME_WIDTH, videoWidth);
|
||||||
}
|
}
|
||||||
@ -15,22 +16,25 @@ Input::~Input()
|
|||||||
|
|
||||||
Mat Input::readFile(String filePath)
|
Mat Input::readFile(String filePath)
|
||||||
{
|
{
|
||||||
std::srand(std::time(0));
|
std::unique_lock<std::mutex> lock(mtx);
|
||||||
|
std::srand(static_cast<unsigned int>(std::time(0)));
|
||||||
// Read all .jpg files from the specified folder
|
// Read all .jpg files from the specified folder
|
||||||
cv::String folder = filePath;
|
cv::String folder = filePath;
|
||||||
std::vector<cv::String> filenames;
|
std::vector<cv::String> filenames;
|
||||||
cv::glob(folder, filenames);
|
cv::glob(folder, filenames);
|
||||||
|
|
||||||
// Random shuffle
|
// Random shuffle
|
||||||
std::random_shuffle(filenames.begin(), filenames.end());
|
std::random_device rd;
|
||||||
|
std::mt19937 g(rd());
|
||||||
|
std::shuffle(filenames.begin(), filenames.end(), g);
|
||||||
|
|
||||||
Mat image = imread(filePath, IMREAD_COLOR);
|
Mat image = imread(filePath, IMREAD_COLOR);
|
||||||
|
|
||||||
if(image.empty())
|
if(image.empty())
|
||||||
{
|
{
|
||||||
std::cout << "Could not read the image: " << filePath << std::endl;
|
stringstream sstream;
|
||||||
return Mat();
|
sstream << "Could not read the image: " << filePath << std::endl;
|
||||||
//To do:Exception handeling
|
throw std::runtime_error(sstream.str());
|
||||||
}
|
}
|
||||||
resize(image, image, Size(this->videoWidth, this->videoHeight));
|
resize(image, image, Size(this->videoWidth, this->videoHeight));
|
||||||
return image;
|
return image;
|
||||||
@ -38,16 +42,19 @@ Mat Input::readFile(String filePath)
|
|||||||
|
|
||||||
Mat Input::readWebcam()
|
Mat Input::readWebcam()
|
||||||
{
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mtx);
|
||||||
Mat image;
|
Mat image;
|
||||||
|
|
||||||
if(!cap.isOpened()) {
|
if(!cap.isOpened()) {
|
||||||
cout << "Video capture not opened" << std::endl;
|
stringstream sstream;
|
||||||
return Mat();
|
sstream << "Video capture not opened" << std::endl;
|
||||||
|
throw std::runtime_error(sstream.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!cap.grab()) {
|
if(!cap.grab()) {
|
||||||
cout << "Could not grab frame from camera" << std::endl;
|
stringstream sstream;
|
||||||
return Mat();
|
sstream << "Could not grab frame from camera" << std::endl;
|
||||||
|
throw std::runtime_error(sstream.str());
|
||||||
}
|
}
|
||||||
cap.retrieve(image);
|
cap.retrieve(image);
|
||||||
return image;
|
return image;
|
||||||
@ -55,5 +62,6 @@ Mat Input::readWebcam()
|
|||||||
|
|
||||||
void Input::freeWebcam()
|
void Input::freeWebcam()
|
||||||
{
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mtx);
|
||||||
this->cap.release();
|
this->cap.release();
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include <opencv2/opencv.hpp>
|
#include <opencv2/opencv.hpp>
|
||||||
#include <opencv2/core/utils/logger.hpp>
|
#include <opencv2/core/utils/logger.hpp>
|
||||||
@ -15,7 +16,7 @@ class Input
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
VideoCapture cap;
|
VideoCapture cap;
|
||||||
|
mutable std::mutex mtx;
|
||||||
public:
|
public:
|
||||||
int videoHeight;
|
int videoHeight;
|
||||||
int videoWidth;
|
int videoWidth;
|
||||||
|
@ -6,4 +6,14 @@ IntersectionHandler::IntersectionHandler(/* args */)
|
|||||||
|
|
||||||
IntersectionHandler::~IntersectionHandler()
|
IntersectionHandler::~IntersectionHandler()
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool IntersectionHandler::foundLane(const FrameData& data)
|
||||||
|
{
|
||||||
|
return data.boundingBoxes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool IntersectionHandler::foundIntersection(const FrameData& data)
|
||||||
|
{
|
||||||
|
return data.boundingBoxes.size()>1;
|
||||||
}
|
}
|
@ -1,11 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <utils.h>
|
||||||
|
|
||||||
class IntersectionHandler
|
class IntersectionHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/* data */
|
|
||||||
public:
|
public:
|
||||||
IntersectionHandler(/* args */);
|
IntersectionHandler(/* args */);
|
||||||
|
|
||||||
~IntersectionHandler();
|
~IntersectionHandler();
|
||||||
|
|
||||||
|
const bool foundLane(const FrameData& data);
|
||||||
|
const bool foundIntersection(const FrameData& data);
|
||||||
};
|
};
|
@ -4,19 +4,63 @@
|
|||||||
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;
|
||||||
|
|
||||||
LFR lfr(videoHeight, videoWidth, thresholdBinary, gaussKernelSize);
|
std::mutex mutex;
|
||||||
lfr.saveOutputFlag = false;
|
|
||||||
lfr.videoFlag = true;
|
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 false;
|
||||||
|
});
|
||||||
|
|
||||||
|
//To calculate the frame rate
|
||||||
|
std::chrono::milliseconds last = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||||
|
std::chrono::milliseconds now = std::chrono::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())
|
||||||
|
{
|
||||||
|
img = result.rawImage;
|
||||||
|
//Resize to minimize latency using raspi over ssh
|
||||||
|
//cv::resize(result.rawImage, img, cv::Size(128, 64+32));
|
||||||
|
|
||||||
|
//Calculate frame rate
|
||||||
|
now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||||
|
unsigned int deltaMs = static_cast<unsigned int>((now-last).count());
|
||||||
|
double delta = static_cast<double>(deltaMs) / 1000.0;
|
||||||
|
double frameRate = 1.0 / static_cast<double>(delta);
|
||||||
|
|
||||||
|
if (result.validLane)
|
||||||
|
{
|
||||||
|
std::cout << "Frame rate: " << frameRate << " angle: " << result.data.angle
|
||||||
|
<< " motor 1: " << result.motorSignals[0] << " motor 2: " << result.motorSignals[1]
|
||||||
|
<< " motor 3: " << result.motorSignals[2] << " motor 4: " << result.motorSignals[3] <<std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "No lane found." << std::endl;;
|
||||||
|
}
|
||||||
|
last = now;
|
||||||
|
}
|
||||||
|
}, &mutex);
|
||||||
|
|
||||||
lfr.startLoop();
|
lfr.startLoop();
|
||||||
//To end the video stream, write any char in the console.
|
|
||||||
char a;
|
for(int finished = false; finished != 'q';){
|
||||||
std::cin >> a;
|
finished = std::tolower(cv::waitKey(1));
|
||||||
lfr.endLoop();
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
if(!img.empty()){
|
||||||
|
cv::imshow("frame", img);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,63 +3,123 @@
|
|||||||
#define right false
|
#define right false
|
||||||
#define left true
|
#define left true
|
||||||
|
|
||||||
LFR::LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize)
|
LFR::LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize, ExceptionCallback cb):
|
||||||
: iAmLooping(false), input(videoHeight, videoWidth), processing(), controlModule(), interpreter(), intersectionHandler()
|
stop(false),
|
||||||
|
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()
|
||||||
{
|
{
|
||||||
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");}
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
while(iAmLooping)
|
listeners.emplace_back(key, std::move(cb));
|
||||||
{
|
}
|
||||||
Mat originalImage = input.readWebcam();
|
|
||||||
|
|
||||||
Point roiOrigin(0, int(originalImage.rows*(3.25/6.0)));
|
void LFR::setStop(bool val)
|
||||||
Rect roi(roiOrigin.x, roiOrigin.y, originalImage.cols, originalImage.rows/6);
|
{
|
||||||
//Mat processedImage = originalImage(roi);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
Mat processedImage = originalImage;
|
stop = val;
|
||||||
|
}
|
||||||
|
|
||||||
processing.processImage(processedImage, this->thresholdBinary, this->gaussKernelSize);
|
void LFR::createThread()
|
||||||
//processedImage = processedImage(roi);
|
{
|
||||||
FrameData data = processing.calculateLineSegments(processedImage, roi);
|
thread = std::make_unique<std::thread>([this](){
|
||||||
processing.filterReflections(data);
|
while(true)
|
||||||
processing.calcAngles(data, originalImage.cols, originalImage.rows, left);
|
{
|
||||||
this->provideOutput(originalImage, processedImage, data, roi);
|
LFR_Result result;
|
||||||
}
|
if(!stop && !listeners.empty())
|
||||||
if(this->videoFlag) {destroyWindow("Display window");}
|
{
|
||||||
input.freeWebcam();
|
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);
|
||||||
|
|
||||||
|
result.validLane = intersectionHandler.foundLane(data);
|
||||||
|
if (result.validLane)
|
||||||
|
{
|
||||||
|
controlModule.calcSpeeds(1,1, data.angle);
|
||||||
|
processedImage = provideOutput(originalImage, processedImage, data, roi);
|
||||||
|
}
|
||||||
|
result.rawImage = originalImage;
|
||||||
|
result.processedImage = processedImage;
|
||||||
|
result.data = data;
|
||||||
|
result.motorSignals = controlModule.readMotors();
|
||||||
|
}
|
||||||
|
catch(std::exception const &ex)
|
||||||
|
{
|
||||||
|
if(!cb(ex))
|
||||||
|
{
|
||||||
|
//callback returned false -> exception not handled -> exit
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Invoke the callback method (ListenerPair second -> ListenerCallback)
|
||||||
|
for(auto &val : listeners)
|
||||||
|
{
|
||||||
|
val.second(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void LFR::startLoop()
|
void LFR::startLoop()
|
||||||
{
|
{
|
||||||
iAmLooping = true;
|
if(thread)
|
||||||
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()
|
||||||
{
|
{
|
||||||
iAmLooping = false;
|
setStop(true);
|
||||||
this->loopThread.join();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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++)
|
for(int i = 0; i < frameData.contours.size(); i++)
|
||||||
{
|
{
|
||||||
@ -83,14 +143,5 @@ void LFR::provideOutput(Mat originalImage, Mat processedImage, const FrameData&
|
|||||||
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);
|
||||||
}
|
}
|
||||||
if(this->videoFlag)
|
return originalImage;
|
||||||
{
|
|
||||||
imshow("Display window", originalImage);
|
|
||||||
imshow("processed:", processedImage);
|
|
||||||
char c = (char)waitKey(25);
|
|
||||||
}
|
|
||||||
if (this->saveOutputFlag && !(this->outputFileName.empty()))
|
|
||||||
{
|
|
||||||
imwrite(this->outputFileName, originalImage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include <opencv2/opencv.hpp>
|
#include <opencv2/opencv.hpp>
|
||||||
|
|
||||||
@ -15,34 +16,54 @@
|
|||||||
|
|
||||||
using namespace cv;
|
using namespace cv;
|
||||||
|
|
||||||
|
struct LFR_Result
|
||||||
|
{
|
||||||
|
bool validLane;
|
||||||
|
cv::Mat rawImage;
|
||||||
|
cv::Mat processedImage;
|
||||||
|
FrameData data;
|
||||||
|
std::vector<float> motorSignals;
|
||||||
|
};
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
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:
|
public:
|
||||||
|
|
||||||
LFR() = delete;
|
LFR() = delete;
|
||||||
LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize);
|
LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize, ExceptionCallback cb);
|
||||||
~LFR();
|
~LFR();
|
||||||
|
|
||||||
void startLoop();
|
void startLoop();
|
||||||
void endLoop();
|
void endLoop();
|
||||||
|
void addListener(ListenerCallback cv, ListenerKey key);
|
||||||
|
void removeListener(ListenerKey key);
|
||||||
bool videoFlag;
|
void isStopped() const noexcept;
|
||||||
bool saveOutputFlag;
|
Mat provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi);
|
||||||
|
|
||||||
std::string outputFileName;
|
|
||||||
|
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user