diff --git a/Makefile b/Makefile index b48445269..76a714a5d 100644 --- a/Makefile +++ b/Makefile @@ -17,9 +17,8 @@ endif ifdef EMSDK CXX := em++ -EMCXXFLAGS += -flto -sDISABLE_EXCEPTION_CATCHING=0 -sDISABLE_EXCEPTION_THROWING=0 -fexceptions -EMLDFLAGS += -s USE_GLFW=3 -s WASM=1 -s -s WASM_BIGINT -s LLD_REPORT_UNDEFINED=1 -s ALLOW_MEMORY_GROWTH=1 -sDISABLE_EXCEPTION_CATCHING=0 -sDISABLE_EXCEPTION_THROWING=0 -sEXCEPTION_DEBUG=1 -fexceptions -#LIBS += -lzlib -lopencv_calib3d -lopencv_core -lopencv_dnn -lopencv_features2d -lopencv_flann -lopencv_imgproc -lopencv_objdetect -lopencv_photo -lopencv_video -lopencv_objdetect -lopencv_face +EMCXXFLAGS += -flto -sINITIAL_MEMORY=512MB -sTOTAL_MEMORY=512MB -s USE_PTHREADS=1 -pthread +EMLDFLAGS += -sUSE_GLFW=3 -sWASM=1 -sWASM_BIGINT -sINITIAL_MEMORY=512MB -sTOTAL_MEMORY=512MB -sALLOW_MEMORY_GROWTH=1 -sUSE_PTHREADS=1 -pthread -sPTHREAD_POOL_SIZE=navigator.hardwareConcurrency EMCXXFLAGS += -msimd128 CXXFLAGS += $(EMCXXFLAGS) -c LDFLAGS += $(EMLDFLAGS) @@ -27,24 +26,69 @@ endif all: release -release: CXXFLAGS += -g0 -O3 +ifneq ($(UNAME_S), Darwin) +release: LDFLAGS += -s +endif +ifdef EMSDK +release: CXXFLAGS += -DNDEBUG -g0 -O3 +release: LDFLAGS += -s STACK_OVERFLOW_CHECK=0 -s ASSERTIONS=0 -s SAFE_HEAP=0 +endif +release: CXXFLAGS += -g0 -O3 -c release: dirs +shrink: CXXFLAGS += -Os -w +shrink: LDFLAGS += -s +shrink: dirs + info: CXXFLAGS += -g3 -O0 +info: LDFLAGS += -Wl,--export-dynamic -rdynamic info: dirs -debug: CXXFLAGS += -g3 -O0 -rdynamic +ifndef EMSDK +debug: CXXFLAGS += -rdynamic +debug: LDFLAGS += -rdynamic +else +debug: CXXFLAGS += -sDISABLE_EXCEPTION_CATCHING=0 -sDISABLE_EXCEPTION_THROWING=0 -fexceptions +debug: LDFLAGS += -s ASSERTIONS=2 -sLLD_REPORT_UNDEFINED=1 -sDISABLE_EXCEPTION_CATCHING=0 -sDISABLE_EXCEPTION_THROWING=0 -sEXCEPTION_DEBUG=1 -fexceptions +endif +debug: CXXFLAGS += -g3 -O0 +debug: LDFLAGS += -Wl,--export-dynamic debug: dirs -profile: CXXFLAGS += -g3 -O1 +profile: CXXFLAGS += -g3 -O3 +profile: LDFLAGS += -Wl,--export-dynamic +ifdef EMSDK +profile: LDFLAGS += --profiling +profile: CXXFLAGS += --profiling +endif +ifndef EMSDK +profile: CXXFLAGS += -rdynamic +endif profile: dirs -unsafe: CXXFLAGS += -g0 -Ofast -DNDEBUG -ffast-math -ftree-vectorizer-verbose=1 -funroll-loops -ftree-vectorize -fno-signed-zeros -fno-trapping-math -frename-registers +ifdef EMSDK +unsafe: CXXFLAGS += -DNDEBUG -g0 -O3 --closure 1 -ffp-contract=fast -freciprocal-math -fno-signed-zeros +unsafe: LDFLAGS += -s STACK_OVERFLOW_CHECK=0 -s ASSERTIONS=0 -s SAFE_HEAP=0 --closure 1 -menable-unsafe-fp-math +else +unsafe: CXXFLAGS += -DNDEBUG -g0 -Ofast +endif +#ifeq ($(UNAME_S), Darwin) +unsafe: LDFLAGS += -s +#endif unsafe: dirs -asan: CXXFLAGS += -g3 -O0 -fno-omit-frame-pointer -fsanitize=address -asan: LDFLAGS += -fsanitize=address +ifdef EMSDK +asan: CXXFLAGS += -fsanitize=address +asan: LDFLAGS += -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=2 -s NO_DISABLE_EXCEPTION_CATCHING=1 -s EXCEPTION_DEBUG=1 -fsanitize=address +else +asan: CXXFLAGS += -rdynamic -fsanitize=address +asan: LDFLAGS += -rdynamic -fsanitize=address +endif +asan: CXXFLAGS += -g3 -O0 -fno-omit-frame-pointer +asan: LDFLAGS += -Wl,--export-dynamic -rdynamic +ifndef EMSDK asan: LIBS+= -lbfd -ldw +endif asan: dirs clean: dirs diff --git a/src/common/detail/clglcontext.cpp b/src/common/detail/clglcontext.cpp index 554117c79..bdfdaf36b 100644 --- a/src/common/detail/clglcontext.cpp +++ b/src/common/detail/clglcontext.cpp @@ -100,24 +100,25 @@ void CLGLContext::end() { void CLGLContext::download(cv::UMat& m) { cv::Mat tmp = m.getMat(cv::ACCESS_RW); assert(tmp.data != nullptr); - GL_CHECK(glReadPixels(0, 0, frameBufferSize_.width, frameBufferSize_.height, GL_RGBA, GL_UNSIGNED_BYTE, tmp.data)); + GL_CHECK(glReadPixels(0, 0, tmp.cols, tmp.rows, GL_RGBA, GL_UNSIGNED_BYTE, tmp.data)); + tmp.release(); } void CLGLContext::upload(const cv::UMat& m) { cv::Mat tmp = m.getMat(cv::ACCESS_RW); assert(tmp.data != nullptr); - GL_CHECK(glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, - frameBufferSize_.width, - frameBufferSize_.height, + tmp.cols, + tmp.rows, GL_RGBA, GL_UNSIGNED_BYTE, tmp.data) ); + tmp.release(); } void CLGLContext::acquireFromGL(cv::UMat &m) { diff --git a/src/common/detail/nanovgcontext.hpp b/src/common/detail/nanovgcontext.hpp index 54cd26f39..df5d185d6 100644 --- a/src/common/detail/nanovgcontext.hpp +++ b/src/common/detail/nanovgcontext.hpp @@ -1,7 +1,12 @@ #ifndef SRC_COMMON_NANOVGCONTEXT_HPP_ #define SRC_COMMON_NANOVGCONTEXT_HPP_ +#ifndef __EMSCRIPTEN__ #define NANOGUI_USE_OPENGL +#else +#define NANOGUI_USE_GLES +#define NANOGUI_GLES_VERSION 3 +#endif #include "clglcontext.hpp" #include #include diff --git a/src/common/nvg.hpp b/src/common/nvg.hpp index 84cf77249..c013ca77d 100644 --- a/src/common/nvg.hpp +++ b/src/common/nvg.hpp @@ -2,7 +2,12 @@ #define SRC_COMMON_NVG_HPP_ #include "viz2d.hpp" +#ifndef __EMSCRIPTEN__ #define NANOGUI_USE_OPENGL +#else +#define NANOGUI_USE_GLES +#define NANOGUI_GLES_VERSION 3 +#endif #include namespace kb { diff --git a/src/common/viz2d.cpp b/src/common/viz2d.cpp index edaf0850d..7e9ce6bd0 100644 --- a/src/common/viz2d.cpp +++ b/src/common/viz2d.cpp @@ -177,7 +177,9 @@ Viz2D::~Viz2D() { } bool Viz2D::initializeWindowing() { - assert(glfwInit() == GLFW_TRUE); + if(glfwInit() != GLFW_TRUE) + return false; + glfwSetErrorCallback(kb::viz2d::error_callback); if (debug_) @@ -186,13 +188,18 @@ bool Viz2D::initializeWindowing() { if (offscreen_) glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); -// glfwSetTime(0); + glfwSetTime(0); #ifdef __APPLE__ - glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 2); - glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 2); + glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); +#elif __EMSCRIPTEN__ + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API) ; #else glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, major_); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor_); diff --git a/src/font/Makefile b/src/font/Makefile index d23c5cbb9..df9bc08f2 100644 --- a/src/font/Makefile +++ b/src/font/Makefile @@ -6,7 +6,7 @@ endif SRCS := font-demo.cpp #precompiled headers -HEADERS := ../common/subsystems.hpp +HEADERS := OBJS := ${SRCS:.cpp=.o} DEPS := ${SRCS:.cpp=.dep} diff --git a/src/font/font-demo.cpp b/src/font/font-demo.cpp index f0f1b7d4e..42dfa6738 100644 --- a/src/font/font-demo.cpp +++ b/src/font/font-demo.cpp @@ -100,8 +100,8 @@ void setup_gui(cv::Ptr v2d) { void iteration() { //BGRA static cv::UMat stars, warped; - static size_t cnt = 0; static cv::RNG rng(cv::getTickCount()); + static size_t cnt = 0; if(update_stars) { v2d->nanovg([&](const cv::Size& sz) { diff --git a/src/optflow/Makefile b/src/optflow/Makefile index 3b59a0d36..60f8b5527 100644 --- a/src/optflow/Makefile +++ b/src/optflow/Makefile @@ -1,15 +1,24 @@ +ifdef EMSDK +TARGET := optflow-demo.js +else TARGET := optflow-demo +endif -SRCS := optflow-demo.cpp +SRCS := optflow-demo.cpp #precompiled headers HEADERS := -OBJS := ${SRCS:.cpp=.o} -DEPS := ${SRCS:.cpp=.dep} +OBJS := ${SRCS:.cpp=.o} +DEPS := ${SRCS:.cpp=.dep} CXXFLAGS += -fpic -LDFLAGS += -LIBS += -lm -lopencv_optflow -lOpenCL -lviz2d +LIBS += -lm -lopencv_optflow -lopencv_video -lopencv_features2d -lviz2d -lz +ifndef EMSDK +LIBS += -lOpenCL +else +LDFLAGS += -sFULL_ES3 -sUSE_ZLIB=1 --bind +endif + .PHONY: all release debug clean distclean all: release diff --git a/src/optflow/optflow-demo.cpp b/src/optflow/optflow-demo.cpp index 1fd467ebc..073fdd551 100644 --- a/src/optflow/optflow-demo.cpp +++ b/src/optflow/optflow-demo.cpp @@ -9,9 +9,11 @@ #include #include #include +#include #include #include +#include #include #include @@ -38,17 +40,67 @@ enum PostProcModes { constexpr unsigned int WIDTH = 1920; constexpr unsigned int HEIGHT = 1080; -constexpr unsigned long DIAG = hypot(double(WIDTH), double(HEIGHT)); +const unsigned long DIAG = hypot(double(WIDTH), double(HEIGHT)); constexpr const char* OUTPUT_FILENAME = "optflow-demo.mkv"; constexpr bool OFFSCREEN = false; constexpr int VA_HW_DEVICE_INDEX = 0; +static cv::Ptr v2d = new kb::viz2d::Viz2D(cv::Size(WIDTH, HEIGHT), cv::Size(WIDTH, HEIGHT), OFFSCREEN, "Sparse Optical Flow Demo"); +#ifndef __EMSCRIPTEN__ +static cv::Ptr v2dMenu = new kb::viz2d::Viz2D(cv::Size(240, 360), cv::Size(240,360), false, "Display Settings"); +#else +# include +# include +# include + +using namespace emscripten; + + +unsigned char buffer[HEIGHT * WIDTH * 4]; + +std::string pushImage(std::string filename){ + + try { + std::ifstream fs(filename, std::fstream::in | std::fstream::binary); + fs.seekg (0, std::ios::end); + auto length = fs.tellg(); + fs.seekg (0, std::ios::beg); + fs.read (reinterpret_cast(buffer),length); + + cv::Mat tmp(HEIGHT, WIDTH, CV_8UC4, buffer); + + v2d->capture([&](cv::UMat &videoFrame) { + tmp.copyTo(videoFrame); + }); + + tmp.release(); + + return "success"; + } catch(std::exception& ex) { + return string(ex.what()); + } +} + +EMSCRIPTEN_BINDINGS(my_module) +{ + function("push_image", &pushImage); +} +#endif + /** Visualization parameters **/ // Generate the foreground at this scale. +#ifndef __EMSCRIPTEN__ float fg_scale = 0.5f; +#else +float fg_scale = 0.5f; +#endif // On every frame the foreground loses on brightness. specifies the loss in percent. +#ifndef __EMSCRIPTEN__ float fg_loss = 2.5; +#else +float fg_loss = 10.0; +#endif //Convert the background to greyscale BackgroundModes background_mode = GREY; // Peak thresholds for the scene change detection. Lowering them makes the detection more sensitive but @@ -57,14 +109,31 @@ float scene_change_thresh = 0.29f; float scene_change_thresh_diff = 0.1f; // The theoretical maximum number of points to track which is scaled by the density of detected points // and therefor is usually much smaller. +#ifndef __EMSCRIPTEN__ int max_points = 250000; +#else +int max_points = 10000; +#endif // How many of the tracked points to lose intentionally, in percent. +#ifndef __EMSCRIPTEN__ float point_loss = 25; +#else +float point_loss = 10; +#endif // The theoretical maximum size of the drawing stroke which is scaled by the area of the convex hull // of tracked points and therefor is usually much smaller. +#ifndef __EMSCRIPTEN__ int max_stroke = 14; +#else +int max_stroke = 2; +#endif // Keep alpha separate for the GUI +#ifndef __EMSCRIPTEN__ float alpha = 0.1f; +#else +float alpha = 1.0f; +#endif + // Red, green, blue and alpha. All from 0.0f to 1.0f nanogui::Color effect_color(1.0f, 0.75f, 0.4f, 1.0f); //display on-screen FPS @@ -74,7 +143,11 @@ bool stretch = false; //Use OpenCL or not bool use_acceleration = true; //The post processing mode +#ifndef __EMSCRIPTEN__ PostProcModes post_proc_mode = GLOW; +#else +PostProcModes post_proc_mode = NONE; +#endif // Intensity of glow or bloom defined by kernel size. The default scales with the image diagonal. int kernel_size = std::max(int(DIAG / 100 % 2 == 0 ? DIAG / 100 + 1 : DIAG / 100), 1); //The lightness selection threshold @@ -84,11 +157,10 @@ float bloom_gain = 3; void prepare_motion_mask(const cv::UMat& srcGrey, cv::UMat& motionMaskGrey) { static cv::Ptr bg_subtrator = cv::createBackgroundSubtractorMOG2(100, 16.0, false); + static int morph_size = 1; + static cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2 * morph_size + 1, 2 * morph_size + 1), cv::Point(morph_size, morph_size)); bg_subtrator->apply(srcGrey, motionMaskGrey); - - int morph_size = 1; - cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2 * morph_size + 1, 2 * morph_size + 1), cv::Point(morph_size, morph_size)); cv::morphologyEx(motionMaskGrey, motionMaskGrey, cv::MORPH_OPEN, element, cv::Point(element.cols >> 1, element.rows >> 1), 2, cv::BORDER_CONSTANT, cv::morphologyDefaultBorderValue()); } @@ -124,6 +196,8 @@ void visualize_sparse_optical_flow(const cv::UMat &prevGrey, const cv::UMat &nex static vector upPrevPoints, upNextPoints; static std::vector status; static std::vector err; + static std::random_device rd; + static std::mt19937 g(rd()); if (detectedPoints.size() > 4) { cv::convexHull(detectedPoints, hull); @@ -133,7 +207,7 @@ void visualize_sparse_optical_flow(const cv::UMat &prevGrey, const cv::UMat &nex float strokeSize = maxStrokeSize * pow(area / (nextGrey.cols * nextGrey.rows), 0.33f); size_t currentMaxPoints = ceil(density * maxPoints); - std::random_shuffle(prevPoints.begin(), prevPoints.end()); + std::shuffle(prevPoints.begin(), prevPoints.end(), g); prevPoints.resize(ceil(prevPoints.size() * (1.0f - (pointLossPercent / 100.0f)))); size_t copyn = std::min(detectedPoints.size(), (size_t(std::ceil(currentMaxPoints)) - prevPoints.size())); @@ -267,7 +341,6 @@ void composite_layers(cv::UMat& background, const cv::UMat& foreground, const cv cv::add(background, post, dst); } - void setup_gui(cv::Ptr v2d, cv::Ptr v2dMenu) { v2d->makeWindow(5, 30, "Effects"); @@ -344,30 +417,105 @@ void setup_gui(cv::Ptr v2d, cv::Ptr v2dMenu) v2dMenu->makeFormVariable("Stetch", stretch, "Stretch the frame buffer to the window size")->set_callback([=](const bool &s) { v2d->setStretching(s); }); +#ifndef __EMSCRIPTEN__ v2dMenu->makeButton("Fullscreen", [=]() { v2d->setFullscreen(!v2d->isFullscreen()); }); v2dMenu->makeButton("Offscreen", [=]() { v2d->setOffscreen(!v2d->isOffscreen()); }); +#endif } +void iteration() { + //BGRA + static cv::UMat background, down; + static cv::UMat foreground(v2d->getFrameBufferSize(), CV_8UC4, cv::Scalar::all(0)); + //RGB + static cv::UMat menuFrame; + //GREY + static cv::UMat downPrevGrey, downNextGrey, downMotionMaskGrey; + static vector detectedPoints; + + if(v2d->isAccelerated() != use_acceleration) + v2d->setAccelerated(use_acceleration); + +#ifndef __EMSCRIPTEN__ + if(!v2d->capture()) + exit(0); +#endif + + v2d->opencl([&](cv::UMat& frameBuffer) { + cv::resize(frameBuffer, down, cv::Size(v2d->getFrameBufferSize().width * fg_scale, v2d->getFrameBufferSize().height * fg_scale)); + frameBuffer.copyTo(background); + }); + + cv::cvtColor(down, downNextGrey, cv::COLOR_RGBA2GRAY); + //Subtract the background to create a motion mask + prepare_motion_mask(downNextGrey, downMotionMaskGrey); + //Detect trackable points in the motion mask + detect_points(downMotionMaskGrey, detectedPoints); + + v2d->nanovg([&](const cv::Size& sz) { + v2d->clear(); + if (!downPrevGrey.empty()) { + //We don't want the algorithm to get out of hand when there is a scene change, so we suppress it when we detect one. + if (!detect_scene_change(downMotionMaskGrey, scene_change_thresh, scene_change_thresh_diff)) { + //Visualize the sparse optical flow using nanovg + cv::Scalar color = cv::Scalar(effect_color.b() * 255.0f, effect_color.g() * 255.0f, effect_color.r() * 255.0f, alpha * 255.0f); + visualize_sparse_optical_flow(downPrevGrey, downNextGrey, detectedPoints, fg_scale, max_stroke, color, max_points, point_loss); + } + } + }); + + downPrevGrey = downNextGrey.clone(); + + v2d->opencl([&](cv::UMat& frameBuffer){ + //Put it all together (OpenCL) + composite_layers(background, foreground, frameBuffer, frameBuffer, kernel_size, fg_loss, background_mode, post_proc_mode); +#ifndef __EMSCRIPTEN__ + cvtColor(frameBuffer, menuFrame, cv::COLOR_BGRA2RGB); +#endif + }); + + update_fps(v2d, show_fps); + +#ifndef __EMSCRIPTEN__ + v2d->write(); + + v2dMenu->capture([&](cv::UMat& videoFrame) { + menuFrame.copyTo(videoFrame); + }); + + if(!v2dMenu->display()) + exit(0); +#endif + + //If onscreen rendering is enabled it displays the framebuffer in the native window. Returns false if the window was closed. + if(!v2d->display()) + exit(0); +} int main(int argc, char **argv) { using namespace kb::viz2d; +#ifndef __EMSCRIPTEN__ if (argc != 2) { std::cerr << "Usage: optflow " << endl; exit(1); } - - cv::Ptr v2d = new Viz2D(cv::Size(WIDTH, HEIGHT), cv::Size(WIDTH, HEIGHT), OFFSCREEN, "Sparse Optical Flow Demo"); - cv::Ptr v2dMenu = new Viz2D(cv::Size(240, 360), cv::Size(240,360), false, "Display Settings"); +#endif print_system_info(); + if(!v2d->isOffscreen()) { +#ifndef __EMSCRIPTEN__ setup_gui(v2d, v2dMenu); - v2d->setVisible(true); v2dMenu->setVisible(true); +#else + setup_gui(v2d, v2d); +#endif + v2d->setVisible(true); } +#ifndef __EMSCRIPTEN__ auto capture = v2d->makeVACapture(argv[1], VA_HW_DEVICE_INDEX); if (!capture.isOpened()) { @@ -378,70 +526,15 @@ int main(int argc, char **argv) { float fps = capture.get(cv::CAP_PROP_FPS); float width = capture.get(cv::CAP_PROP_FRAME_WIDTH); float height = capture.get(cv::CAP_PROP_FRAME_HEIGHT); - v2d->makeVAWriter(OUTPUT_FILENAME, cv::VideoWriter::fourcc('V', 'P', '9', '0'), fps, cv::Size(width, height), VA_HW_DEVICE_INDEX); - - //BGRA - cv::UMat background, down; - cv::UMat foreground(v2d->getFrameBufferSize(), CV_8UC4, cv::Scalar::all(0)); - //RGB - cv::UMat menuFrame; - //GREY - cv::UMat downPrevGrey, downNextGrey, downMotionMaskGrey; - vector detectedPoints; + v2d->makeVAWriter(OUTPUT_FILENAME, cv::VideoWriter::fourcc('V', 'P', '9', '0'), fps, cv::Size(width, height), VA_HW_DEVICE_INDEX); while (true) { - if(v2d->isAccelerated() != use_acceleration) - v2d->setAccelerated(use_acceleration); - - if(!v2d->capture()) - break; - - v2d->opencl([&](cv::UMat& frameBuffer) { - cv::resize(frameBuffer, down, cv::Size(v2d->getFrameBufferSize().width * fg_scale, v2d->getFrameBufferSize().height * fg_scale)); - frameBuffer.copyTo(background); - }); - - cv::cvtColor(down, downNextGrey, cv::COLOR_RGBA2GRAY); - //Subtract the background to create a motion mask - prepare_motion_mask(downNextGrey, downMotionMaskGrey); - //Detect trackable points in the motion mask - detect_points(downMotionMaskGrey, detectedPoints); - - v2d->nanovg([&](const cv::Size& sz) { - v2d->clear(); - if (!downPrevGrey.empty()) { - //We don't want the algorithm to get out of hand when there is a scene change, so we suppress it when we detect one. - if (!detect_scene_change(downMotionMaskGrey, scene_change_thresh, scene_change_thresh_diff)) { - //Visualize the sparse optical flow using nanovg - cv::Scalar color = cv::Scalar(effect_color.b() * 255.0f, effect_color.g() * 255.0f, effect_color.r() * 255.0f, alpha * 255.0f); - visualize_sparse_optical_flow(downPrevGrey, downNextGrey, detectedPoints, fg_scale, max_stroke, color, max_points, point_loss); - } - } - }); - - downPrevGrey = downNextGrey.clone(); - - v2d->opencl([&](cv::UMat& frameBuffer){ - //Put it all together (OpenCL) - composite_layers(background, foreground, frameBuffer, frameBuffer, kernel_size, fg_loss, background_mode, post_proc_mode); - cvtColor(frameBuffer, menuFrame, cv::COLOR_BGRA2RGB); - }); - - update_fps(v2d, show_fps); - - v2d->write(); - - v2dMenu->capture([&](cv::UMat& videoFrame) { - menuFrame.copyTo(videoFrame); - }); - - //If onscreen rendering is enabled it displays the framebuffer in the native window. Returns false if the window was closed. - if(!v2d->display()) - break; - - if(!v2dMenu->display()) - break; + iteration(); } +#else + emscripten_set_main_loop(iteration, -1, false); +#endif + return 0; }