|
|
|
@ -9,6 +9,7 @@ |
|
|
|
|
#include "detail/nanovgcontext.hpp" |
|
|
|
|
#include "detail/nanoguicontext.hpp" |
|
|
|
|
#include "detail/glcontext.hpp" |
|
|
|
|
#include "detail/timetracker.hpp" |
|
|
|
|
#include "opencv2/v4d/dialog.hpp" |
|
|
|
|
#include "opencv2/v4d/formhelper.hpp" |
|
|
|
|
#include <sstream> |
|
|
|
@ -24,8 +25,7 @@ cv::Ptr<V4D> V4D::make(const cv::Size& size, const cv::Size& fbsize, const strin |
|
|
|
|
|
|
|
|
|
V4D::V4D(const cv::Size& size, const cv::Size& fbsize, const string& title, bool offscreen, bool debug, bool compat, int samples) : |
|
|
|
|
initialSize_(size), title_(title), compat_( |
|
|
|
|
compat), samples_(samples), debug_(debug), viewport_(0, 0, size.width, size.height), zoomScale_( |
|
|
|
|
1), mousePos_(0, 0), scaling_(true), pool_(2) { |
|
|
|
|
compat), samples_(samples), debug_(debug), viewport_(0, 0, size.width, size.height), scaling_(true), pool_(2) { |
|
|
|
|
#ifdef __EMSCRIPTEN__ |
|
|
|
|
printf(""); //makes sure we have FS as a dependency
|
|
|
|
|
#endif |
|
|
|
@ -122,31 +122,41 @@ bool V4D::hasGlCtx(uint32_t idx) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::gl(std::function<void()> fn, uint32_t idx) { |
|
|
|
|
glCtx(idx).render([=](const cv::Size& sz) { |
|
|
|
|
CV_UNUSED(sz); |
|
|
|
|
fn(); |
|
|
|
|
TimeTracker::getInstance()->execute("gl(" + detail::func_id(fn) + ")/" + std::to_string(idx), [&](){ |
|
|
|
|
glCtx(idx).render([=](const cv::Size& sz) { |
|
|
|
|
CV_UNUSED(sz); |
|
|
|
|
fn(); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void V4D::gl(std::function<void(const cv::Size&)> fn, uint32_t idx) { |
|
|
|
|
glCtx(idx).render(fn); |
|
|
|
|
TimeTracker::getInstance()->execute("gl(" + detail::func_id(fn) + ")/" + std::to_string(idx), [&](){ |
|
|
|
|
glCtx(idx).render(fn); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void V4D::fb(std::function<void(cv::UMat&)> fn) { |
|
|
|
|
fbCtx().execute(fn); |
|
|
|
|
TimeTracker::getInstance()->execute("fb(" + detail::func_id(fn) + ")", [&](){ |
|
|
|
|
fbCtx().execute(fn); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::nvg(std::function<void()> fn) { |
|
|
|
|
nvgCtx().render([fn](const cv::Size& sz) { |
|
|
|
|
CV_UNUSED(sz); |
|
|
|
|
fn(); |
|
|
|
|
TimeTracker::getInstance()->execute("nvg(" + detail::func_id(fn) + ")", [&](){ |
|
|
|
|
nvgCtx().render([fn](const cv::Size& sz) { |
|
|
|
|
CV_UNUSED(sz); |
|
|
|
|
fn(); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::nvg(std::function<void(const cv::Size&)> fn) { |
|
|
|
|
nvgCtx().render(fn); |
|
|
|
|
TimeTracker::getInstance()->execute("nvg(" + detail::func_id(fn) + ")", [&](){ |
|
|
|
|
nvgCtx().render(fn); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::nanogui(std::function<void(cv::v4d::FormHelper& form)> fn) { |
|
|
|
@ -154,13 +164,17 @@ void V4D::nanogui(std::function<void(cv::v4d::FormHelper& form)> fn) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::copyTo(cv::OutputArray m) { |
|
|
|
|
UMat um = m.getUMat(); |
|
|
|
|
fbCtx().copyTo(um); |
|
|
|
|
TimeTracker::getInstance()->execute("copyTo", [&](){ |
|
|
|
|
UMat um = m.getUMat(); |
|
|
|
|
fbCtx().copyTo(um); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::copyFrom(cv::InputArray m) { |
|
|
|
|
UMat um = m.getUMat(); |
|
|
|
|
fbCtx().copyFrom(um); |
|
|
|
|
TimeTracker::getInstance()->execute("copyTo", [&](){ |
|
|
|
|
UMat um = m.getUMat(); |
|
|
|
|
fbCtx().copyFrom(um); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef __EMSCRIPTEN__ |
|
|
|
@ -194,7 +208,8 @@ void V4D::setSource(const Source& src) { |
|
|
|
|
source_ = src; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::feed(cv::InputArray& in) { |
|
|
|
|
void V4D::feed(cv::InputArray in) { |
|
|
|
|
TimeTracker::getInstance()->execute("feed", [&](){ |
|
|
|
|
cv::UMat frame; |
|
|
|
|
clvaCtx().capture([&](cv::UMat& videoFrame) { |
|
|
|
|
in.copyTo(videoFrame); |
|
|
|
@ -203,15 +218,17 @@ void V4D::feed(cv::InputArray& in) { |
|
|
|
|
fb([frame](cv::UMat& frameBuffer){ |
|
|
|
|
frame.copyTo(frameBuffer); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
InputOutputArray V4D::fetch() { |
|
|
|
|
cv::UMat frame; |
|
|
|
|
|
|
|
|
|
_InputOutputArray V4D::fetch() { |
|
|
|
|
cv::UMat frame; |
|
|
|
|
TimeTracker::getInstance()->execute("copyTo", [&](){ |
|
|
|
|
fb([frame](cv::UMat& framebuffer){ |
|
|
|
|
framebuffer.copyTo(frame); |
|
|
|
|
}); |
|
|
|
|
return frame; |
|
|
|
|
}); |
|
|
|
|
return frame; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool V4D::capture() { |
|
|
|
@ -222,42 +239,42 @@ bool V4D::capture() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool V4D::capture(std::function<void(cv::UMat&)> fn) { |
|
|
|
|
if (!source_.isReady() || !source_.isOpen()) { |
|
|
|
|
bool res = true; |
|
|
|
|
TimeTracker::getInstance()->execute("capture", [&, this](){ |
|
|
|
|
if (!source_.isReady() || !source_.isOpen()) { |
|
|
|
|
#ifndef __EMSCRIPTEN__ |
|
|
|
|
return false; |
|
|
|
|
#else |
|
|
|
|
return true; |
|
|
|
|
res = false; |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
if (futureReader_.valid()) { |
|
|
|
|
if (!futureReader_.get()) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (futureReader_.valid()) { |
|
|
|
|
if (!futureReader_.get()) { |
|
|
|
|
#ifndef __EMSCRIPTEN__ |
|
|
|
|
return false; |
|
|
|
|
#else |
|
|
|
|
return true; |
|
|
|
|
res = false; |
|
|
|
|
#endif |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(nextReaderFrame_.empty()) { |
|
|
|
|
if (!clvaCtx().capture(fn, nextReaderFrame_)) { |
|
|
|
|
if(nextReaderFrame_.empty()) { |
|
|
|
|
if (!clvaCtx().capture(fn, nextReaderFrame_)) { |
|
|
|
|
#ifndef __EMSCRIPTEN__ |
|
|
|
|
return false; |
|
|
|
|
#else |
|
|
|
|
return true; |
|
|
|
|
res = false; |
|
|
|
|
#endif |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
currentReaderFrame_ = nextReaderFrame_.clone(); |
|
|
|
|
futureReader_ = pool_.enqueue( |
|
|
|
|
[](V4D* v, std::function<void(UMat&)> func, cv::UMat& frame) { |
|
|
|
|
return v->clvaCtx().capture(func, frame); |
|
|
|
|
}, this, fn, nextReaderFrame_); |
|
|
|
|
|
|
|
|
|
fb([this](cv::UMat& frameBuffer){ |
|
|
|
|
currentReaderFrame_.copyTo(frameBuffer); |
|
|
|
|
currentReaderFrame_ = nextReaderFrame_.clone(); |
|
|
|
|
futureReader_ = pool_.enqueue( |
|
|
|
|
[](V4D* v, std::function<void(UMat&)> func, cv::UMat& frame) { |
|
|
|
|
return v->clvaCtx().capture(func, frame); |
|
|
|
|
}, this, fn, nextReaderFrame_); |
|
|
|
|
|
|
|
|
|
fb([this](cv::UMat& frameBuffer){ |
|
|
|
|
currentReaderFrame_.copyTo(frameBuffer); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
return true; |
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool V4D::isSourceReady() { |
|
|
|
@ -278,19 +295,21 @@ void V4D::write() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::write(std::function<void(const cv::UMat&)> fn) { |
|
|
|
|
if (!sink_.isReady() || !sink_.isOpen()) |
|
|
|
|
return; |
|
|
|
|
TimeTracker::getInstance()->execute("write", [&, this](){ |
|
|
|
|
if (!sink_.isReady() || !sink_.isOpen()) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
if (futureWriter_.valid()) |
|
|
|
|
futureWriter_.get(); |
|
|
|
|
if (futureWriter_.valid()) |
|
|
|
|
futureWriter_.get(); |
|
|
|
|
|
|
|
|
|
fb([this](cv::UMat& frameBuffer){ |
|
|
|
|
frameBuffer.copyTo(currentWriterFrame_); |
|
|
|
|
}); |
|
|
|
|
fb([this](cv::UMat& frameBuffer){ |
|
|
|
|
frameBuffer.copyTo(currentWriterFrame_); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
futureWriter_ = pool_.enqueue([](V4D* v, std::function<void(const UMat&)> func, cv::UMat& frame) { |
|
|
|
|
v->clvaCtx().write(func, frame); |
|
|
|
|
}, this, fn, currentWriterFrame_); |
|
|
|
|
futureWriter_ = pool_.enqueue([](V4D* v, std::function<void(const UMat&)> func, cv::UMat& frame) { |
|
|
|
|
v->clvaCtx().write(func, frame); |
|
|
|
|
}, this, fn, currentWriterFrame_); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool V4D::isSinkReady() { |
|
|
|
@ -304,100 +323,10 @@ void V4D::showGui(bool s) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::setMouseDrag(bool d) { |
|
|
|
|
mouseDrag_ = d; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool V4D::isMouseDrag() { |
|
|
|
|
return mouseDrag_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::pan(int x, int y) { |
|
|
|
|
viewport_.x += x * zoomScale_; |
|
|
|
|
viewport_.y += y * zoomScale_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::zoom(float factor) { |
|
|
|
|
if (zoomScale_ == 1 && viewport_.x == 0 && viewport_.y == 0 && factor > 1) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
double oldScale = zoomScale_; |
|
|
|
|
double origW = framebufferSize().width; |
|
|
|
|
double origH = framebufferSize().height; |
|
|
|
|
|
|
|
|
|
zoomScale_ *= factor; |
|
|
|
|
if (zoomScale_ <= 0.025) { |
|
|
|
|
zoomScale_ = 0.025; |
|
|
|
|
return; |
|
|
|
|
} else if (zoomScale_ > 1) { |
|
|
|
|
zoomScale_ = 1; |
|
|
|
|
viewport_.width = origW; |
|
|
|
|
viewport_.height = origH; |
|
|
|
|
if (factor > 1) { |
|
|
|
|
viewport_.x += log10(((viewport_.x * (1.0 - factor)) / viewport_.width) * 9 + 1.0) |
|
|
|
|
* viewport_.width; |
|
|
|
|
viewport_.y += log10(((viewport_.y * (1.0 - factor)) / viewport_.height) * 9 + 1.0) |
|
|
|
|
* viewport_.height; |
|
|
|
|
} else { |
|
|
|
|
viewport_.x += log10(((-viewport_.x * (1.0 - factor)) / viewport_.width) * 9 + 1.0) |
|
|
|
|
* viewport_.width; |
|
|
|
|
viewport_.y += log10(((-viewport_.y * (1.0 - factor)) / viewport_.height) * 9 + 1.0) |
|
|
|
|
* viewport_.height; |
|
|
|
|
} |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cv::Vec2f offset; |
|
|
|
|
double oldW = (origW * oldScale); |
|
|
|
|
double oldH = (origH * oldScale); |
|
|
|
|
viewport_.width = std::min(zoomScale_ * origW, origW); |
|
|
|
|
viewport_.height = std::min(zoomScale_ * origH, origH); |
|
|
|
|
|
|
|
|
|
float delta_x; |
|
|
|
|
float delta_y; |
|
|
|
|
|
|
|
|
|
if (factor < 1.0) { |
|
|
|
|
offset = cv::Vec2f(viewport_.x, viewport_.y) |
|
|
|
|
- cv::Vec2f(mousePos_[0], origH - mousePos_[1]); |
|
|
|
|
delta_x = offset[0] / oldW; |
|
|
|
|
delta_y = offset[1] / oldH; |
|
|
|
|
} else { |
|
|
|
|
offset = cv::Vec2f(viewport_.x - (viewport_.width / 2.0), |
|
|
|
|
viewport_.y - (viewport_.height / 2.0)) - cv::Vec2f(viewport_.x, viewport_.y); |
|
|
|
|
delta_x = offset[0] / oldW; |
|
|
|
|
delta_y = offset[1] / oldH; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float x_offset; |
|
|
|
|
float y_offset; |
|
|
|
|
x_offset = delta_x * (viewport_.width - oldW); |
|
|
|
|
y_offset = delta_y * (viewport_.height - oldH); |
|
|
|
|
|
|
|
|
|
if (factor < 1.0) { |
|
|
|
|
viewport_.x += x_offset; |
|
|
|
|
viewport_.y += y_offset; |
|
|
|
|
} else { |
|
|
|
|
viewport_.x += x_offset; |
|
|
|
|
viewport_.y += y_offset; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cv::Vec2f V4D::position() { |
|
|
|
|
return fbCtx().position(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cv::Vec2f V4D::getMousePosition() { |
|
|
|
|
return mousePos_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::setMousePosition(int x, int y) { |
|
|
|
|
mousePos_ = { float(x), float(y) }; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float V4D::zoomScale() { |
|
|
|
|
return zoomScale_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cv::Rect& V4D::viewport() { |
|
|
|
|
return viewport_; |
|
|
|
|
} |
|
|
|
@ -434,6 +363,10 @@ bool V4D::getPrintFPS() { |
|
|
|
|
return printFPS_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool V4D::getShowTracking() { |
|
|
|
|
return showTracking_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::setShowFPS(bool s) { |
|
|
|
|
showFPS_ = s; |
|
|
|
|
} |
|
|
|
@ -442,6 +375,10 @@ void V4D::setPrintFPS(bool p) { |
|
|
|
|
printFPS_ = p; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void V4D::setShowTracking(bool st) { |
|
|
|
|
showTracking_ = st; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool V4D::isFullscreen() { |
|
|
|
|
return fbCtx().isFullscreen(); |
|
|
|
|
} |
|
|
|
@ -545,7 +482,7 @@ bool V4D::display() { |
|
|
|
|
fbCtx().blitFrameBufferToScreen(viewport(), fbCtx().getWindowSize(), isScaling()); |
|
|
|
|
} |
|
|
|
|
#ifndef __EMSCRIPTEN__ |
|
|
|
|
nguiCtx().render(printFPS_, showFPS_); |
|
|
|
|
nguiCtx().render(printFPS_, showFPS_, showTracking_); |
|
|
|
|
#endif |
|
|
|
|
fbCtx().makeCurrent(); |
|
|
|
|
#ifndef __EMSCRIPTEN__ |
|
|
|
|