|
|
|
|
|
|
|
|
#define right false |
|
|
#define right false |
|
|
#define left true |
|
|
#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->thresholdBinary = thresholdBinary; |
|
|
this->gaussKernelSize = gaussKernelSize; |
|
|
this->gaussKernelSize = gaussKernelSize; |
|
|
|
|
|
|
|
|
this->videoFlag = false; |
|
|
|
|
|
this->saveOutputFlag = false; |
|
|
|
|
|
this->outputFileName = ""; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
LFR::~LFR() |
|
|
LFR::~LFR() |
|
|
{ |
|
|
{ |
|
|
if(iAmLooping) |
|
|
|
|
|
{ |
|
|
|
|
|
this->endLoop(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
endLoop(); |
|
|
|
|
|
thread->join(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void LFR::loop() |
|
|
|
|
|
|
|
|
void LFR::removeListener(LFR::ListenerKey key) |
|
|
{ |
|
|
{ |
|
|
if(this->videoFlag) {namedWindow("Display window");} |
|
|
|
|
|
while(iAmLooping) |
|
|
|
|
|
|
|
|
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)) |
|
|
{ |
|
|
{ |
|
|
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(roi); |
|
|
|
|
|
Mat processedImage = originalImage; |
|
|
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
listeners.erase(it); |
|
|
} |
|
|
} |
|
|
if(this->videoFlag) {destroyWindow("Display window");} |
|
|
|
|
|
input.freeWebcam(); |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LFR::addListener(LFR::ListenerCallback cb, LFR::ListenerKey key) |
|
|
|
|
|
{ |
|
|
|
|
|
std::lock_guard<std::mutex> lock(mutex); |
|
|
|
|
|
listeners.emplace_back(key, std::move(cb)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LFR::setStop(bool val) |
|
|
|
|
|
{ |
|
|
|
|
|
std::lock_guard<std::mutex> lock(mutex); |
|
|
|
|
|
stop = val; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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() |
|
|
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() |
|
|
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++) |
|
|
for(int i = 0; i < frameData.contours.size(); i++) |
|
|
{ |
|
|
{ |
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
{ |
|
|
|
|
|
imshow("Display window", originalImage); |
|
|
|
|
|
imshow("processed:", processedImage); |
|
|
|
|
|
char c = (char)waitKey(25); |
|
|
|
|
|
} |
|
|
|
|
|
if (this->saveOutputFlag && !(this->outputFileName.empty())) |
|
|
|
|
|
{ |
|
|
|
|
|
imwrite(this->outputFileName, originalImage); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return originalImage; |
|
|
} |
|
|
} |