├── .gitignore ├── CMakeLists.txt ├── README.md ├── hello.cpp ├── index.html └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | third-party 3 | 4 | # Created by https://www.gitignore.io/api/osx,vim,c++,linux,windows 5 | # Edit at https://www.gitignore.io/?templates=osx,vim,c++,linux,windows 6 | 7 | ### C++ ### 8 | # Prerequisites 9 | *.d 10 | 11 | # Compiled Object files 12 | *.slo 13 | *.lo 14 | *.o 15 | *.obj 16 | 17 | # Precompiled Headers 18 | *.gch 19 | *.pch 20 | 21 | # Compiled Dynamic libraries 22 | *.so 23 | *.dylib 24 | *.dll 25 | 26 | # Fortran module files 27 | *.mod 28 | *.smod 29 | 30 | # Compiled Static libraries 31 | *.lai 32 | *.la 33 | *.a 34 | *.lib 35 | 36 | # Executables 37 | *.exe 38 | *.out 39 | *.app 40 | 41 | ### Linux ### 42 | *~ 43 | 44 | # temporary files which can be created if a process still has a handle open of a deleted file 45 | .fuse_hidden* 46 | 47 | # KDE directory preferences 48 | .directory 49 | 50 | # Linux trash folder which might appear on any partition or disk 51 | .Trash-* 52 | 53 | # .nfs files are created when an open file is removed but is still being accessed 54 | .nfs* 55 | 56 | ### OSX ### 57 | # General 58 | .DS_Store 59 | .AppleDouble 60 | .LSOverride 61 | 62 | # Icon must end with two \r 63 | Icon 64 | 65 | # Thumbnails 66 | ._* 67 | 68 | # Files that might appear in the root of a volume 69 | .DocumentRevisions-V100 70 | .fseventsd 71 | .Spotlight-V100 72 | .TemporaryItems 73 | .Trashes 74 | .VolumeIcon.icns 75 | .com.apple.timemachine.donotpresent 76 | 77 | # Directories potentially created on remote AFP share 78 | .AppleDB 79 | .AppleDesktop 80 | Network Trash Folder 81 | Temporary Items 82 | .apdisk 83 | 84 | ### Vim ### 85 | # Swap 86 | [._]*.s[a-v][a-z] 87 | [._]*.sw[a-p] 88 | [._]s[a-rt-v][a-z] 89 | [._]ss[a-gi-z] 90 | [._]sw[a-p] 91 | 92 | # Session 93 | Session.vim 94 | 95 | # Temporary 96 | .netrwhist 97 | # Auto-generated tag files 98 | tags 99 | # Persistent undo 100 | [._]*.un~ 101 | 102 | ### Windows ### 103 | # Windows thumbnail cache files 104 | Thumbs.db 105 | ehthumbs.db 106 | ehthumbs_vista.db 107 | 108 | # Dump file 109 | *.stackdump 110 | 111 | # Folder config file 112 | [Dd]esktop.ini 113 | 114 | # Recycle Bin used on file shares 115 | $RECYCLE.BIN/ 116 | 117 | # Windows Installer files 118 | *.cab 119 | *.msi 120 | *.msix 121 | *.msm 122 | *.msp 123 | 124 | # Windows shortcuts 125 | *.lnk 126 | 127 | # End of https://www.gitignore.io/api/osx,vim,c++,linux,windows 128 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required( VERSION 3.1 ) 2 | project( HelloCV ) 3 | 4 | # Use C++ 11 by default 5 | set( CMAKE_CXX_STANDARD 11 ) 6 | 7 | # Set Release as default build type 8 | if(NOT CMAKE_BUILD_TYPE) 9 | set(CMAKE_BUILD_TYPE Release) 10 | endif(NOT CMAKE_BUILD_TYPE) 11 | 12 | # Does not work 13 | # find_package( OpenCV REQUIRED PATHS third-party/opencv-4.1.0/build_wasm NO_DEFAULT_PATH) 14 | 15 | # Needed for opencv2/opencv.hpp 16 | include_directories( third-party/opencv-4.1.0/include ) 17 | 18 | # Needed by opencv.hpp for opencv2/opencv_modules.hpp 19 | include_directories( third-party/opencv-4.1.0/build_wasm ) 20 | 21 | # Needed by opencv_modules.hpp for every module 22 | file( GLOB opencv_include_modules "third-party/opencv-4.1.0/modules/*/include" ) 23 | include_directories( ${opencv_include_modules} ) 24 | 25 | # Our hello world executable 26 | add_executable( hello hello.cpp ) 27 | 28 | # Link to opencv.js precompiled libraries 29 | file( GLOB opencv_js "third-party/opencv-4.1.0/build_wasm/lib/*.a" ) 30 | target_link_libraries( hello ${opencv_js} ) 31 | 32 | # Specify linker arguments 33 | # set_target_properties( hello PROPERTIES LINK_FLAGS "-s DEMANGLE_SUPPORT=1 --preload-file assets --bind" ) 34 | set_target_properties( hello PROPERTIES LINK_FLAGS "-s DEMANGLE_SUPPORT=1 --bind" ) 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # emscripten-opencv 2 | 3 | Or how to use opencv as a dependency in WebAssembly (wasm) code. 4 | This repository is an attempt at doing very basic image tasks like: 5 | 6 | - Decoding an image into a Mat. 7 | - Doing some matrix processing. 8 | - Exposing matrix data back to JavaScript. 9 | 10 | ## Setup 11 | 12 | You need to have [emscripten][emscripten] installed and accessible (source the shell scripts). 13 | You also need [OpenCV][opencv] source code to be able to compile its wasm version. 14 | Adapt the `CMakeLists.txt` to the location of your OpenCV directory. 15 | 16 | [emscripten]: https://emscripten.org/index.html 17 | [opencv]: https://opencv.org/ 18 | 19 | ## Activate Emscripten in the shell 20 | 21 | You can add some code to your shell config file. 22 | Personally I just run the following (fish shell) when I need it. 23 | 24 | ``` 25 | source ~/programs/emsdk/emsdk_env.fish 26 | ``` 27 | 28 | ## Build OpenCV.js 29 | 30 | OpenCV.js is the name of the Emscripten build of OpenCV. 31 | In our case, we are building it for WebAssembly (wasm). 32 | 33 | ``` 34 | python ./platforms/js/build_js.py build_wasm --build_wasm 35 | ``` 36 | 37 | > PS: You can modify the `build_js.py` file to enable/disable modules. 38 | 39 | ## Building this example with Emscripten 40 | 41 | ``` 42 | mkdir build 43 | cd build 44 | emconfigure cmake .. 45 | emmake make 46 | ``` 47 | 48 | ## Running the example in the browser 49 | 50 | After building the example, just deploy a static http server at the root of this repository. 51 | 52 | ``` 53 | python -m http.server 8080 54 | ``` 55 | 56 | Then open your localhost page, and look at the dev tools console. 57 | -------------------------------------------------------------------------------- /hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | using namespace cv; 11 | using namespace emscripten; 12 | 13 | class Hello { 14 | private: 15 | std::vector buffer; 16 | Mat decoded; 17 | 18 | public: 19 | Hello() : buffer{}, decoded{} {}; 20 | 21 | val allocate(size_t size) { 22 | this->buffer.reserve(size); 23 | unsigned char *byteBuffer = this->buffer.data(); 24 | return val(typed_memory_view(size, byteBuffer)); 25 | } 26 | 27 | Mat my_imdecode() { 28 | // this->decoded = cv::imdecode(this->buffer, IMREAD_GRAYSCALE); 29 | return this->decoded; 30 | } 31 | }; 32 | 33 | EMSCRIPTEN_BINDINGS(my_module) { 34 | class_("Mat"); 35 | class_("Hello") 36 | .constructor<>() 37 | .function("imdecode", &Hello::my_imdecode) 38 | .function("allocate", &Hello::allocate); 39 | } 40 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | emscripten-opencv 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var Module = { 2 | onRuntimeInitialized: () => init(Module) 3 | }; 4 | 5 | function init(Module) { 6 | const hello = new Module.Hello(); 7 | const view = hello.allocate(1000); 8 | console.log("allocated"); 9 | // TODO put in "view" actual image data 10 | const mat = hello.imdecode(); 11 | console.log("decoded"); 12 | } 13 | --------------------------------------------------------------------------------