Merge remote-tracking branch 'upstream/3.4' into merge-3.4

pull/18639/head
Alexander Alekhin 4 years ago
commit e8058b9fdb
  1. 1
      3rdparty/protobuf/CMakeLists.txt
  2. 34
      doc/js_tutorials/js_setup/js_setup/js_setup.markdown
  3. 2
      modules/core/include/opencv2/core/cvdef.h
  4. 313
      modules/core/include/opencv2/core/hal/intrin_wasm.hpp
  5. 8
      modules/imgcodecs/include/opencv2/imgcodecs.hpp
  6. 0
      modules/imgproc/doc/pics/colormaps/colorscale_deepgreen.jpg
  7. 2
      modules/imgproc/include/opencv2/imgproc.hpp
  8. 6
      modules/imgproc/src/demosaicing.cpp
  9. 19
      modules/js/CMakeLists.txt
  10. 15
      modules/js/perf/base.js
  11. 67
      modules/js/perf/perf_64bits.html
  12. 180
      modules/js/perf/perf_64bits.js
  13. 244
      modules/js/perf/perf_helpfunc.js
  14. 73
      modules/js/perf/perf_imgproc/perf_blur.html
  15. 130
      modules/js/perf/perf_imgproc/perf_blur.js
  16. 370
      modules/js/perf/perf_imgproc/perf_cvtcolor.js
  17. 73
      modules/js/perf/perf_imgproc/perf_dilate.html
  18. 117
      modules/js/perf/perf_imgproc/perf_dilate.js
  19. 73
      modules/js/perf/perf_imgproc/perf_erode.html
  20. 117
      modules/js/perf/perf_imgproc/perf_erode.js
  21. 73
      modules/js/perf/perf_imgproc/perf_filter2D.html
  22. 127
      modules/js/perf/perf_imgproc/perf_filter2D.js
  23. 73
      modules/js/perf/perf_imgproc/perf_gaussianBlur.html
  24. 126
      modules/js/perf/perf_imgproc/perf_gaussianBlur.js
  25. 73
      modules/js/perf/perf_imgproc/perf_medianBlur.html
  26. 118
      modules/js/perf/perf_imgproc/perf_medianBlur.js
  27. 73
      modules/js/perf/perf_imgproc/perf_pyrDown.html
  28. 116
      modules/js/perf/perf_imgproc/perf_pyrDown.js
  29. 73
      modules/js/perf/perf_imgproc/perf_remap.html
  30. 182
      modules/js/perf/perf_imgproc/perf_remap.js
  31. 197
      modules/js/perf/perf_imgproc/perf_resize.js
  32. 73
      modules/js/perf/perf_imgproc/perf_scharr.html
  33. 156
      modules/js/perf/perf_imgproc/perf_scharr.js
  34. 73
      modules/js/perf/perf_imgproc/perf_sobel.html
  35. 170
      modules/js/perf/perf_imgproc/perf_sobel.js
  36. 199
      modules/js/perf/perf_imgproc/perf_threshold.js
  37. 73
      modules/js/perf/perf_imgproc/perf_warpAffine.html
  38. 130
      modules/js/perf/perf_imgproc/perf_warpAffine.js
  39. 73
      modules/js/perf/perf_imgproc/perf_warpPerspective.html
  40. 143
      modules/js/perf/perf_imgproc/perf_warpPerspective.js
  41. 96
      modules/js/src/loader.js
  42. 14
      platforms/js/build_js.py
  43. 4
      samples/dnn/siamrpnpp.py

@ -140,6 +140,7 @@ append_if_exist(Protobuf_SRCS
${PROTOBUF_ROOT}/src/google/protobuf/wrappers.pb.cc ${PROTOBUF_ROOT}/src/google/protobuf/wrappers.pb.cc
) )
include_directories(BEFORE "${PROTOBUF_ROOT}/src") # ensure using if own headers: https://github.com/opencv/opencv/issues/13328
add_library(libprotobuf STATIC ${Protobuf_SRCS}) add_library(libprotobuf STATIC ${Protobuf_SRCS})
target_include_directories(libprotobuf SYSTEM PUBLIC $<BUILD_INTERFACE:${PROTOBUF_ROOT}/src>) target_include_directories(libprotobuf SYSTEM PUBLIC $<BUILD_INTERFACE:${PROTOBUF_ROOT}/src>)
set_target_properties(libprotobuf set_target_properties(libprotobuf

@ -32,6 +32,15 @@ source ./emsdk_env.sh
echo ${EMSCRIPTEN} echo ${EMSCRIPTEN}
@endcode @endcode
The version 1.39.16 of emscripten is verified for latest WebAssembly. Please check the version of emscripten to use the newest features of WebAssembly.
For example:
@code{.bash}
./emsdk update
./emsdk install 1.39.16
./emsdk activate 1.39.16
@endcode
Obtaining OpenCV Source Code Obtaining OpenCV Source Code
-------------------------- --------------------------
@ -76,6 +85,31 @@ Building OpenCV.js from Source
python ./platforms/js/build_js.py build_wasm --build_wasm python ./platforms/js/build_js.py build_wasm --build_wasm
@endcode @endcode
-# [Optional] To build the OpenCV.js loader, append `--build_loader`.
For example:
@code{.bash}
python ./platforms/js/build_js.py build_js --build_loader
@endcode
@note
The loader is implemented as a js file in the path `<opencv_js_dir>/bin/loader.js`. The loader utilizes the [WebAssembly Feature Detection](https://github.com/GoogleChromeLabs/wasm-feature-detect) to detect the features of the broswer and load corresponding OpenCV.js automatically. To use it, you need to use the UMD version of [WebAssembly Feature Detection](https://github.com/GoogleChromeLabs/wasm-feature-detect) and introduce the `loader.js` in your Web application.
Example Code:
@code{.javascipt}
// Set paths configuration
let pathsConfig = {
wasm: "../../build_wasm/opencv.js",
threads: "../../build_mt/opencv.js",
simd: "../../build_simd/opencv.js",
threadsSimd: "../../build_mtSIMD/opencv.js",
}
// Load OpenCV.js and use the pathsConfiguration and main function as the params.
loadOpenCV(pathsConfig, main);
@endcode
-# [optional] To build documents, append `--build_doc` option. -# [optional] To build documents, append `--build_doc` option.
For example: For example:

@ -90,7 +90,7 @@ namespace cv { namespace debug_build_guard { } using namespace debug_build_guard
// keep current value (through OpenCV port file) // keep current value (through OpenCV port file)
#elif defined __GNUC__ || (defined (__cpluscplus) && (__cpluscplus >= 201103)) #elif defined __GNUC__ || (defined (__cpluscplus) && (__cpluscplus >= 201103))
#define CV_Func __func__ #define CV_Func __func__
#elif defined __clang__ && (__clang_minor__ * 100 + __clang_major >= 305) #elif defined __clang__ && (__clang_minor__ * 100 + __clang_major__ >= 305)
#define CV_Func __func__ #define CV_Func __func__
#elif defined(__STDC_VERSION__) && (__STDC_VERSION >= 199901) #elif defined(__STDC_VERSION__) && (__STDC_VERSION >= 199901)
#define CV_Func __func__ #define CV_Func __func__

@ -207,13 +207,7 @@ struct v_uint64x2
uint64 get0() const uint64 get0() const
{ {
#ifdef __wasm_unimplemented_simd128__
return (uint64)wasm_i64x2_extract_lane(val, 0); return (uint64)wasm_i64x2_extract_lane(val, 0);
#else
uint64 des[2];
wasm_v128_store(des, val);
return des[0];
#endif
} }
v128_t val; v128_t val;
@ -235,13 +229,7 @@ struct v_int64x2
int64 get0() const int64 get0() const
{ {
#ifdef __wasm_unimplemented_simd128__
return wasm_i64x2_extract_lane(val, 0); return wasm_i64x2_extract_lane(val, 0);
#else
int64 des[2];
wasm_v128_store(des, val);
return des[0];
#endif
} }
v128_t val; v128_t val;
@ -263,13 +251,7 @@ struct v_float64x2
double get0() const double get0() const
{ {
#ifdef __wasm_unimplemented_simd128__
return wasm_f64x2_extract_lane(val, 0); return wasm_f64x2_extract_lane(val, 0);
#else
double des[2];
wasm_v128_store(des, val);
return des[0];
#endif
} }
v128_t val; v128_t val;
@ -1797,22 +1779,9 @@ OPENCV_HAL_IMPL_WASM_INITVEC(v_int16x8, short, s16, i16x8, short)
OPENCV_HAL_IMPL_WASM_INITVEC(v_uint32x4, unsigned, u32, i32x4, int) OPENCV_HAL_IMPL_WASM_INITVEC(v_uint32x4, unsigned, u32, i32x4, int)
OPENCV_HAL_IMPL_WASM_INITVEC(v_int32x4, int, s32, i32x4, int) OPENCV_HAL_IMPL_WASM_INITVEC(v_int32x4, int, s32, i32x4, int)
OPENCV_HAL_IMPL_WASM_INITVEC(v_float32x4, float, f32, f32x4, float) OPENCV_HAL_IMPL_WASM_INITVEC(v_float32x4, float, f32, f32x4, float)
#ifdef __wasm_unimplemented_simd128__
OPENCV_HAL_IMPL_WASM_INITVEC(v_uint64x2, uint64, u64, i64x2, int64) OPENCV_HAL_IMPL_WASM_INITVEC(v_uint64x2, uint64, u64, i64x2, int64)
OPENCV_HAL_IMPL_WASM_INITVEC(v_int64x2, int64, s64, i64x2, int64) OPENCV_HAL_IMPL_WASM_INITVEC(v_int64x2, int64, s64, i64x2, int64)
OPENCV_HAL_IMPL_WASM_INITVEC(v_float64x2, double, f64, f64x2, double) OPENCV_HAL_IMPL_WASM_INITVEC(v_float64x2, double, f64, f64x2, double)
#else
#define OPENCV_HAL_IMPL_FALLBACK_INITVEC(_Tpvec, _Tp, suffix, _Tps) \
inline _Tpvec v_setzero_##suffix() { return _Tpvec((_Tps)0, (_Tps)0); } \
inline _Tpvec v_setall_##suffix(_Tp v) { return _Tpvec((_Tps)v, (_Tps)v); } \
template<typename _Tpvec0> inline _Tpvec v_reinterpret_as_##suffix(const _Tpvec0& a) \
{ return _Tpvec(a.val); }
OPENCV_HAL_IMPL_FALLBACK_INITVEC(v_uint64x2, uint64, u64, int64)
OPENCV_HAL_IMPL_FALLBACK_INITVEC(v_int64x2, int64, s64, int64)
OPENCV_HAL_IMPL_FALLBACK_INITVEC(v_float64x2, double, f64, double)
#endif
//////////////// PACK /////////////// //////////////// PACK ///////////////
inline v_uint8x16 v_pack(const v_uint16x8& a, const v_uint16x8& b) inline v_uint8x16 v_pack(const v_uint16x8& a, const v_uint16x8& b)
@ -1931,28 +1900,18 @@ inline v_int16x8 v_rshr_pack(const v_int32x4& a, const v_int32x4& b)
template<int n> template<int n>
inline v_uint32x4 v_rshr_pack(const v_uint64x2& a, const v_uint64x2& b) inline v_uint32x4 v_rshr_pack(const v_uint64x2& a, const v_uint64x2& b)
{ {
#ifdef __wasm_unimplemented_simd128__
v128_t delta = wasm_i64x2_splat(((int64)1 << (n-1))); v128_t delta = wasm_i64x2_splat(((int64)1 << (n-1)));
v128_t a1 = wasm_u64x2_shr(wasm_i64x2_add(a.val, delta), n); v128_t a1 = wasm_u64x2_shr(wasm_i64x2_add(a.val, delta), n);
v128_t b1 = wasm_u64x2_shr(wasm_i64x2_add(b.val, delta), n); v128_t b1 = wasm_u64x2_shr(wasm_i64x2_add(b.val, delta), n);
return v_uint32x4(wasm_v8x16_shuffle(a1, b1, 0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27)); return v_uint32x4(wasm_v8x16_shuffle(a1, b1, 0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27));
#else
fallback::v_uint64x2 a_(a), b_(b);
return fallback::v_rshr_pack<n>(a_, b_);
#endif
} }
template<int n> template<int n>
inline v_int32x4 v_rshr_pack(const v_int64x2& a, const v_int64x2& b) inline v_int32x4 v_rshr_pack(const v_int64x2& a, const v_int64x2& b)
{ {
#ifdef __wasm_unimplemented_simd128__
v128_t delta = wasm_i64x2_splat(((int64)1 << (n-1))); v128_t delta = wasm_i64x2_splat(((int64)1 << (n-1)));
v128_t a1 = wasm_i64x2_shr(wasm_i64x2_add(a.val, delta), n); v128_t a1 = wasm_i64x2_shr(wasm_i64x2_add(a.val, delta), n);
v128_t b1 = wasm_i64x2_shr(wasm_i64x2_add(b.val, delta), n); v128_t b1 = wasm_i64x2_shr(wasm_i64x2_add(b.val, delta), n);
return v_int32x4(wasm_v8x16_shuffle(a1, b1, 0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27)); return v_int32x4(wasm_v8x16_shuffle(a1, b1, 0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27));
#else
fallback::v_int64x2 a_(a), b_(b);
return fallback::v_rshr_pack<n>(a_, b_);
#endif
} }
template<int n> template<int n>
inline v_uint8x16 v_rshr_pack_u(const v_int16x8& a, const v_int16x8& b) inline v_uint8x16 v_rshr_pack_u(const v_int16x8& a, const v_int16x8& b)
@ -2139,7 +2098,6 @@ inline void v_rshr_pack_store(short* ptr, const v_int32x4& a)
template<int n> template<int n>
inline void v_rshr_pack_store(unsigned* ptr, const v_uint64x2& a) inline void v_rshr_pack_store(unsigned* ptr, const v_uint64x2& a)
{ {
#ifdef __wasm_unimplemented_simd128__
v128_t delta = wasm_i64x2_splat(((int64)1 << (n-1))); v128_t delta = wasm_i64x2_splat(((int64)1 << (n-1)));
v128_t a1 = wasm_u64x2_shr(wasm_i64x2_add(a.val, delta), n); v128_t a1 = wasm_u64x2_shr(wasm_i64x2_add(a.val, delta), n);
v128_t r = wasm_v8x16_shuffle(a1, a1, 0,1,2,3,8,9,10,11,0,1,2,3,8,9,10,11); v128_t r = wasm_v8x16_shuffle(a1, a1, 0,1,2,3,8,9,10,11,0,1,2,3,8,9,10,11);
@ -2148,15 +2106,10 @@ inline void v_rshr_pack_store(unsigned* ptr, const v_uint64x2& a)
for (int i=0; i<2; ++i) { for (int i=0; i<2; ++i) {
ptr[i] = t_ptr[i]; ptr[i] = t_ptr[i];
} }
#else
fallback::v_uint64x2 _a(a);
fallback::v_rshr_pack_store<n>(ptr, _a);
#endif
} }
template<int n> template<int n>
inline void v_rshr_pack_store(int* ptr, const v_int64x2& a) inline void v_rshr_pack_store(int* ptr, const v_int64x2& a)
{ {
#ifdef __wasm_unimplemented_simd128__
v128_t delta = wasm_i64x2_splat(((int64)1 << (n-1))); v128_t delta = wasm_i64x2_splat(((int64)1 << (n-1)));
v128_t a1 = wasm_i64x2_shr(wasm_i64x2_add(a.val, delta), n); v128_t a1 = wasm_i64x2_shr(wasm_i64x2_add(a.val, delta), n);
v128_t r = wasm_v8x16_shuffle(a1, a1, 0,1,2,3,8,9,10,11,0,1,2,3,8,9,10,11); v128_t r = wasm_v8x16_shuffle(a1, a1, 0,1,2,3,8,9,10,11,0,1,2,3,8,9,10,11);
@ -2165,10 +2118,6 @@ inline void v_rshr_pack_store(int* ptr, const v_int64x2& a)
for (int i=0; i<2; ++i) { for (int i=0; i<2; ++i) {
ptr[i] = t_ptr[i]; ptr[i] = t_ptr[i];
} }
#else
fallback::v_int64x2 _a(a);
fallback::v_rshr_pack_store<n>(ptr, _a);
#endif
} }
template<int n> template<int n>
inline void v_rshr_pack_u_store(uchar* ptr, const v_int16x8& a) inline void v_rshr_pack_u_store(uchar* ptr, const v_int16x8& a)
@ -2228,7 +2177,6 @@ inline v_uint8x16 v_pack_b(const v_uint64x2& a, const v_uint64x2& b, const v_uin
const v_uint64x2& d, const v_uint64x2& e, const v_uint64x2& f, const v_uint64x2& d, const v_uint64x2& e, const v_uint64x2& f,
const v_uint64x2& g, const v_uint64x2& h) const v_uint64x2& g, const v_uint64x2& h)
{ {
#ifdef __wasm_unimplemented_simd128__
v128_t maxval = wasm_i32x4_splat(255); v128_t maxval = wasm_i32x4_splat(255);
v128_t a1 = wasm_v128_bitselect(maxval, a.val, ((__u64x2)(a.val) > (__u64x2)maxval)); v128_t a1 = wasm_v128_bitselect(maxval, a.val, ((__u64x2)(a.val) > (__u64x2)maxval));
v128_t b1 = wasm_v128_bitselect(maxval, b.val, ((__u64x2)(b.val) > (__u64x2)maxval)); v128_t b1 = wasm_v128_bitselect(maxval, b.val, ((__u64x2)(b.val) > (__u64x2)maxval));
@ -2245,10 +2193,6 @@ inline v_uint8x16 v_pack_b(const v_uint64x2& a, const v_uint64x2& b, const v_uin
v128_t abcd = wasm_v8x16_shuffle(ab, cd, 0,1,2,3,16,17,18,19,0,1,2,3,16,17,18,19); v128_t abcd = wasm_v8x16_shuffle(ab, cd, 0,1,2,3,16,17,18,19,0,1,2,3,16,17,18,19);
v128_t efgh = wasm_v8x16_shuffle(ef, gh, 0,1,2,3,16,17,18,19,0,1,2,3,16,17,18,19); v128_t efgh = wasm_v8x16_shuffle(ef, gh, 0,1,2,3,16,17,18,19,0,1,2,3,16,17,18,19);
return v_uint8x16(wasm_v8x16_shuffle(abcd, efgh, 0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23)); return v_uint8x16(wasm_v8x16_shuffle(abcd, efgh, 0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23));
#else
fallback::v_uint64x2 a_(a), b_(b), c_(c), d_(d), e_(e), f_(f), g_(g), h_(h);
return fallback::v_pack_b(a_, b_, c_, d_, e_, f_, g_, h_);
#endif
} }
inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0, inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0,
@ -2310,8 +2254,6 @@ OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_float32x4, wasm_f32x4_add)
OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_float32x4, wasm_f32x4_sub) OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_float32x4, wasm_f32x4_sub)
OPENCV_HAL_IMPL_WASM_BIN_OP(*, v_float32x4, wasm_f32x4_mul) OPENCV_HAL_IMPL_WASM_BIN_OP(*, v_float32x4, wasm_f32x4_mul)
OPENCV_HAL_IMPL_WASM_BIN_OP(/, v_float32x4, wasm_f32x4_div) OPENCV_HAL_IMPL_WASM_BIN_OP(/, v_float32x4, wasm_f32x4_div)
#ifdef __wasm_unimplemented_simd128__
OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_uint64x2, wasm_i64x2_add) OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_uint64x2, wasm_i64x2_add)
OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_uint64x2, wasm_i64x2_sub) OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_uint64x2, wasm_i64x2_sub)
OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_int64x2, wasm_i64x2_add) OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_int64x2, wasm_i64x2_add)
@ -2320,30 +2262,6 @@ OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_float64x2, wasm_f64x2_add)
OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_float64x2, wasm_f64x2_sub) OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_float64x2, wasm_f64x2_sub)
OPENCV_HAL_IMPL_WASM_BIN_OP(*, v_float64x2, wasm_f64x2_mul) OPENCV_HAL_IMPL_WASM_BIN_OP(*, v_float64x2, wasm_f64x2_mul)
OPENCV_HAL_IMPL_WASM_BIN_OP(/, v_float64x2, wasm_f64x2_div) OPENCV_HAL_IMPL_WASM_BIN_OP(/, v_float64x2, wasm_f64x2_div)
#else
#define OPENCV_HAL_IMPL_FALLBACK_BIN_OP(bin_op, _Tpvec) \
inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \
{ \
fallback::_Tpvec a_(a), b_(b); \
return _Tpvec((a_) bin_op (b_)); \
} \
inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \
{ \
fallback::_Tpvec a_(a), b_(b); \
a_ bin_op##= b_; \
a = _Tpvec(a_); \
return a; \
}
OPENCV_HAL_IMPL_FALLBACK_BIN_OP(+, v_uint64x2)
OPENCV_HAL_IMPL_FALLBACK_BIN_OP(-, v_uint64x2)
OPENCV_HAL_IMPL_FALLBACK_BIN_OP(+, v_int64x2)
OPENCV_HAL_IMPL_FALLBACK_BIN_OP(-, v_int64x2)
OPENCV_HAL_IMPL_FALLBACK_BIN_OP(+, v_float64x2)
OPENCV_HAL_IMPL_FALLBACK_BIN_OP(-, v_float64x2)
OPENCV_HAL_IMPL_FALLBACK_BIN_OP(*, v_float64x2)
OPENCV_HAL_IMPL_FALLBACK_BIN_OP(/, v_float64x2)
#endif
// saturating multiply 8-bit, 16-bit // saturating multiply 8-bit, 16-bit
#define OPENCV_HAL_IMPL_WASM_MUL_SAT(_Tpvec, _Tpwvec) \ #define OPENCV_HAL_IMPL_WASM_MUL_SAT(_Tpvec, _Tpwvec) \
@ -2405,19 +2323,11 @@ inline void v_mul_expand(const v_uint16x8& a, const v_uint16x8& b,
inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b,
v_uint64x2& c, v_uint64x2& d) v_uint64x2& c, v_uint64x2& d)
{ {
#ifdef __wasm_unimplemented_simd128__
v_uint64x2 a0, a1, b0, b1; v_uint64x2 a0, a1, b0, b1;
v_expand(a, a0, a1); v_expand(a, a0, a1);
v_expand(b, b0, b1); v_expand(b, b0, b1);
c.val = ((__u64x2)(a0.val) * (__u64x2)(b0.val)); c.val = ((__u64x2)(a0.val) * (__u64x2)(b0.val));
d.val = ((__u64x2)(a1.val) * (__u64x2)(b1.val)); d.val = ((__u64x2)(a1.val) * (__u64x2)(b1.val));
#else
fallback::v_uint32x4 a_(a), b_(b);
fallback::v_uint64x2 c_, d_;
fallback::v_mul_expand(a_, b_, c_, d_);
c = v_uint64x2(c_);
d = v_uint64x2(d_);
#endif
} }
inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b)
@ -2457,7 +2367,6 @@ inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b, const v_int32
inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b) inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b)
{ {
#ifdef __wasm_unimplemented_simd128__
v128_t a0 = wasm_i64x2_shr(wasm_i64x2_shl(a.val, 32), 32); v128_t a0 = wasm_i64x2_shr(wasm_i64x2_shl(a.val, 32), 32);
v128_t a1 = wasm_i64x2_shr(a.val, 32); v128_t a1 = wasm_i64x2_shr(a.val, 32);
v128_t b0 = wasm_i64x2_shr(wasm_i64x2_shl(b.val, 32), 32); v128_t b0 = wasm_i64x2_shr(wasm_i64x2_shl(b.val, 32), 32);
@ -2465,22 +2374,10 @@ inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b)
v128_t c = (v128_t)((__i64x2)a0 * (__i64x2)b0); v128_t c = (v128_t)((__i64x2)a0 * (__i64x2)b0);
v128_t d = (v128_t)((__i64x2)a1 * (__i64x2)b1); v128_t d = (v128_t)((__i64x2)a1 * (__i64x2)b1);
return v_int64x2(wasm_i64x2_add(c, d)); return v_int64x2(wasm_i64x2_add(c, d));
#else
fallback::v_int32x4 a_(a);
fallback::v_int32x4 b_(b);
return fallback::v_dotprod(a_, b_);
#endif
} }
inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c)
{ {
#ifdef __wasm_unimplemented_simd128__
return v_dotprod(a, b) + c; return v_dotprod(a, b) + c;
#else
fallback::v_int32x4 a_(a);
fallback::v_int32x4 b_(b);
fallback::v_int64x2 c_(c);
return fallback::v_dotprod(a_, b_, c_);
#endif
} }
// 8 >> 32 // 8 >> 32
@ -2515,32 +2412,32 @@ inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b, const
// 16 >> 64 // 16 >> 64
inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b) inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b)
{ {
fallback::v_uint16x8 a_(a); v128_t a0 = wasm_u32x4_shr(wasm_i32x4_shl(a.val, 16), 16);
fallback::v_uint16x8 b_(b); v128_t a1 = wasm_u32x4_shr(a.val, 16);
return fallback::v_dotprod_expand(a_, b_); v128_t b0 = wasm_u32x4_shr(wasm_i32x4_shl(b.val, 16), 16);
v128_t b1 = wasm_u32x4_shr(b.val, 16);
return v_uint64x2((
v_dotprod(v_int32x4(a0), v_int32x4(b0)) +
v_dotprod(v_int32x4(a1), v_int32x4(b1))).val
);
} }
inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c) inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c)
{ { return v_dotprod_expand(a, b) + c; }
fallback::v_uint16x8 a_(a);
fallback::v_uint16x8 b_(b);
fallback::v_uint64x2 c_(c);
return fallback::v_dotprod_expand(a_, b_, c_);
}
inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b) inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b)
{ {
fallback::v_int16x8 a_(a); v128_t a0 = wasm_i32x4_shr(wasm_i32x4_shl(a.val, 16), 16);
fallback::v_int16x8 b_(b); v128_t a1 = wasm_i32x4_shr(a.val, 16);
return fallback::v_dotprod_expand(a_, b_); v128_t b0 = wasm_i32x4_shr(wasm_i32x4_shl(b.val, 16), 16);
v128_t b1 = wasm_i32x4_shr(b.val, 16);
return v_int64x2((
v_dotprod(v_int32x4(a0), v_int32x4(b0)) +
v_dotprod(v_int32x4(a1), v_int32x4(b1)))
);
} }
inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b, const v_int64x2& c) inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b, const v_int64x2& c)
{ { return v_dotprod_expand(a, b) + c; }
fallback::v_int16x8 a_(a);
fallback::v_int16x8 b_(b);
fallback::v_int64x2 c_(c);
return fallback::v_dotprod_expand(a_, b_, c_);
}
// 32 >> 64f // 32 >> 64f
inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b) inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b)
@ -2610,44 +2507,24 @@ OPENCV_HAL_IMPL_WASM_LOGIC_OP(v_float64x2)
inline v_float32x4 v_sqrt(const v_float32x4& x) inline v_float32x4 v_sqrt(const v_float32x4& x)
{ {
#ifdef __wasm_unimplemented_simd128__
return v_float32x4(wasm_f32x4_sqrt(x.val)); return v_float32x4(wasm_f32x4_sqrt(x.val));
#else
fallback::v_float32x4 x_(x);
return fallback::v_sqrt(x_);
#endif
} }
inline v_float32x4 v_invsqrt(const v_float32x4& x) inline v_float32x4 v_invsqrt(const v_float32x4& x)
{ {
#ifdef __wasm_unimplemented_simd128__
const v128_t _1_0 = wasm_f32x4_splat(1.0); const v128_t _1_0 = wasm_f32x4_splat(1.0);
return v_float32x4(wasm_f32x4_div(_1_0, wasm_f32x4_sqrt(x.val))); return v_float32x4(wasm_f32x4_div(_1_0, wasm_f32x4_sqrt(x.val)));
#else
fallback::v_float32x4 x_(x);
return fallback::v_invsqrt(x_);
#endif
} }
inline v_float64x2 v_sqrt(const v_float64x2& x) inline v_float64x2 v_sqrt(const v_float64x2& x)
{ {
#ifdef __wasm_unimplemented_simd128__
return v_float64x2(wasm_f64x2_sqrt(x.val)); return v_float64x2(wasm_f64x2_sqrt(x.val));
#else
fallback::v_float64x2 x_(x);
return fallback::v_sqrt(x_);
#endif
} }
inline v_float64x2 v_invsqrt(const v_float64x2& x) inline v_float64x2 v_invsqrt(const v_float64x2& x)
{ {
#ifdef __wasm_unimplemented_simd128__
const v128_t _1_0 = wasm_f64x2_splat(1.0); const v128_t _1_0 = wasm_f64x2_splat(1.0);
return v_float64x2(wasm_f64x2_div(_1_0, wasm_f64x2_sqrt(x.val))); return v_float64x2(wasm_f64x2_div(_1_0, wasm_f64x2_sqrt(x.val)));
#else
fallback::v_float64x2 x_(x);
return fallback::v_invsqrt(x_);
#endif
} }
#define OPENCV_HAL_IMPL_WASM_ABS_INT_FUNC(_Tpuvec, _Tpsvec, suffix, zsuffix, shiftWidth) \ #define OPENCV_HAL_IMPL_WASM_ABS_INT_FUNC(_Tpuvec, _Tpsvec, suffix, zsuffix, shiftWidth) \
@ -2666,12 +2543,7 @@ inline v_float32x4 v_abs(const v_float32x4& x)
{ return v_float32x4(wasm_f32x4_abs(x.val)); } { return v_float32x4(wasm_f32x4_abs(x.val)); }
inline v_float64x2 v_abs(const v_float64x2& x) inline v_float64x2 v_abs(const v_float64x2& x)
{ {
#ifdef __wasm_unimplemented_simd128__
return v_float64x2(wasm_f64x2_abs(x.val)); return v_float64x2(wasm_f64x2_abs(x.val));
#else
fallback::v_float64x2 x_(x);
return fallback::v_abs(x_);
#endif
} }
// TODO: exp, log, sin, cos // TODO: exp, log, sin, cos
@ -2684,21 +2556,8 @@ inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \
OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_float32x4, v_min, wasm_f32x4_min) OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_float32x4, v_min, wasm_f32x4_min)
OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_float32x4, v_max, wasm_f32x4_max) OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_float32x4, v_max, wasm_f32x4_max)
#ifdef __wasm_unimplemented_simd128__
OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_float64x2, v_min, wasm_f64x2_min) OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_float64x2, v_min, wasm_f64x2_min)
OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_float64x2, v_max, wasm_f64x2_max) OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_float64x2, v_max, wasm_f64x2_max)
#else
#define OPENCV_HAL_IMPL_WASM_MINMAX_64f_FUNC(func) \
inline v_float64x2 func(const v_float64x2& a, const v_float64x2& b) \
{ \
fallback::v_float64x2 a_(a), b_(b); \
return fallback::func(a_, b_); \
}
OPENCV_HAL_IMPL_WASM_MINMAX_64f_FUNC(v_min)
OPENCV_HAL_IMPL_WASM_MINMAX_64f_FUNC(v_max)
#endif
#define OPENCV_HAL_IMPL_WASM_MINMAX_S_INIT_FUNC(_Tpvec, suffix) \ #define OPENCV_HAL_IMPL_WASM_MINMAX_S_INIT_FUNC(_Tpvec, suffix) \
inline _Tpvec v_min(const _Tpvec& a, const _Tpvec& b) \ inline _Tpvec v_min(const _Tpvec& a, const _Tpvec& b) \
@ -2753,24 +2612,7 @@ OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_int16x8, i16x8, i16x8)
OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_uint32x4, u32x4, i32x4) OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_uint32x4, u32x4, i32x4)
OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_int32x4, i32x4, i32x4) OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_int32x4, i32x4, i32x4)
OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_float32x4, f32x4, f32x4) OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_float32x4, f32x4, f32x4)
#ifdef __wasm_unimplemented_simd128__
OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_float64x2, f64x2, f64x2) OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_float64x2, f64x2, f64x2)
#else
#define OPENCV_HAL_IMPL_INIT_FALLBACK_CMP_OP(_Tpvec, bin_op) \
inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \
{ \
fallback::_Tpvec a_(a), b_(b); \
return _Tpvec((a_) bin_op (b_));\
} \
OPENCV_HAL_IMPL_INIT_FALLBACK_CMP_OP(v_float64x2, ==)
OPENCV_HAL_IMPL_INIT_FALLBACK_CMP_OP(v_float64x2, !=)
OPENCV_HAL_IMPL_INIT_FALLBACK_CMP_OP(v_float64x2, <)
OPENCV_HAL_IMPL_INIT_FALLBACK_CMP_OP(v_float64x2, >)
OPENCV_HAL_IMPL_INIT_FALLBACK_CMP_OP(v_float64x2, <=)
OPENCV_HAL_IMPL_INIT_FALLBACK_CMP_OP(v_float64x2, >=)
#endif
#define OPENCV_HAL_IMPL_WASM_64BIT_CMP_OP(_Tpvec, cast) \ #define OPENCV_HAL_IMPL_WASM_64BIT_CMP_OP(_Tpvec, cast) \
inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \
@ -2789,14 +2631,9 @@ inline v_float32x4 v_not_nan(const v_float32x4& a)
} }
inline v_float64x2 v_not_nan(const v_float64x2& a) inline v_float64x2 v_not_nan(const v_float64x2& a)
{ {
#ifdef __wasm_unimplemented_simd128__
v128_t z = wasm_i64x2_splat(0x7fffffffffffffff); v128_t z = wasm_i64x2_splat(0x7fffffffffffffff);
v128_t t = wasm_i64x2_splat(0x7ff0000000000000); v128_t t = wasm_i64x2_splat(0x7ff0000000000000);
return v_float64x2((__u64x2)(wasm_v128_and(a.val, z)) < (__u64x2)t); return v_float64x2((__u64x2)(wasm_v128_and(a.val, z)) < (__u64x2)t);
#else
fallback::v_float64x2 a_(a);
return fallback::v_not_nan(a_);
#endif
} }
OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_uint8x16, v_add_wrap, wasm_i8x16_add) OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_uint8x16, v_add_wrap, wasm_i8x16_add)
@ -2877,32 +2714,30 @@ inline v_float32x4 v_absdiff(const v_float32x4& a, const v_float32x4& b)
} }
inline v_float64x2 v_absdiff(const v_float64x2& a, const v_float64x2& b) inline v_float64x2 v_absdiff(const v_float64x2& a, const v_float64x2& b)
{ {
#ifdef __wasm_unimplemented_simd128__
v128_t absmask_vec = wasm_u64x2_shr(wasm_i32x4_splat(-1), 1); v128_t absmask_vec = wasm_u64x2_shr(wasm_i32x4_splat(-1), 1);
return v_float64x2(wasm_v128_and(wasm_f64x2_sub(a.val, b.val), absmask_vec)); return v_float64x2(wasm_v128_and(wasm_f64x2_sub(a.val, b.val), absmask_vec));
#else
fallback::v_float64x2 a_(a), b_(b);
return fallback::v_absdiff(a_, b_);
#endif
} }
#define OPENCV_HAL_IMPL_WASM_MISC_FLT_OP(_Tpvec) \ #define OPENCV_HAL_IMPL_WASM_MISC_FLT_OP(_Tpvec, suffix) \
inline _Tpvec v_magnitude(const _Tpvec& a, const _Tpvec& b) \ inline _Tpvec v_magnitude(const _Tpvec& a, const _Tpvec& b) \
{ \ { \
fallback::_Tpvec a_(a), b_(b); \ v128_t a_Square = wasm_##suffix##_mul(a.val, a.val); \
return fallback::v_magnitude(a_, b_); \ v128_t b_Square = wasm_##suffix##_mul(b.val, b.val); \
return _Tpvec(wasm_##suffix##_sqrt(wasm_##suffix##_add(a_Square, b_Square))); \
} \ } \
inline _Tpvec v_sqr_magnitude(const _Tpvec& a, const _Tpvec& b) \ inline _Tpvec v_sqr_magnitude(const _Tpvec& a, const _Tpvec& b) \
{ \ { \
return v_fma(a, a, b*b); \ v128_t a_Square = wasm_##suffix##_mul(a.val, a.val); \
v128_t b_Square = wasm_##suffix##_mul(b.val, b.val); \
return _Tpvec(wasm_##suffix##_add(a_Square, b_Square)); \
} \ } \
inline _Tpvec v_muladd(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ inline _Tpvec v_muladd(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \
{ \ { \
return v_fma(a, b, c); \ return _Tpvec(wasm_##suffix##_add(wasm_##suffix##_mul(a.val, b.val), c.val)); \
} }
OPENCV_HAL_IMPL_WASM_MISC_FLT_OP(v_float32x4) OPENCV_HAL_IMPL_WASM_MISC_FLT_OP(v_float32x4, f32x4)
OPENCV_HAL_IMPL_WASM_MISC_FLT_OP(v_float64x2) OPENCV_HAL_IMPL_WASM_MISC_FLT_OP(v_float64x2, f64x2)
#define OPENCV_HAL_IMPL_WASM_SHIFT_OP(_Tpuvec, _Tpsvec, suffix, ssuffix) \ #define OPENCV_HAL_IMPL_WASM_SHIFT_OP(_Tpuvec, _Tpsvec, suffix, ssuffix) \
inline _Tpuvec operator << (const _Tpuvec& a, int imm) \ inline _Tpuvec operator << (const _Tpuvec& a, int imm) \
@ -2945,37 +2780,7 @@ inline _Tpsvec v_shr(const _Tpsvec& a) \
OPENCV_HAL_IMPL_WASM_SHIFT_OP(v_uint8x16, v_int8x16, i8x16, u8x16) OPENCV_HAL_IMPL_WASM_SHIFT_OP(v_uint8x16, v_int8x16, i8x16, u8x16)
OPENCV_HAL_IMPL_WASM_SHIFT_OP(v_uint16x8, v_int16x8, i16x8, u16x8) OPENCV_HAL_IMPL_WASM_SHIFT_OP(v_uint16x8, v_int16x8, i16x8, u16x8)
OPENCV_HAL_IMPL_WASM_SHIFT_OP(v_uint32x4, v_int32x4, i32x4, u32x4) OPENCV_HAL_IMPL_WASM_SHIFT_OP(v_uint32x4, v_int32x4, i32x4, u32x4)
#ifdef __wasm_unimplemented_simd128__
OPENCV_HAL_IMPL_WASM_SHIFT_OP(v_uint64x2, v_int64x2, i64x2, u64x2) OPENCV_HAL_IMPL_WASM_SHIFT_OP(v_uint64x2, v_int64x2, i64x2, u64x2)
#else
#define OPENCV_HAL_IMPL_FALLBACK_SHIFT_OP(_Tpvec) \
inline _Tpvec operator << (const _Tpvec& a, int imm) \
{ \
fallback::_Tpvec a_(a); \
return a_ << imm; \
} \
inline _Tpvec operator >> (const _Tpvec& a, int imm) \
{ \
fallback::_Tpvec a_(a); \
return a_ >> imm; \
} \
template<int imm> \
inline _Tpvec v_shl(const _Tpvec& a) \
{ \
fallback::_Tpvec a_(a); \
return fallback::v_shl<imm>(a_); \
} \
template<int imm> \
inline _Tpvec v_shr(const _Tpvec& a) \
{ \
fallback::_Tpvec a_(a); \
return fallback::v_shr<imm>(a_); \
} \
OPENCV_HAL_IMPL_FALLBACK_SHIFT_OP(v_uint64x2)
OPENCV_HAL_IMPL_FALLBACK_SHIFT_OP(v_int64x2)
#endif
namespace hal_wasm_internal namespace hal_wasm_internal
{ {
@ -3180,9 +2985,18 @@ OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_uint8x16, unsigned)
OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_int8x16, int) OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_int8x16, int)
OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_uint16x8, unsigned) OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_uint16x8, unsigned)
OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_int16x8, int) OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_int16x8, int)
OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_uint64x2, uint64)
OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_int64x2, int64)
OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_float64x2, double) #define OPENCV_HAL_IMPL_WASM_REDUCE_OP_2_SUM(_Tpvec, scalartype, regtype, suffix, esuffix) \
inline scalartype v_reduce_sum(const _Tpvec& a) \
{ \
regtype val = a.val; \
val = wasm_##suffix##_add(val, wasm_v8x16_shuffle(val, val, 8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7)); \
return (scalartype)wasm_##esuffix##_extract_lane(val, 0); \
}
OPENCV_HAL_IMPL_WASM_REDUCE_OP_2_SUM(v_uint64x2, uint64, v128_t, i64x2, i64x2)
OPENCV_HAL_IMPL_WASM_REDUCE_OP_2_SUM(v_int64x2, int64, v128_t, i64x2, i64x2)
OPENCV_HAL_IMPL_WASM_REDUCE_OP_2_SUM(v_float64x2, double, v128_t, f64x2,f64x2)
inline v_float32x4 v_reduce_sum4(const v_float32x4& a, const v_float32x4& b, inline v_float32x4 v_reduce_sum4(const v_float32x4& a, const v_float32x4& b,
const v_float32x4& c, const v_float32x4& d) const v_float32x4& c, const v_float32x4& d)
@ -3318,30 +3132,27 @@ OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_int16x8, i16x8, short)
OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_uint32x4, i32x4, int) OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_uint32x4, i32x4, int)
OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_int32x4, i32x4, int) OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_int32x4, i32x4, int)
OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_float32x4, i32x4, float) OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_float32x4, i32x4, float)
OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_float64x2, f64x2, double)
#define OPENCV_HAL_IMPL_WASM_CHECK_ALL_ANY(_Tpvec, suffix, esuffix) \
inline bool v_check_all(const _Tpvec& a) \
{ \
v128_t masked = v_reinterpret_as_##esuffix(a).val; \
masked = wasm_i32x4_replace_lane(masked, 0, 0xffffffff); \
masked = wasm_i32x4_replace_lane(masked, 2, 0xffffffff); \
return wasm_i8x16_all_true(wasm_##suffix##_lt(masked, wasm_##suffix##_splat(0))); \
} \
inline bool v_check_any(const _Tpvec& a) \
{ \
v128_t masked = v_reinterpret_as_##esuffix(a).val; \
masked = wasm_i32x4_replace_lane(masked, 0, 0x0); \
masked = wasm_i32x4_replace_lane(masked, 2, 0x0); \
return wasm_i8x16_any_true(wasm_##suffix##_lt(masked, wasm_##suffix##_splat(0))); \
} \
OPENCV_HAL_IMPL_WASM_CHECK_ALL_ANY(v_int64x2, i32x4, s32)
OPENCV_HAL_IMPL_WASM_CHECK_ALL_ANY(v_uint64x2, i32x4, u32)
inline int v_signmask(const v_float64x2& a)
{
fallback::v_float64x2 a_(a);
return fallback::v_signmask(a_);
}
inline bool v_check_all(const v_float64x2& a)
{
#ifdef __wasm_unimplemented_simd128__
return wasm_i8x16_all_true((__i64x2)(a.val) < (__i64x2)(wasm_i64x2_splat(0)));
#else
fallback::v_float64x2 a_(a);
return fallback::v_check_all(a_);
#endif
}
inline bool v_check_any(const v_float64x2& a)
{
#ifdef __wasm_unimplemented_simd128__
return wasm_i8x16_any_true((__i64x2)(a.val) < (__i64x2)(wasm_i64x2_splat(0)));;
#else
fallback::v_float64x2 a_(a);
return fallback::v_check_any(a_);
#endif
}
inline int v_scan_forward(const v_int8x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))); } inline int v_scan_forward(const v_int8x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))); }
inline int v_scan_forward(const v_uint8x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))); } inline int v_scan_forward(const v_uint8x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))); }
@ -3366,8 +3177,8 @@ OPENCV_HAL_IMPL_WASM_SELECT(v_uint16x8)
OPENCV_HAL_IMPL_WASM_SELECT(v_int16x8) OPENCV_HAL_IMPL_WASM_SELECT(v_int16x8)
OPENCV_HAL_IMPL_WASM_SELECT(v_uint32x4) OPENCV_HAL_IMPL_WASM_SELECT(v_uint32x4)
OPENCV_HAL_IMPL_WASM_SELECT(v_int32x4) OPENCV_HAL_IMPL_WASM_SELECT(v_int32x4)
// OPENCV_HAL_IMPL_WASM_SELECT(v_uint64x2) OPENCV_HAL_IMPL_WASM_SELECT(v_uint64x2)
// OPENCV_HAL_IMPL_WASM_SELECT(v_int64x2) OPENCV_HAL_IMPL_WASM_SELECT(v_int64x2)
OPENCV_HAL_IMPL_WASM_SELECT(v_float32x4) OPENCV_HAL_IMPL_WASM_SELECT(v_float32x4)
OPENCV_HAL_IMPL_WASM_SELECT(v_float64x2) OPENCV_HAL_IMPL_WASM_SELECT(v_float64x2)

@ -225,6 +225,14 @@ It also demonstrates how to save multiple images in a TIFF file:
CV_EXPORTS_W bool imwrite( const String& filename, InputArray img, CV_EXPORTS_W bool imwrite( const String& filename, InputArray img,
const std::vector<int>& params = std::vector<int>()); const std::vector<int>& params = std::vector<int>());
/// @overload multi-image overload for bindings
CV_WRAP static inline
bool imwritemulti(const String& filename, InputArrayOfArrays img,
const std::vector<int>& params = std::vector<int>())
{
return imwrite(filename, img, params);
}
/** @brief Reads an image from a buffer in memory. /** @brief Reads an image from a buffer in memory.
The function imdecode reads an image from the specified buffer in the memory. If the buffer is too short or The function imdecode reads an image from the specified buffer in the memory. If the buffer is too short or

@ -3371,7 +3371,7 @@ but also identifies the nearest connected component consisting of zero pixels
(labelType==#DIST_LABEL_CCOMP) or the nearest zero pixel (labelType==#DIST_LABEL_PIXEL). Index of the (labelType==#DIST_LABEL_CCOMP) or the nearest zero pixel (labelType==#DIST_LABEL_PIXEL). Index of the
component/pixel is stored in `labels(x, y)`. When labelType==#DIST_LABEL_CCOMP, the function component/pixel is stored in `labels(x, y)`. When labelType==#DIST_LABEL_CCOMP, the function
automatically finds connected components of zero pixels in the input image and marks them with automatically finds connected components of zero pixels in the input image and marks them with
distinct labels. When labelType==#DIST_LABEL_CCOMP, the function scans through the input image and distinct labels. When labelType==#DIST_LABEL_PIXEL, the function scans through the input image and
marks all the zero pixels with distinct labels. marks all the zero pixels with distinct labels.
In this mode, the complexity is still linear. That is, the function provides a very fast way to In this mode, the complexity is still linear. That is, the function provides a very fast way to

@ -1566,9 +1566,9 @@ public:
int x = 1; int x = 1;
if (start_with_green) if (start_with_green)
{ {
D[blue<<1] = (S[-sstep] + S[sstep]) >> 1; D[blue<<1] = (S[-sstep] + S[sstep] + 1) >> 1;
D[1] = S[0]; D[1] = S[0];
D[2-(blue<<1)] = (S[-1] + S[1]) >> 1; D[2-(blue<<1)] = (S[-1] + S[1] + 1) >> 1;
D += dcn; D += dcn;
++S; ++S;
++x; ++x;
@ -1584,7 +1584,7 @@ public:
{ {
D[0] = S[0]; D[0] = S[0];
D[1] = (std::abs(S[-1] - S[1]) > std::abs(S[sstep] - S[-sstep]) ? (S[sstep] + S[-sstep] + 1) : (S[-1] + S[1] + 1)) >> 1; D[1] = (std::abs(S[-1] - S[1]) > std::abs(S[sstep] - S[-sstep]) ? (S[sstep] + S[-sstep] + 1) : (S[-1] + S[1] + 1)) >> 1;
D[2] = (S[-sstep-1] + S[-sstep+1] + S[sstep-1] + S[sstep+1]) >> 2; D[2] = (S[-sstep-1] + S[-sstep+1] + S[sstep-1] + S[sstep+1] + 2) >> 2;
D[3] = (S[0] + S[2] + 1) >> 1; D[3] = (S[0] + S[2] + 1) >> 1;
D[4] = S[1]; D[4] = S[1];

@ -180,3 +180,22 @@ endforeach()
add_custom_target(${PROJECT_NAME}_perf ALL add_custom_target(${PROJECT_NAME}_perf ALL
DEPENDS ${OCV_JS_PATH} ${opencv_perf_js_file_deps}) DEPENDS ${OCV_JS_PATH} ${opencv_perf_js_file_deps})
#loader
set(opencv_loader_js_bin_dir "${EXECUTABLE_OUTPUT_PATH}")
set(loader_dir ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(opencv_loader_js_file_deps "")
# make sure the build directory exists
file(MAKE_DIRECTORY "${opencv_loader_js_bin_dir}")
add_custom_command(
TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${loader_dir}/loader.js
${opencv_loader_js_bin_dir}/loader.js)
list(APPEND opencv_loader_js_file_deps "${loader_dir}/loader.js" "${opencv_loader_js_bin_dir}/loader.js")
add_custom_target(${PROJECT_NAME}_loader ALL
DEPENDS ${OCV_JS_PATH} ${opencv_loader_js_file_deps})

@ -2,17 +2,28 @@ if (typeof window === 'undefined') {
var cv = require("../opencv"); var cv = require("../opencv");
} }
const cvSize = { let gCvSize;
function getCvSize() {
if (gCvSize === undefined) {
gCvSize = {
szODD: new cv.Size(127, 61), szODD: new cv.Size(127, 61),
szQVGA: new cv.Size(320, 240), szQVGA: new cv.Size(320, 240),
szVGA: new cv.Size(640, 480), szVGA: new cv.Size(640, 480),
szSVGA: new cv.Size(800, 600),
szqHD: new cv.Size(960, 540), szqHD: new cv.Size(960, 540),
szXGA: new cv.Size(1024, 768),
sz720p: new cv.Size(1280, 720), sz720p: new cv.Size(1280, 720),
szSXGA: new cv.Size(1280, 1024),
sz1080p: new cv.Size(1920, 1080), sz1080p: new cv.Size(1920, 1080),
sz130x60: new cv.Size(130, 60), sz130x60: new cv.Size(130, 60),
sz213x120: new cv.Size(120 * 1280 / 720, 120), sz213x120: new cv.Size(120 * 1280 / 720, 120),
};
}
return gCvSize;
} }
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
exports.cvSize = cvSize; exports.getCvSize = getCvSize;
} }

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenCV.js Performance Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
font-size: 13px;
}
.top-margin {
margin-top:10px;
}
h1, h4 {
margin: 24px 0 0;
}
h1 {
font-size: 2.0em;
}
h4 {
font-size: 1.2em;
}
pre {
font-family: 'Consolas', 'Monaco', monospace, serif;
font-size: 12px;
tab-size: 2;
}
input[type=checkbox] {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container" id="container">
<div class="row">
<div class="col-12">
<h1>OpenCV.js Performance Test</h1>
<div>
<h4>Functions for 64-bit Perf</h4>
<h7>CountnonZero, Mat::dot, Split, Merge</h7>
</div>
<div>
<h4>Mat Shape</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (1000x1000)
</div>
<div class='row labels-wrapper' id='labelitem'></div>
<div class="row top-margin">
</div>
<div>
<button type="button" id="runButton" class="btn btn-primary disabled" disabled="disabled">Loading</button>
(It will take several minutes)</div>
<div class="row top-margin">
</div>
<div>
<pre id="log"></pre>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js"></script>
<script src="../opencv.js" type="text/javascript"></script>
<script src="./perf_64bits.js"></script>
</body>
</html>

@ -0,0 +1,180 @@
const isNodeJs = (typeof window) === 'undefined'? true : false;
if (isNodeJs) {
var Benchmark = require('benchmark');
var cv = require('../../opencv');
} else {
var paramsElement = document.getElementById('params');
var runButton = document.getElementById('runButton');
var logElement = document.getElementById('log');
}
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
} else {
runButton.removeAttribute('disabled');
runButton.setAttribute('class', 'btn btn-primary');
runButton.innerHTML = 'Run';
}
let totalCaseNum, currentCaseId;
function addCountNonZeroCase(suite) {
suite.add('countNonZero', function() {
cv.countNonZero(mat);
}, {
'setup': function() {
let size = this.params.size;
let mat = cv.Mat.eye(size[0], size[1], cv.CV_64F);
}, 'teardown': function() {
mat.delete();
}
});
}
function addMatDotCase(suite) {
suite.add('Mat::dot', function() {
mat.dot(matT);
}, {
'setup': function() {
let size = this.params.size;
let mat = cv.Mat.ones(size[0], size[1], cv.CV_64FC1);
let matT = mat.t();
}, 'teardown': function() {
mat.delete();
matT.delete();
}
});
}
function addSplitCase(suite) {
suite.add('Split', function() {
cv.split(mat, planes);
}, {
'setup': function() {
let size = this.params.size;
let mat = cv.Mat.ones(size[0], size[1], cv.CV_64FC3);
let planes = new cv.MatVector();
}, 'teardown': function() {
mat.delete();
planes.delete();
}
});
}
function addMergeCase(suite) {
suite.add('Merge', function() {
cv.merge(planes, mat);
}, {
'setup': function() {
let size = this.params.size;
let mat = new cv.Mat();
let mat1 = cv.Mat.ones(size[0], size[1], cv.CV_64FC3);
let planes = new cv.MatVector();
cv.split(mat1, planes);
}, 'teardown': function() {
mat.delete();
mat1.delete();
planes.delete();
}
});
}
function setInitParams(suite, sizeArray) {
for( let i =0; i < suite.length; i++) {
suite[i].params = {
size: sizeArray
};
}
}
function log(message) {
console.log(message);
if (!isNodeJs) {
logElement.innerHTML += `\n${'\t' + message}`;
}
}
function setBenchmarkSuite(suite) {
suite
// add listeners
.on('cycle', function(event) {
++currentCaseId;
let size = event.target.params.size;
log(`=== ${event.target.name} ${currentCaseId} ===`);
log(`params: (${parseInt(size[0])}x${parseInt(size[1])})`);
log('elapsed time:' +String(event.target.times.elapsed*1000)+' ms');
log('mean time:' +String(event.target.stats.mean*1000)+' ms');
log('stddev time:' +String(event.target.stats.deviation*1000)+' ms');
log(String(event.target));
})
.on('error', function(event) { log(`test case ${event.target.name} failed`); })
.on('complete', function(event) {
log(`\n ###################################`)
log(`Finished testing ${event.currentTarget.length} cases \n`);
if (!isNodeJs) {
runButton.removeAttribute('disabled');
runButton.setAttribute('class', 'btn btn-primary');
runButton.innerHTML = 'Run';
}
});
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
var sizeArray;
totalCaseNum = 4;
currentCaseId = 0;
if (/\([0-9]+x[0-9]+\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+\)/g)[0];
let sizeStrs = (params.match(/[0-9]+/g) || []).slice(0, 2).toString().split(",");
sizeArray = sizeStrs.map(Number);
} else {
log("no getting invalid params, run all the cases with Mat of shape (1000 x 1000)");
sizeArray = [1000, 1000];
}
addCountNonZeroCase(suite);
addMatDotCase(suite);
addSplitCase(suite);
addMergeCase(suite);
setInitParams(suite, sizeArray)
setBenchmarkSuite(suite);
log(`Running ${totalCaseNum} tests from 64-bit intrinsics`);
suite.run({ 'async': true }); // run the benchmark
}
// set test filter params
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+\)/g)[0];
}
genBenchmarkCase(paramsContent);
} else {
runButton.onclick = function() {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
runButton.setAttribute("disabled", "disabled");
runButton.setAttribute('class', 'btn btn-primary disabled');
runButton.innerHTML = "Running";
}
}
}
};
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -16,14 +16,57 @@ var fillGradient = function(cv, img, delta=5) {
} }
} }
var smoothBorder = function(cv, img, color, delta=5) {
let ch = img.channels();
console.assert(!img.empty() && img.depth() == cv.CV_8U && ch <= 4);
let n = 100/delta;
let nR = Math.min(n, (img.rows+1)/2);
let nC = Math.min(n, (img.cols+1)/2);
let s = new cv.Scalar();
for (let r = 0; r < nR; r++) {
let k1 = r*delta/100.0, k2 = 1-k1;
for(let c = 0; c < img.cols; c++) {
let view = img.ptr(r, c);
for(let i = 0; i < ch; i++) s[i] = view[i];
for(let i = 0; i < ch; i++) view[i] = s[i]*k1 + color[i] * k2;
}
for(let c=0; c < img.cols; c++) {
let view = img.ptr(img.rows-r-1, c);
for(let i = 0; i < ch; i++) s[i] = view[i];
for(let i = 0; i < ch; i++) view[i] = s[i]*k1 + color[i] * k2;
}
}
for (let r = 0; r < img.rows; r++) {
for(let c = 0; c < nC; c++) {
let k1 = c*delta/100.0, k2 = 1-k1;
let view = img.ptr(r, c);
for(let i = 0; i < ch; i++) s[i] = view[i];
for(let i = 0; i < ch; i++) view[i] = s[i]*k1 + color[i] * k2;
}
for(let c = 0; c < n; c++) {
let k1 = c*delta/100.0, k2 = 1-k1;
let view = img.ptr(r, img.cols-c-1);
for(let i = 0; i < ch; i++) s[i] = view[i];
for(let i = 0; i < ch; i++) view[i] = s[i]*k1 + color[i] * k2;
}
}
}
var cvtStr2cvSize = function(strSize) { var cvtStr2cvSize = function(strSize) {
let size; let size;
let cvSize = getCvSize();
switch(strSize) { switch(strSize) {
case "127,61": size = cvSize.szODD;break; case "127,61": size = cvSize.szODD;break;
case '320,240': size = cvSize.szQVGA;break; case '320,240': size = cvSize.szQVGA;break;
case '640,480': size = cvSize.szVGA;break; case '640,480': size = cvSize.szVGA;break;
case '800,600': size = cvSize.szSVGA;break;
case '960,540': size = cvSize.szqHD;break; case '960,540': size = cvSize.szqHD;break;
case '1024,768': size = cvSize.szXGA;break;
case '1280,720': size = cvSize.sz720p;break; case '1280,720': size = cvSize.sz720p;break;
case '1280,1024': size = cvSize.szSXGA;break;
case '1920,1080': size = cvSize.sz1080p;break; case '1920,1080': size = cvSize.sz1080p;break;
case "130,60": size = cvSize.sz130x60;break; case "130,60": size = cvSize.sz130x60;break;
case '213,120': size = cvSize.sz213x120;break; case '213,120': size = cvSize.sz213x120;break;
@ -52,8 +95,209 @@ function permute (source, target) {
return result; return result;
} }
var constructMode = function (startStr, sChannel, dChannel) {
let modeList = []
for (let j in dChannel) {
modeList.push(startStr+sChannel+"2"+dChannel[j])
}
return modeList;
}
var enableButton = function () {
runButton.removeAttribute('disabled');
runButton.setAttribute('class', 'btn btn-primary');
runButton.innerHTML = 'Run';
}
var disableButton = function () {
runButton.setAttribute("disabled", "disabled");
runButton.setAttribute('class', 'btn btn-primary disabled');
runButton.innerHTML = "Running";
}
var log = function (message) {
console.log(message);
if (!isNodeJs) {
logElement.innerHTML += `\n${'\t' + message}`;
}
}
var addKernelCase = function (suite, params, type, kernelFunc) {
kernelFunc(suite, type);
let index = suite.length - 1;
suite[index].params = params;
}
function constructParamLog(params, kernel) {
let paramLog = '';
if (kernel == "cvtcolor") {
let mode = params.mode;
let size = params.size;
paramLog = `params: (${parseInt(size[0])}x${parseInt(size[1])}, ${mode})`;
} else if (kernel == "resize") {
let matType = params.matType;
let size1 = params.from;
let size2 = params.to;
paramLog = `params: (${matType},${parseInt(size1.width)}x${parseInt(size1.height)},`+
`${parseInt(size2.width)}x${parseInt(size2.height)})`;
} else if (kernel == "threshold") {
let matSize = params.matSize;
let matType = params.matType;
let threshType = params.threshType;
paramLog = `params: (${parseInt(matSize.width)}x${parseInt(matSize.height)},`+
`${matType},${threshType})`;
} else if (kernel == "sobel") {
let size = params.size;
let ddepth = params.ddepth;
let dxdy = params.dxdy;
let ksize = params.ksize;
let borderType = params.borderType;
paramLog = `params: (${parseInt(size[0])}x${parseInt(size[1])},`+
`${ddepth},${dxdy},${borderType}, ksize:${ksize})`;
} else if (kernel == "filter2d") {
let size = params.size;
let ksize = params.ksize;
let borderMode = params.borderMode;
paramLog = `params: (${parseInt(size.width)}x${parseInt(size.height)},`+
`${ksize},${borderMode})`;
} else if (kernel == "scharr") {
let size = params.size;
let ddepth = params.ddepth;
let dxdy = params.dxdy;
let borderType = params.borderType;
paramLog = `params: (${parseInt(size[0])}x${parseInt(size[1])},`+
`${ddepth},${dxdy},${borderType})`;
} else if (kernel == "gaussianBlur" || kernel == "blur") {
let size = params.size;
let matType = params.matType;
let borderType = params.borderType;
let ksize = params.ksize;
paramLog = `params: (${parseInt(size.width)}x${parseInt(size.height)},`+
`${matType},${borderType}, ksize: (${ksize}x${ksize}))`;
} else if (kernel == "medianBlur") {
let size = params.size;
let matType = params.matType;
let ksize = params.ksize;
paramLog = `params: (${parseInt(size.width)}x${parseInt(size.height)},`+
`${matType}, ksize: ${ksize})`;
} else if (kernel == "erode" || kernel == "dilate" || kernel == "pyrDown") {
let size = params.size;
let matType = params.matType;
paramLog = `params: (${parseInt(size.width)}x${parseInt(size.height)},`+
`${matType})`;
} else if (kernel == "remap") {
let size = params.size;
let matType = params.matType;
let mapType = params.mapType;
let interType = params.interType;
paramLog = `params: (${parseInt(size.width)}x${parseInt(size.height)},`+
`${matType}, ${mapType}, ${interType})`;
} else if (kernel == "warpAffine" || kernel == "warpPerspective") {
let size = params.size;
let interType = params.interType;
let borderMode = params.borderMode;
paramLog = `params: (${parseInt(size.width)}x${parseInt(size.height)},`+
`${interType}, ${borderMode})`;
}
return paramLog;
}
var setBenchmarkSuite = function (suite, kernel, currentCaseId) {
suite
// add listeners
.on('cycle', function(event) {
++currentCaseId;
let params = event.target.params;
paramLog = constructParamLog(params, kernel);
log(`=== ${event.target.name} ${currentCaseId} ===`);
log(paramLog);
log('elapsed time:' +String(event.target.times.elapsed*1000)+' ms');
log('mean time:' +String(event.target.stats.mean*1000)+' ms');
log('stddev time:' +String(event.target.stats.deviation*1000)+' ms');
log(String(event.target));
})
.on('error', function(event) { log(`test case ${event.target.name} failed`); })
.on('complete', function(event) {
log(`\n ###################################`)
log(`Finished testing ${event.currentTarget.length} cases \n`);
if (!isNodeJs) {
runButton.removeAttribute('disabled');
runButton.setAttribute('class', 'btn btn-primary');
runButton.innerHTML = 'Run';
}
});
}
var decodeParams2Case = function(paramContent, paramsList, combinations) {
let sizeString = (paramContent.match(/[0-9]+x[0-9]+/g) || []).toString();
let sizes = (sizeString.match(/[0-9]+/g) || []);
let paramSize = paramsList.length;
let paramObjs = []
let sizeCount = 0;
for (let i = 0; i < paramSize; i++) {
let param = paramsList[i];
let paramName = param.name;
let paramValue = param.value;
let paramReg = param.reg;
let paramIndex = param.index;
if(paramValue != "") {
paramObjs.push({name: paramName, value: paramValue, index: paramIndex});
} else if (paramName.startsWith('size')) {
let sizeStr = sizes.slice(sizeCount, sizeCount+2).toString();
paramValue = cvtStr2cvSize(sizeStr);
sizeCount += 2;
paramObjs.push({name: paramName, value: paramValue, index: paramIndex});
} else {
for (let index in paramReg) {
let reg = eval(paramReg[index]);
if ('loc' in param) {
paramValue = (paramContent.match(reg) || [])[param.loc].toString();
} else {
paramValue = (paramContent.match(reg) || []).toString();
}
if (paramValue != "") {
paramObjs.push({name: paramName, value: paramValue, index: paramIndex});
break;
}
}
}
}
let location = [];
for (let i = 0; i < combinations.length; ++i) {
let combination = combinations[i];
for (let j = 0; j < combination.length; ++j) {
if (judgeCombin(combination[j], paramObjs)) {
location.push([i,j]);
}
}
}
return location;
}
function judgeCombin(combination, paramObjs) {
for (let i =0; i < paramObjs.length; i++) {
if (paramObjs[i].value != combination[paramObjs[i].index]){
return false;
}
}
return true;
}
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
exports.enableButton = enableButton;
exports.disableButton = disableButton;
exports.fillGradient = fillGradient; exports.fillGradient = fillGradient;
exports.smoothBorder = smoothBorder;
exports.cvtStr2cvSize = cvtStr2cvSize; exports.cvtStr2cvSize = cvtStr2cvSize;
exports.combine = combine; exports.combine = combine;
exports.constructMode = constructMode;
exports.log = log;
exports.decodeParams2Case = decodeParams2Case;
exports.setBenchmarkSuite = setBenchmarkSuite;
exports.addKernelCase = addKernelCase;
} }

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenCV.js Performance Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
font-size: 13px;
}
.top-margin {
margin-top:10px;
}
h1, h4 {
margin: 24px 0 0;
}
h1 {
font-size: 2.0em;
}
h4 {
font-size: 1.2em;
}
pre {
font-family: 'Consolas', 'Monaco', monospace, serif;
font-size: 12px;
tab-size: 2;
}
input[type=checkbox] {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container" id="container">
<div class="row">
<div class="col-12">
<h1>OpenCV.js Performance Test</h1>
<div>
<h4>Modules</h4>
<h7>Image Processing</h7>
</div>
<div>
<h4>Kernels</h4>
<h7>Blur</h7>
</div>
<div>
<h4>Parameters Filter</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (1280x720, CV_8UC1, BORDER_REPLICATE)
</div>
<div class='row labels-wrapper' id='labelitem'></div>
<div class="row top-margin">
</div>
<div>
<button type="button" id="runButton" class="btn btn-primary disabled" disabled="disabled">Loading</button>
(It will take several minutes)</div>
<div class="row top-margin">
</div>
<div>
<pre id="log"></pre>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js"></script>
<script src="../../opencv.js" type="text/javascript"></script>
<script src="../base.js"></script>
<script src="../perf_helpfunc.js"></script>
<script src="./perf_blur.js"></script>
</body>
</html>

@ -0,0 +1,130 @@
const isNodeJs = (typeof window) === 'undefined'? true : false;
if (isNodeJs) {
var Benchmark = require('benchmark');
var cv = require('../../opencv');
var HelpFunc = require('../perf_helpfunc');
var Base = require('../base');
} else {
var paramsElement = document.getElementById('params');
var runButton = document.getElementById('runButton');
var logElement = document.getElementById('log');
}
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.getCvSize();
} else {
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
const BlurSize = [cvSize.szODD, cvSize.szQVGA, cvSize.szVGA, cvSize.sz720p];
const Blur5x16Size = [cvSize.szVGA, cvSize.sz720p];
const BlurType = ["CV_8UC1", "CV_8UC4", "CV_16UC1", "CV_16SC1", "CV_32FC1"];
const BlurType5x5 = ["CV_8UC1", "CV_8UC4", "CV_16UC1", "CV_16SC1", "CV_32FC1", "CV_32FC3"];
const BorderType3x3 = ["BORDER_REPLICATE", "BORDER_CONSTANT"];
const BorderTypeAll = ["BORDER_REPLICATE", "BORDER_CONSTANT", "BORDER_REFLECT", "BORDER_REFLECT101"];
const combiBlur3x3 = combine(BlurSize, BlurType, BorderType3x3);
const combiBlur16x16 = combine(Blur5x16Size, BlurType, BorderTypeAll);
const combiBlur5x5 = combine(Blur5x16Size, BlurType5x5, BorderTypeAll);
function addBlurCase(suite, type) {
suite.add('blur', function() {
cv.blur(src, dst, ksize, new cv.Point(-1,-1), borderType);
}, {
'setup': function() {
let size = this.params.size;
let matType = cv[this.params.matType];
let borderType = cv[this.params.borderType];
let ksizeNum = this.params.ksize;
let ksize = new cv.Size(ksizeNum, ksizeNum);
let src = new cv.Mat(size, matType);
let dst = new cv.Mat(size, matType);
},
'teardown': function() {
src.delete();
dst.delete();
}
});
}
function addBlurModeCase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let matType = combination[i][1];
let borderType = combination[i][2];
let ksizeArray = [3, 16, 5];
let params = {size: size, matType:matType, ksize: ksizeArray[type], borderType:borderType};
addKernelCase(suite, params, type, addBlurCase);
}
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*BORDER\_\w+\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*BORDER\_\w+\)/g)[0];
let paramObjs = [];
paramObjs.push({name:"size", value:"", reg:[""], index:0});
paramObjs.push({name:"matType", value:"", reg:["/CV\_[0-9]+[FSUfsu]C[0-9]/"], index:1});
paramObjs.push({name:"borderMode", value: "", reg:["/BORDER\_\\w+/"], index:2});
let locationList = decodeParams2Case(params, paramObjs,blurCombinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
addBlurModeCase(suite, [blurCombinations[first][second]], first);
}
} else {
log("no filter or getting invalid params, run all the cases");
addBlurModeCase(suite, combiBlur3x3, 0);
addBlurModeCase(suite, combiBlur16x16, 1);
addBlurModeCase(suite, combiBlur5x5, 2);
}
setBenchmarkSuite(suite, "blur", currentCaseId);
log(`Running ${totalCaseNum} tests from blur`);
suite.run({ 'async': true }); // run the benchmark
}
let blurCombinations = [combiBlur3x3, combiBlur16x16, combiBlur5x5];
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*BORDER\_\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*BORDER\_\w+\)/g)[0];
}
genBenchmarkCase(paramsContent);
} else {
runButton.onclick = function() {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
disableButton();
}
}
}
};
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -11,17 +11,17 @@ if (isNodeJs) {
var logElement = document.getElementById('log'); var logElement = document.getElementById('log');
} }
cv.onRuntimeInitialized = () => { function perf() {
console.log('opencv.js loaded'); console.log('opencv.js loaded');
if (isNodeJs) { if (isNodeJs) {
global.cv = cv; global.cv = cv;
global.combine = HelpFunc.combine; global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize; global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.cvSize; global.cvSize = Base.getCvSize();
} else { } else {
runButton.removeAttribute('disabled'); enableButton();
runButton.setAttribute('class', 'btn btn-primary'); cvSize = getCvSize();
runButton.innerHTML = 'Run';
} }
let totalCaseNum, currentCaseId; let totalCaseNum, currentCaseId;
@ -73,126 +73,77 @@ cv.onRuntimeInitialized = () => {
cv.CX_YUV2RGBA = cv.COLOR_COLORCVT_MAX + cv.COLOR_YUV2RGB cv.CX_YUV2RGBA = cv.COLOR_COLORCVT_MAX + cv.COLOR_YUV2RGB
}; };
const CvtMode = [
"COLOR_BGR2BGR555", "COLOR_BGR2BGR565", "COLOR_BGR2BGRA", "COLOR_BGR2GRAY",
"COLOR_BGR2HLS", "COLOR_BGR2HLS_FULL", "COLOR_BGR2HSV", "COLOR_BGR2HSV_FULL",
"COLOR_BGR2Lab", "COLOR_BGR2Luv", "COLOR_BGR2RGB", "COLOR_BGR2RGBA", "COLOR_BGR2XYZ",
"COLOR_BGR2YCrCb", "COLOR_BGR2YUV", "COLOR_BGR5552BGR", "COLOR_BGR5552BGRA",
"COLOR_BGR5552GRAY", "COLOR_BGR5552RGB", "COLOR_BGR5552RGBA", "COLOR_BGR5652BGR",
"COLOR_BGR5652BGRA", "COLOR_BGR5652GRAY", "COLOR_BGR5652RGB", "COLOR_BGR5652RGBA",
"COLOR_BGRA2BGR", "COLOR_BGRA2BGR555", "COLOR_BGRA2BGR565", "COLOR_BGRA2GRAY", "COLOR_BGRA2RGBA",
"CX_BGRA2HLS", "CX_BGRA2HLS_FULL", "CX_BGRA2HSV", "CX_BGRA2HSV_FULL",
"CX_BGRA2Lab", "CX_BGRA2Luv", "CX_BGRA2XYZ",
"CX_BGRA2YCrCb", "CX_BGRA2YUV",
"COLOR_GRAY2BGR", "COLOR_GRAY2BGR555", "COLOR_GRAY2BGR565", "COLOR_GRAY2BGRA",
"COLOR_HLS2BGR", "COLOR_HLS2BGR_FULL", "COLOR_HLS2RGB", "COLOR_HLS2RGB_FULL",
"CX_HLS2BGRA", "CX_HLS2BGRA_FULL", "CX_HLS2RGBA", "CX_HLS2RGBA_FULL",
"COLOR_HSV2BGR", "COLOR_HSV2BGR_FULL", "COLOR_HSV2RGB", "COLOR_HSV2RGB_FULL",
"CX_HSV2BGRA", "CX_HSV2BGRA_FULL", "CX_HSV2RGBA", "CX_HSV2RGBA_FULL",
"COLOR_Lab2BGR", "COLOR_Lab2LBGR", "COLOR_Lab2LRGB", "COLOR_Lab2RGB",
"CX_Lab2BGRA", "CX_Lab2LBGRA", "CX_Lab2LRGBA", "CX_Lab2RGBA",
"COLOR_LBGR2Lab", "COLOR_LBGR2Luv", "COLOR_LRGB2Lab", "COLOR_LRGB2Luv",
"CX_LBGRA2Lab", "CX_LBGRA2Luv", "CX_LRGBA2Lab", "CX_LRGBA2Luv",
"COLOR_Luv2BGR", "COLOR_Luv2LBGR", "COLOR_Luv2LRGB", "COLOR_Luv2RGB",
"CX_Luv2BGRA", "CX_Luv2LBGRA", "CX_Luv2LRGBA", "CX_Luv2RGBA",
"COLOR_RGB2BGR555", "COLOR_RGB2BGR565", "COLOR_RGB2GRAY",
"COLOR_RGB2HLS", "COLOR_RGB2HLS_FULL", "COLOR_RGB2HSV", "COLOR_RGB2HSV_FULL",
"COLOR_RGB2Lab", "COLOR_RGB2Luv", "COLOR_RGB2XYZ", "COLOR_RGB2YCrCb", "COLOR_RGB2YUV",
"COLOR_RGBA2BGR", "COLOR_RGBA2BGR555", "COLOR_RGBA2BGR565", "COLOR_RGBA2GRAY",
"CX_RGBA2HLS", "CX_RGBA2HLS_FULL", "CX_RGBA2HSV", "CX_RGBA2HSV_FULL",
"CX_RGBA2Lab", "CX_RGBA2Luv", "CX_RGBA2XYZ",
"CX_RGBA2YCrCb", "CX_RGBA2YUV",
"COLOR_XYZ2BGR", "COLOR_XYZ2RGB", "CX_XYZ2BGRA", "CX_XYZ2RGBA",
"COLOR_YCrCb2BGR", "COLOR_YCrCb2RGB", "CX_YCrCb2BGRA", "CX_YCrCb2RGBA",
"COLOR_YUV2BGR", "COLOR_YUV2RGB", "CX_YUV2BGRA", "CX_YUV2RGBA"
];
const CvtModeSize = [cvSize.szODD, cvSize.szVGA, cvSize.sz1080p];
const combiCvtMode = combine(CvtModeSize, CvtMode);
// didn't support 16u and 32f perf tests according to // didn't support 16u and 32f perf tests according to
// https://github.com/opencv/opencv/commit/4e679e1cc5b075ec006b29a58b4fe117523fba1d // https://github.com/opencv/opencv/commit/4e679e1cc5b075ec006b29a58b4fe117523fba1d
const CvtMode16U = [ function constructCvtMode16U() {
"COLOR_BGR2BGRA", "COLOR_BGR2GRAY", let cvtMode16U = [];
"COLOR_BGR2RGB", "COLOR_BGR2RGBA", "COLOR_BGR2XYZ", cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "BGR", ["BGRA", "GRAY", "RGB", "RGBA", "XYZ", "YCrCb", "YUV"]));
"COLOR_BGR2YCrCb", "COLOR_BGR2YUV", cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "BGRA", ["BGR", "GRAY", "RGBA"]));
cvtMode16U = cvtMode16U.concat(constructMode("CX_", "BGRA", ["XYZ", "YCrCb", "YUV"]));
"COLOR_BGRA2BGR", "COLOR_BGRA2GRAY", "COLOR_BGRA2RGBA", cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "GRAY", ["BGR", "BGRA"]));
"CX_BGRA2XYZ", cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "RGB", ["GRAY", "XYZ", "YCrCb", "YUV"]));
"CX_BGRA2YCrCb", "CX_BGRA2YUV", cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "RGBA", ["BGR", "GRAY"]));
cvtMode16U = cvtMode16U.concat(constructMode("CX_", "RGBA", ["XYZ", "YCrCb", "YUV"]));
"COLOR_GRAY2BGR", "COLOR_GRAY2BGRA", cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "XYZ", ["BGR", "RGB"]));
cvtMode16U = cvtMode16U.concat(constructMode("CX_", "XYZ", ["BGRA", "RGBA"]));
"COLOR_RGB2GRAY", cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "YCrCb", ["BGR", "RGB"]));
"COLOR_RGB2XYZ", "COLOR_RGB2YCrCb", "COLOR_RGB2YUV", cvtMode16U = cvtMode16U.concat(constructMode("CX_", "YCrCb", ["BGRA", "RGBA"]));
cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "YUV", ["BGR", "RGB"]));
"COLOR_RGBA2BGR", "COLOR_RGBA2GRAY", cvtMode16U = cvtMode16U.concat(constructMode("CX_", "YUV", ["BGRA", "RGBA"]));
"CX_RGBA2XYZ",
"CX_RGBA2YCrCb", "CX_RGBA2YUV", return cvtMode16U;
}
"COLOR_XYZ2BGR", "COLOR_XYZ2RGB", "CX_XYZ2BGRA", "CX_XYZ2RGBA", const CvtMode16U = constructCvtMode16U();
"COLOR_YCrCb2BGR", "COLOR_YCrCb2RGB", "CX_YCrCb2BGRA", "CX_YCrCb2RGBA",
"COLOR_YUV2BGR", "COLOR_YUV2RGB", "CX_YUV2BGRA", "CX_YUV2RGBA"
];
const CvtMode16USize = [cvSize.szODD, cvSize.szVGA, cvSize.sz1080p]; const CvtMode16USize = [cvSize.szODD, cvSize.szVGA, cvSize.sz1080p];
const combiCvtMode16U = combine(CvtMode16USize, CvtMode16U); const combiCvtMode16U = combine(CvtMode16USize, CvtMode16U);
const CvtMode32F = [ function constructCvtMode32F(source) {
"COLOR_BGR2BGRA", "COLOR_BGR2GRAY", let cvtMode32F = source;
"COLOR_BGR2HLS", "COLOR_BGR2HLS_FULL", "COLOR_BGR2HSV", "COLOR_BGR2HSV_FULL", cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "BGR", ["HLS", "HLS_FULL", "HSV", "HSV_FULL", "Lab", "Luv"]));
"COLOR_BGR2Lab", "COLOR_BGR2Luv", "COLOR_BGR2RGB", "COLOR_BGR2RGBA", "COLOR_BGR2XYZ", cvtMode32F = cvtMode32F.concat(constructMode("CX_", "BGRA", ["HLS", "HLS_FULL", "HSV", "HSV_FULL", "Lab", "Luv"]));
"COLOR_BGR2YCrCb", "COLOR_BGR2YUV", cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "HLS", ["BGR", "BGR_FULL", "RGB", "RGB_FULL"]));
cvtMode32F = cvtMode32F.concat(constructMode("CX_", "HLS", ["BGRA", "BGRA_FULL", "RGBA", "RGBA_FULL"]));
"COLOR_BGRA2BGR", "COLOR_BGRA2GRAY", "COLOR_BGRA2RGBA", cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "HSV", ["BGR", "BGR_FULL", "RGB", "RGB_FULL"]));
"CX_BGRA2HLS", "CX_BGRA2HLS_FULL", "CX_BGRA2HSV", "CX_BGRA2HSV_FULL", cvtMode32F = cvtMode32F.concat(constructMode("CX_", "HSV", ["BGRA", "BGRA_FULL", "RGBA", "RGBA_FULL"]));
"CX_BGRA2Lab", "CX_BGRA2Luv", "CX_BGRA2XYZ", cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "Lab", ["BGR", "LBGR", "RGB", "LRGB"]));
"CX_BGRA2YCrCb", "CX_BGRA2YUV", cvtMode32F = cvtMode32F.concat(constructMode("CX_", "Lab", ["BGRA", "LBGRA", "RGBA", "LRGBA"]));
cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "Luv", ["BGR", "LBGR", "RGB", "LRGB"]));
"COLOR_GRAY2BGR", "COLOR_GRAY2BGRA", cvtMode32F = cvtMode32F.concat(constructMode("CX_", "Luv", ["BGRA", "LBGRA", "RGBA", "LRGBA"]));
cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "LBGR", ["Lab", "Luv"]));
"COLOR_HLS2BGR", "COLOR_HLS2BGR_FULL", "COLOR_HLS2RGB", "COLOR_HLS2RGB_FULL", cvtMode32F = cvtMode32F.concat(constructMode("CX_", "LBGRA", ["Lab", "Luv"]));
"CX_HLS2BGRA", "CX_HLS2BGRA_FULL", "CX_HLS2RGBA", "CX_HLS2RGBA_FULL", cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "LRGB", ["Lab", "Luv"]));
cvtMode32F = cvtMode32F.concat(constructMode("CX_", "LRGBA", ["Lab", "Luv"]));
"COLOR_HSV2BGR", "COLOR_HSV2BGR_FULL", "COLOR_HSV2RGB", "COLOR_HSV2RGB_FULL", cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "RGB", ["HLS", "HLS_FULL", "HSV", "HSV_FULL", "Lab", "Luv"]));
"CX_HSV2BGRA", "CX_HSV2BGRA_FULL", "CX_HSV2RGBA", "CX_HSV2RGBA_FULL", cvtMode32F = cvtMode32F.concat(constructMode("CX_", "RGBA", ["HLS", "HLS_FULL", "HSV", "HSV_FULL", "Lab", "Luv"]));
"COLOR_Lab2BGR", "COLOR_Lab2LBGR", "COLOR_Lab2LRGB", "COLOR_Lab2RGB", return cvtMode32F;
"CX_Lab2BGRA", "CX_Lab2LBGRA", "CX_Lab2LRGBA", "CX_Lab2RGBA", }
"COLOR_LBGR2Lab", "COLOR_LBGR2Luv", "COLOR_LRGB2Lab", "COLOR_LRGB2Luv",
"CX_LBGRA2Lab", "CX_LBGRA2Luv", "CX_LRGBA2Lab", "CX_LRGBA2Luv",
"COLOR_Luv2BGR", "COLOR_Luv2LBGR", "COLOR_Luv2LRGB", "COLOR_Luv2RGB", const CvtMode32F = constructCvtMode32F(CvtMode16U);
"CX_Luv2BGRA", "CX_Luv2LBGRA", "CX_Luv2LRGBA", "CX_Luv2RGBA",
"COLOR_RGB2GRAY", const CvtMode32FSize = [cvSize.szODD, cvSize.szVGA, cvSize.sz1080p];
"COLOR_RGB2HLS", "COLOR_RGB2HLS_FULL", "COLOR_RGB2HSV", "COLOR_RGB2HSV_FULL", const combiCvtMode32F = combine(CvtMode32FSize, CvtMode32F);
"COLOR_RGB2Lab", "COLOR_RGB2Luv", "COLOR_RGB2XYZ", "COLOR_RGB2YCrCb", "COLOR_RGB2YUV",
"COLOR_RGBA2BGR", "COLOR_RGBA2GRAY", function constructeCvtMode(source) {
"CX_RGBA2HLS", "CX_RGBA2HLS_FULL", "CX_RGBA2HSV", "CX_RGBA2HSV_FULL", let cvtMode = source
"CX_RGBA2Lab", "CX_RGBA2Luv", "CX_RGBA2XYZ", cvtMode = cvtMode.concat(constructMode("COLOR_", "BGR", ["BGR555", "BGR565"]));
"CX_RGBA2YCrCb", "CX_RGBA2YUV", cvtMode = cvtMode.concat(constructMode("COLOR_", "BGR555", ["BGR", "BGRA", "GRAY", "RGB", "RGBA"]));
cvtMode = cvtMode.concat(constructMode("COLOR_", "BGR565", ["BGR", "BGRA", "GRAY", "RGB", "RGBA"]));
cvtMode = cvtMode.concat(constructMode("COLOR_", "BGRA", ["BGR555", "BGR565"]));
cvtMode = cvtMode.concat(constructMode("COLOR_", "GRAY", ["BGR555", "BGR565"]));
cvtMode = cvtMode.concat(constructMode("COLOR_", "RGB", ["BGR555", "BGR565"]));
cvtMode = cvtMode.concat(constructMode("COLOR_", "RGBA", ["BGR555", "BGR565"]));
return cvtMode;
}
"COLOR_XYZ2BGR", "COLOR_XYZ2RGB", "CX_XYZ2BGRA", "CX_XYZ2RGBA", const CvtMode = constructeCvtMode(CvtMode32F);
"COLOR_YCrCb2BGR", "COLOR_YCrCb2RGB", "CX_YCrCb2BGRA", "CX_YCrCb2RGBA", const CvtModeSize = [cvSize.szODD, cvSize.szVGA, cvSize.sz1080p];
"COLOR_YUV2BGR", "COLOR_YUV2RGB", "CX_YUV2BGRA", "CX_YUV2RGBA" // combiCvtMode permute size and mode
]; const combiCvtMode = combine(CvtModeSize, CvtMode);
const CvtMode32FSize = [cvSize.szODD, cvSize.szVGA, cvSize.sz1080p];
const combiCvtMode32F = combine(CvtMode32FSize, CvtMode32F);
const CvtModeBayer = [ const CvtModeBayer = [
"COLOR_BayerBG2BGR", "COLOR_BayerBG2BGRA", "COLOR_BayerBG2BGR_VNG", "COLOR_BayerBG2GRAY", "COLOR_BayerBG2BGR", "COLOR_BayerBG2BGRA", "COLOR_BayerBG2BGR_VNG", "COLOR_BayerBG2GRAY",
@ -357,7 +308,7 @@ cv.onRuntimeInitialized = () => {
return [mat1Type, mat2Type]; return [mat1Type, mat2Type];
} }
function addCvtColorCase(suite) { function addCvtColorCase(suite, type) {
suite.add('cvtColor', function() { suite.add('cvtColor', function() {
cv.cvtColor(mat1, mat2, mode, 0); cv.cvtColor(mat1, mat2, mode, 0);
}, { }, {
@ -375,179 +326,57 @@ cv.onRuntimeInitialized = () => {
}); });
} }
function addCvtModeCase(suite, combination) { function addCvtModeCase(suite, combination, type) {
totalCaseNum += combination.length; totalCaseNum += combination.length;
for(let i = 0; i < combination.length; ++i) { for(let i = 0; i < combination.length; ++i) {
let size = combination[i][0]; let size = combination[i][0];
let mode = combination[i][1]; let mode = combination[i][1];
let chPair = getConversionInfo(mode); let chPair = getConversionInfo(mode);
let matType = getMatType(chPair); let matType = getMatType(chPair);
let sizeArray = [size.width, size.height]; let sizeArray;
if (type == 0) {
addCvtColorCase(suite); sizeArray = [size.width, size.height];
// set init params } else {
let index = suite.length - 1; sizeArray = [size.width, size.height+size.height/2];
suite[index].params = {
size: sizeArray,
matType: matType,
mode: mode
};
};
}
function addCvtModeBayerCase(suite, combination) {
totalCaseNum += combination.length;
for(let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let mode = combination[i][1];
let chPair = getConversionInfo(mode);
let matType = getMatType(chPair);
let sizeArray = [size.width, size.height];
addCvtColorCase(suite);
// set init params
let index = suite.length - 1;
suite[index].params = {
size: sizeArray,
matType: matType,
mode: mode
};
};
}
function addCvtMode2Case(suite, combination) {
totalCaseNum += combination.length;
for(let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let mode = combination[i][1];
let chPair = getConversionInfo(mode);
let matType = getMatType(chPair);
let sizeArray = [size.width, size.height+size.height/2];
addCvtColorCase(suite);
// set init params
let index = suite.length - 1;
suite[index].params = {
size: sizeArray,
matType: matType,
mode: mode
};
};
} }
let params = {size:sizeArray, matType: matType, mode: mode};
function addCvtMode3Case(suite, combination) { addKernelCase(suite, params, type, addCvtColorCase);
totalCaseNum += combination.length;
for(let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let mode = combination[i][1];
let chPair = getConversionInfo(mode);
let matType = getMatType(chPair);
let sizeArray = [size.width, size.height+size.height/2];
addCvtColorCase(suite);
// set init params
let index = suite.length - 1;
suite[index].params = {
size: sizeArray,
matType: matType,
mode: mode
};
}; };
} }
function addEdgeAwareBayerModeCase(suite, combination) {
totalCaseNum += combination.length;
for(let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let mode = combination[i][1];
let chPair = getConversionInfo(mode);
let matType = getMatType(chPair);
let sizeArray = [size.width, size.height];
addCvtColorCase(suite);
// set init params
let index = suite.length - 1;
suite[index].params = {
size: sizeArray,
matType: matType,
mode: mode
};
};
}
function decodeParams2Case(suite, params) {
let sizeStr = (params.match(/[0-9]+/g) || []).slice(0, 2).toString();
let mode = (params.match(/CX\_[A-z]+2[A-z]+/) || params.match(/COLOR\_[A-z]+2[A-z]+/) || []).toString();
let size = cvtStr2cvSize(sizeStr);
// check if the params match and add case
for (let i = 0; i < combinations.length; ++i) {
let combination = combinations[i];
for (let j = 0; j < combination.length; ++j) {
if (size === combination[j][0] && mode === combination[j][1]) {
cvtFunc[i](suite, [combination[j]]);
}
}
}
}
function log(message) {
console.log(message);
if (!isNodeJs) {
logElement.innerHTML += `\n${'\t' + message}`;
}
}
function setBenchmarkSuite(suite) {
suite
// add listeners
.on('cycle', function(event) {
++currentCaseId;
let params = event.target.params;
let mode = params.mode;
let size = params.size;
log(`=== ${event.target.name} ${currentCaseId} ===`);
log(`params: (${parseInt(size[0])}x${parseInt(size[1])}, ${mode})`);
log('elapsed time:' +String(event.target.times.elapsed*1000)+' ms');
log('mean time:' +String(event.target.stats.mean*1000)+' ms');
log('stddev time:' +String(event.target.stats.deviation*1000)+' ms');
log(String(event.target));
})
.on('error', function(event) { log(`test case ${event.target.name} failed`); })
.on('complete', function(event) {
log(`\n ###################################`)
log(`Finished testing ${event.currentTarget.length} cases \n`);
if (!isNodeJs) {
runButton.removeAttribute('disabled');
runButton.setAttribute('class', 'btn btn-primary');
runButton.innerHTML = 'Run';
}
});
}
function genBenchmarkCase(paramsContent) { function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite; let suite = new Benchmark.Suite;
totalCaseNum = 0; totalCaseNum = 0;
currentCaseId = 0; currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*\w+\)/g.test(paramsContent.toString())) { if (/\([0-9]+x[0-9]+,[\ ]*\w+\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+\)/g)[0]; let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+\)/g)[0];
decodeParams2Case(suite, params); let paramObjs = [];
paramObjs.push({name:"mode", value:"", reg:["/CX\_[A-z]+2[A-z]+/", "/COLOR\_[A-z]+2[A-z]+/"], index:1});
paramObjs.push({name:"size", value:"", reg:[""], index:0});
let locationList = decodeParams2Case(params, paramObjs,combinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
if (first < 2) {
addCvtModeCase(suite, [combinations[first][second]], 0);
} else {
addCvtModeCase(suite, [combinations[first][second]], 1);
}
}
} else { } else {
log("no filter or getting invalid params, run all the cases"); log("no filter or getting invalid params, run all the cases");
addCvtModeCase(suite, combiCvtMode); addCvtModeCase(suite, combiCvtMode, 0);
addCvtModeBayerCase(suite, combiCvtModeBayer); addCvtModeCase(suite, combiCvtModeBayer, 0);
addCvtMode2Case(suite, combiCvtMode2); addCvtModeCase(suite, combiCvtMode2, 1);
addCvtMode3Case(suite, combiCvtMode3); addCvtModeCase(suite, combiCvtMode3, 1);
} }
setBenchmarkSuite(suite); setBenchmarkSuite(suite, "cvtcolor", currentCaseId);
log(`Running ${totalCaseNum} tests from CvtColor`); log(`Running ${totalCaseNum} tests from CvtColor`);
suite.run({ 'async': true }); // run the benchmark suite.run({ 'async': true }); // run the benchmark
} }
// init // init
let cvtFunc = [addCvtModeCase, addCvtModeBayerCase, addCvtMode2Case, addCvtMode3Case];//, addEdgeAwareBayerModeCase];
let combinations = [combiCvtMode, combiCvtModeBayer, combiCvtMode2, combiCvtMode3];//, combiEdgeAwareBayer]; let combinations = [combiCvtMode, combiCvtModeBayer, combiCvtMode2, combiCvtMode3];//, combiEdgeAwareBayer];
// set test filter params // set test filter params
@ -563,10 +392,19 @@ cv.onRuntimeInitialized = () => {
let paramsContent = paramsElement.value; let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent); genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) { if (totalCaseNum !== 0) {
runButton.setAttribute("disabled", "disabled"); disableButton();
runButton.setAttribute('class', 'btn btn-primary disabled');
runButton.innerHTML = "Running";
} }
} }
} }
}; };
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenCV.js Performance Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
font-size: 13px;
}
.top-margin {
margin-top:10px;
}
h1, h4 {
margin: 24px 0 0;
}
h1 {
font-size: 2.0em;
}
h4 {
font-size: 1.2em;
}
pre {
font-family: 'Consolas', 'Monaco', monospace, serif;
font-size: 12px;
tab-size: 2;
}
input[type=checkbox] {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container" id="container">
<div class="row">
<div class="col-12">
<h1>OpenCV.js Performance Test</h1>
<div>
<h4>Modules</h4>
<h7>Image Processing</h7>
</div>
<div>
<h4>Kernels</h4>
<h7>Dilate</h7>
</div>
<div>
<h4>Parameters Filter</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (1024x768, CV_8UC1)
</div>
<div class='row labels-wrapper' id='labelitem'></div>
<div class="row top-margin">
</div>
<div>
<button type="button" id="runButton" class="btn btn-primary disabled" disabled="disabled">Loading</button>
(It will take several minutes)</div>
<div class="row top-margin">
</div>
<div>
<pre id="log"></pre>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js"></script>
<script src="../../opencv.js" type="text/javascript"></script>
<script src="../base.js"></script>
<script src="../perf_helpfunc.js"></script>
<script src="./perf_dilate.js"></script>
</body>
</html>

@ -0,0 +1,117 @@
const isNodeJs = (typeof window) === 'undefined'? true : false;
if (isNodeJs) {
var Benchmark = require('benchmark');
var cv = require('../../opencv');
var HelpFunc = require('../perf_helpfunc');
var Base = require('../base');
} else {
var paramsElement = document.getElementById('params');
var runButton = document.getElementById('runButton');
var logElement = document.getElementById('log');
}
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.getCvSize();
} else {
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
const DilateSize = [cvSize.szQVGA, cvSize.szVGA, cvSize.szSVGA, cvSize.szXGA, cvSize.szSXGA];
const DilateType = ["CV_8UC1", "CV_8UC4"];
const combiDilate = combine(DilateSize, DilateType);
function addDialteCase(suite, type) {
suite.add('dilate', function() {
cv.dilate(src, dst, kernel);
}, {
'setup': function() {
let size = this.params.size;
let matType = cv[this.params.matType];
let src = new cv.Mat(size, matType);
let dst = new cv.Mat(size, matType);
let kernel = new cv.Mat();
},
'teardown': function() {
src.delete();
dst.delete();
kernel.delete();
}
});
}
function addDilateModeCase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let matType = combination[i][1];
let params = {size: size, matType:matType};
addKernelCase(suite, params, type, addDialteCase);
}
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*CV\_\w+\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+\)/g)[0];
let paramObjs = [];
paramObjs.push({name:"size", value:"", reg:[""], index:0});
paramObjs.push({name:"matType", value:"", reg:["/CV\_[0-9]+[FSUfsu]C[0-9]/"], index:1});
let locationList = decodeParams2Case(params, paramObjs, dilateCombinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
addDilateModeCase(suite, [dilateCombinations[first][second]], first);
}
} else {
log("no filter or getting invalid params, run all the cases");
addDilateModeCase(suite, combiDilate, 0);
}
setBenchmarkSuite(suite, "dilate", currentCaseId);
log(`Running ${totalCaseNum} tests from dilate`);
suite.run({ 'async': true }); // run the benchmark
}
let dilateCombinations = [combiDilate];
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*CV\_\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+\)/g)[0];
}
genBenchmarkCase(paramsContent);
} else {
runButton.onclick = function() {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
disableButton();
}
}
}
};
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenCV.js Performance Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
font-size: 13px;
}
.top-margin {
margin-top:10px;
}
h1, h4 {
margin: 24px 0 0;
}
h1 {
font-size: 2.0em;
}
h4 {
font-size: 1.2em;
}
pre {
font-family: 'Consolas', 'Monaco', monospace, serif;
font-size: 12px;
tab-size: 2;
}
input[type=checkbox] {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container" id="container">
<div class="row">
<div class="col-12">
<h1>OpenCV.js Performance Test</h1>
<div>
<h4>Modules</h4>
<h7>Image Processing</h7>
</div>
<div>
<h4>Kernels</h4>
<h7>Erode</h7>
</div>
<div>
<h4>Parameters Filter</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (1024x768, CV_8UC1)
</div>
<div class='row labels-wrapper' id='labelitem'></div>
<div class="row top-margin">
</div>
<div>
<button type="button" id="runButton" class="btn btn-primary disabled" disabled="disabled">Loading</button>
(It will take several minutes)</div>
<div class="row top-margin">
</div>
<div>
<pre id="log"></pre>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js"></script>
<script src="../../opencv.js" type="text/javascript"></script>
<script src="../base.js"></script>
<script src="../perf_helpfunc.js"></script>
<script src="./perf_erode.js"></script>
</body>
</html>

@ -0,0 +1,117 @@
const isNodeJs = (typeof window) === 'undefined'? true : false;
if (isNodeJs) {
var Benchmark = require('benchmark');
var cv = require('../../opencv');
var HelpFunc = require('../perf_helpfunc');
var Base = require('../base');
} else {
var paramsElement = document.getElementById('params');
var runButton = document.getElementById('runButton');
var logElement = document.getElementById('log');
}
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.getCvSize();
} else {
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
const ErodeSize = [cvSize.szQVGA, cvSize.szVGA, cvSize.szSVGA, cvSize.szXGA, cvSize.szSXGA];
const ErodeType = ["CV_8UC1", "CV_8UC4"];
const combiErode = combine(ErodeSize, ErodeType);
function addErodeCase(suite, type) {
suite.add('erode', function() {
cv.erode(src, dst, kernel);
}, {
'setup': function() {
let size = this.params.size;
let matType = cv[this.params.matType];
let src = new cv.Mat(size, matType);
let dst = new cv.Mat(size, matType);
let kernel = new cv.Mat();
},
'teardown': function() {
src.delete();
dst.delete();
kernel.delete();
}
});
}
function addErodeModeCase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let matType = combination[i][1];
let params = {size: size, matType:matType};
addKernelCase(suite, params, type, addErodeCase);
}
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*CV\_\w+\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+\)/g)[0];
let paramObjs = [];
paramObjs.push({name:"size", value:"", reg:[""], index:0});
paramObjs.push({name:"matType", value:"", reg:["/CV\_[0-9]+[FSUfsu]C[0-9]/"], index:1});
let locationList = decodeParams2Case(params, paramObjs, erodeCombinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
addErodeModeCase(suite, [erodeCombinations[first][second]], first);
}
} else {
log("no filter or getting invalid params, run all the cases");
addErodeModeCase(suite, combiErode, 0);
}
setBenchmarkSuite(suite, "erode", currentCaseId);
log(`Running ${totalCaseNum} tests from erode`);
suite.run({ 'async': true }); // run the benchmark
}
let erodeCombinations = [combiErode];
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*CV\_\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+\)/g)[0];
}
genBenchmarkCase(paramsContent);
} else {
runButton.onclick = function() {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
disableButton();
}
}
}
};
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenCV.js Performance Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
font-size: 13px;
}
.top-margin {
margin-top:10px;
}
h1, h4 {
margin: 24px 0 0;
}
h1 {
font-size: 2.0em;
}
h4 {
font-size: 1.2em;
}
pre {
font-family: 'Consolas', 'Monaco', monospace, serif;
font-size: 12px;
tab-size: 2;
}
input[type=checkbox] {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container" id="container">
<div class="row">
<div class="col-12">
<h1>OpenCV.js Performance Test</h1>
<div>
<h4>Modules</h4>
<h7>Image Processing</h7>
</div>
<div>
<h4>Kernels</h4>
<h7>Filter2D</h7>
</div>
<div>
<h4>Parameters Filter</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (320x240, 3, BORDER_CONSTANT)
</div>
<div class='row labels-wrapper' id='labelitem'></div>
<div class="row top-margin">
</div>
<div>
<button type="button" id="runButton" class="btn btn-primary disabled" disabled="disabled">Loading</button>
(It will take several minutes)</div>
<div class="row top-margin">
</div>
<div>
<pre id="log"></pre>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js"></script>
<script src="../../opencv.js" type="text/javascript"></script>
<script src="../base.js"></script>
<script src="../perf_helpfunc.js"></script>
<script src="./perf_filter2D.js"></script>
</body>
</html>

@ -0,0 +1,127 @@
const isNodeJs = (typeof window) === 'undefined'? true : false;
if (isNodeJs) {
var Benchmark = require('benchmark');
var cv = require('../../opencv');
var HelpFunc = require('../perf_helpfunc');
var Base = require('../base');
} else {
var paramsElement = document.getElementById('params');
var runButton = document.getElementById('runButton');
var logElement = document.getElementById('log');
}
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.getCvSize();
} else {
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
const Filter2dSize = [cvSize.szQVGA, cvSize.sz1080p];
const Filter2dKsize = ["3", "5"];
const Filter2dBorderMode = ["BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_REFLECT_101"];
const DISABLED_Filter2dBorderMode = ["BORDER_CONSTANT", "BORDER_REPLICATE"];
const combiFilter2dCase = combine(Filter2dSize, Filter2dKsize, Filter2dBorderMode);
const combiDISABLEDFilter2dCase = combine(Filter2dSize, Filter2dKsize, DISABLED_Filter2dBorderMode);
function addFilter2dCase(suite, type) {
suite.add('filter2d', function() {
cv.filter2D(src, dst, cv.CV_8UC4, kernel, new cv.Point(1, 1), 0.0, borderMode);
}, {
'setup': function() {
let size = this.params.size;
let ksize = parseInt(this.params.ksize);
let borderMode = cv[this.params.borderMode];
let src = new cv.Mat(size, cv.CV_8UC4);
let dst = new cv.Mat(size, cv.CV_8UC4);
let kernelElement = [];
for (let i = 0; i < ksize*ksize; i++) {
let randNum = Math.random();
kernelElement.push(-3.0+randNum*13.0);
}
let kernel = cv.matFromArray(ksize, ksize, cv.CV_32FC1, kernelElement);
},
'teardown': function() {
src.delete();
dst.delete();
}
});
}
function addFilter2dModeCase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let ksize = combination[i][1];
let borderMode = combination[i][2];
let params = {size: size, ksize: ksize, borderMode:borderMode};
addKernelCase(suite, params, type, addFilter2dCase);
}
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*[0-9],[\ ]*BORDER\_\w+\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*[0-9],[\ ]*BORDER\_\w+\)/g)[0];
let paramObjs = [];
paramObjs.push({name:"size", value:"", reg:[""], index:0});
paramObjs.push({name:"ksize", value:"", reg:["/\\b[0-9]\\b/"], index:1});
paramObjs.push({name:"borderMode", value: "", reg:["/BORDER\_\\w+/"], index:2});
let locationList = decodeParams2Case(params, paramObjs,filter2dCombinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
addFilter2dModeCase(suite, [filter2dCombinations[first][second]], 0);
}
} else {
log("no filter or getting invalid params, run all the cases");
addFilter2dModeCase(suite, combiFilter2dCase, 0);
}
setBenchmarkSuite(suite, "filter2d", currentCaseId);
log(`Running ${totalCaseNum} tests from Filter2d`);
suite.run({ 'async': true }); // run the benchmark
}
let filter2dCombinations = [combiFilter2dCase];//,combiDISABLEDFilter2dCase];
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*[0-9],[\ ]*BORDER\_\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*[0-9],[\ ]*BORDER\_\w+\)/g)[0];
}
genBenchmarkCase(paramsContent);
} else {
runButton.onclick = function() {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
disableButton();
}
}
}
};
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenCV.js Performance Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
font-size: 13px;
}
.top-margin {
margin-top:10px;
}
h1, h4 {
margin: 24px 0 0;
}
h1 {
font-size: 2.0em;
}
h4 {
font-size: 1.2em;
}
pre {
font-family: 'Consolas', 'Monaco', monospace, serif;
font-size: 12px;
tab-size: 2;
}
input[type=checkbox] {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container" id="container">
<div class="row">
<div class="col-12">
<h1>OpenCV.js Performance Test</h1>
<div>
<h4>Modules</h4>
<h7>Image Processing</h7>
</div>
<div>
<h4>Kernels</h4>
<h7>gaussianBlur</h7>
</div>
<div>
<h4>Parameters Filter</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (1280x720, CV_8UC1, BORDER_REPLICATE)
</div>
<div class='row labels-wrapper' id='labelitem'></div>
<div class="row top-margin">
</div>
<div>
<button type="button" id="runButton" class="btn btn-primary disabled" disabled="disabled">Loading</button>
(It will take several minutes)</div>
<div class="row top-margin">
</div>
<div>
<pre id="log"></pre>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js"></script>
<script src="../../opencv.js" type="text/javascript"></script>
<script src="../base.js"></script>
<script src="../perf_helpfunc.js"></script>
<script src="./perf_gaussianBlur.js"></script>
</body>
</html>

@ -0,0 +1,126 @@
const isNodeJs = (typeof window) === 'undefined'? true : false;
if (isNodeJs) {
var Benchmark = require('benchmark');
var cv = require('../../opencv');
var HelpFunc = require('../perf_helpfunc');
var Base = require('../base');
} else {
var paramsElement = document.getElementById('params');
var runButton = document.getElementById('runButton');
var logElement = document.getElementById('log');
}
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.getCvSize();
} else {
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
const GaussianBlurSize = [cvSize.szODD, cvSize.szQVGA, cvSize.szVGA, cvSize.sz720p];
const GaussianBlurType = ["CV_8UC1", "CV_8UC4", "CV_16UC1", "CV_16SC1", "CV_32FC1"];
const BorderType3x3 = ["BORDER_REPLICATE", "BORDER_CONSTANT"];
const BorderType3x3ROI = ["BORDER_REPLICATE", "BORDER_CONSTANT", "BORDER_REFLECT", "BORDER_REFLECT101"];
const combiGaussianBlurBorder3x3 = combine(GaussianBlurSize, GaussianBlurType, BorderType3x3);
const combiGaussianBlurBorder3x3ROI = combine(GaussianBlurSize, GaussianBlurType, BorderType3x3ROI);
function addGaussianBlurCase(suite, type) {
suite.add('gaussianBlur', function() {
cv.GaussianBlur(src, dst, ksize, 1, 0, borderType);
}, {
'setup': function() {
let size = this.params.size;
let matType = cv[this.params.matType];
let borderType = cv[this.params.borderType];
let type = this.params.type;
let src = new cv.Mat(size, matType);
let dst = new cv.Mat(size, matType);
let ksizeNum = this.params.ksize;
let ksize = new cv.Size(ksizeNum, ksizeNum);
},
'teardown': function() {
src.delete();
dst.delete();
}
});
}
function addGaussianBlurModeCase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let matType = combination[i][1];
let borderType = combination[i][2];
let ksizeArray = [3, 5];
let params = {size: size, matType:matType, ksize: ksizeArray[type], borderType:borderType};
addKernelCase(suite, params, type, addGaussianBlurCase);
}
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*BORDER\_\w+\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*BORDER\_\w+\)/g)[0];
let paramObjs = [];
paramObjs.push({name:"size", value:"", reg:[""], index:0});
paramObjs.push({name:"matType", value:"", reg:["/CV\_[0-9]+[FSUfsu]C[0-9]/"], index:1});
paramObjs.push({name:"borderMode", value: "", reg:["/BORDER\_\\w+/"], index:2});
let locationList = decodeParams2Case(params, paramObjs,gaussianBlurCombinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
addGaussianBlurModeCase(suite, [gaussianBlurCombinations[first][second]], first);
}
} else {
log("no filter or getting invalid params, run all the cases");
addGaussianBlurModeCase(suite, combiGaussianBlurBorder3x3, 0);
addGaussianBlurModeCase(suite, combiGaussianBlurBorder3x3ROI, 1);
}
setBenchmarkSuite(suite, "gaussianBlur", currentCaseId);
log(`Running ${totalCaseNum} tests from gaussianBlur`);
suite.run({ 'async': true }); // run the benchmark
}
let gaussianBlurCombinations = [combiGaussianBlurBorder3x3, combiGaussianBlurBorder3x3ROI];
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*BORDER\_\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*BORDER\_\w+\)/g)[0];
}
genBenchmarkCase(paramsContent);
} else {
runButton.onclick = function() {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
disableButton();
}
}
}
};
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenCV.js Performance Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
font-size: 13px;
}
.top-margin {
margin-top:10px;
}
h1, h4 {
margin: 24px 0 0;
}
h1 {
font-size: 2.0em;
}
h4 {
font-size: 1.2em;
}
pre {
font-family: 'Consolas', 'Monaco', monospace, serif;
font-size: 12px;
tab-size: 2;
}
input[type=checkbox] {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container" id="container">
<div class="row">
<div class="col-12">
<h1>OpenCV.js Performance Test</h1>
<div>
<h4>Modules</h4>
<h7>Image Processing</h7>
</div>
<div>
<h4>Kernels</h4>
<h7>MedianBlur</h7>
</div>
<div>
<h4>Parameters Filter</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (1280x720, CV_8UC1, 3)
</div>
<div class='row labels-wrapper' id='labelitem'></div>
<div class="row top-margin">
</div>
<div>
<button type="button" id="runButton" class="btn btn-primary disabled" disabled="disabled">Loading</button>
(It will take several minutes)</div>
<div class="row top-margin">
</div>
<div>
<pre id="log"></pre>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js"></script>
<script src="../../opencv.js" type="text/javascript"></script>
<script src="../base.js"></script>
<script src="../perf_helpfunc.js"></script>
<script src="./perf_medianBlur.js"></script>
</body>
</html>

@ -0,0 +1,118 @@
const isNodeJs = (typeof window) === 'undefined'? true : false;
if (isNodeJs) {
var Benchmark = require('benchmark');
var cv = require('../../opencv');
var HelpFunc = require('../perf_helpfunc');
var Base = require('../base');
} else {
var paramsElement = document.getElementById('params');
var runButton = document.getElementById('runButton');
var logElement = document.getElementById('log');
}
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.getCvSize();
} else {
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
const MedianBlurSize = [cvSize.szODD, cvSize.szQVGA, cvSize.szVGA, cvSize.sz720p];
const MedianBlurType = ["CV_8UC1", "CV_8UC4", "CV_16UC1", "CV_16SC1", "CV_32FC1"];
const combiMedianBlur = combine(MedianBlurSize, MedianBlurType, [3,5]);
function addMedianBlurCase(suite, type) {
suite.add('medianBlur', function() {
cv.medianBlur(src, dst, ksize);
}, {
'setup': function() {
let size = this.params.size;
let matType = cv[this.params.matType];
let ksize = this.params.ksize;
let src = new cv.Mat(size, matType);
let dst = new cv.Mat(size, matType);
},
'teardown': function() {
src.delete();
dst.delete();
}
});
}
function addMedianBlurModeCase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let matType = combination[i][1];
let ksize = combination[i][2];
let params = {size: size, matType:matType, ksize: ksize};
addKernelCase(suite, params, type, addMedianBlurCase);
}
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*(3|5)\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*(3|5)\)/g)[0];
let paramObjs = [];
paramObjs.push({name:"size", value:"", reg:[""], index:0});
paramObjs.push({name:"matType", value:"", reg:["/CV\_[0-9]+[FSUfsu]C[0-9]/"], index:1});
paramObjs.push({name:"ksize", value: "", reg:["/\\b[0-9]\\b/"], index:2});
let locationList = decodeParams2Case(params, paramObjs, medianBlurCombinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
addMedianBlurModeCase(suite, [medianBlurCombinations[first][second]], first);
}
} else {
log("no filter or getting invalid params, run all the cases");
addMedianBlurModeCase(suite, combiMedianBlur, 0);
}
setBenchmarkSuite(suite, "medianBlur", currentCaseId);
log(`Running ${totalCaseNum} tests from medianBlur`);
suite.run({ 'async': true }); // run the benchmark
}
let medianBlurCombinations = [combiMedianBlur];
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*(3|5)\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*(3|5)\)/g)[0];
}
genBenchmarkCase(paramsContent);
} else {
runButton.onclick = function() {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
disableButton();
}
}
}
};
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenCV.js Performance Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
font-size: 13px;
}
.top-margin {
margin-top:10px;
}
h1, h4 {
margin: 24px 0 0;
}
h1 {
font-size: 2.0em;
}
h4 {
font-size: 1.2em;
}
pre {
font-family: 'Consolas', 'Monaco', monospace, serif;
font-size: 12px;
tab-size: 2;
}
input[type=checkbox] {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container" id="container">
<div class="row">
<div class="col-12">
<h1>OpenCV.js Performance Test</h1>
<div>
<h4>Modules</h4>
<h7>Image Processing</h7>
</div>
<div>
<h4>Kernels</h4>
<h7>pyrDown</h7>
</div>
<div>
<h4>Parameters Filter</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (1920x1080, CV_8UC3)
</div>
<div class='row labels-wrapper' id='labelitem'></div>
<div class="row top-margin">
</div>
<div>
<button type="button" id="runButton" class="btn btn-primary disabled" disabled="disabled">Loading</button>
(It will take several minutes)</div>
<div class="row top-margin">
</div>
<div>
<pre id="log"></pre>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js"></script>
<script src="../../opencv.js" type="text/javascript"></script>
<script src="../base.js"></script>
<script src="../perf_helpfunc.js"></script>
<script src="./perf_pyrDown.js"></script>
</body>
</html>

@ -0,0 +1,116 @@
const isNodeJs = (typeof window) === 'undefined'? true : false;
if (isNodeJs) {
var Benchmark = require('benchmark');
var cv = require('../../opencv');
var HelpFunc = require('../perf_helpfunc');
var Base = require('../base');
} else {
var paramsElement = document.getElementById('params');
var runButton = document.getElementById('runButton');
var logElement = document.getElementById('log');
}
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.getCvSize();
} else {
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
const PyrDownSize = [cvSize.sz1080p, cvSize.sz720p, cvSize.szVGA, cvSize.szQVGA, cvSize.szODD];
const PyrDownType = ["CV_8UC1", "CV_8UC3", "CV_8UC4", "CV_16SC1", "CV_16SC3", "CV_16SC4", "CV_32FC1", "CV_32FC3", "CV_32FC4"];
const combiPyrDown = combine(PyrDownSize, PyrDownType);
function addPryDownCase(suite, type) {
suite.add('pyrDown', function() {
cv.pyrDown(src, dst);
}, {
'setup': function() {
let size = this.params.size;
let matType = cv[this.params.matType];
let src = new cv.Mat(size, matType);
let dst = new cv.Mat((size.height + 1)/2, (size.height + 1)/2, matType)
},
'teardown': function() {
src.delete();
dst.delete();
}
});
}
function addPyrDownModeCase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let matType = combination[i][1];
let params = {size: size, matType:matType};
addKernelCase(suite, params, type, addPryDownCase);
}
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*CV\_\w+\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+\)/g)[0];
let paramObjs = [];
paramObjs.push({name:"size", value:"", reg:[""], index:0});
paramObjs.push({name:"matType", value:"", reg:["/CV\_[0-9]+[FSUfsu]C[0-9]/"], index:1});
let locationList = decodeParams2Case(params, paramObjs, pyrDownCombinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
addPyrDownModeCase(suite, [pyrDownCombinations[first][second]], first);
}
} else {
log("no filter or getting invalid params, run all the cases");
addPyrDownModeCase(suite, combiPyrDown, 0);
}
setBenchmarkSuite(suite, "pyrDown", currentCaseId);
log(`Running ${totalCaseNum} tests from pyrDown`);
suite.run({ 'async': true }); // run the benchmark
}
let pyrDownCombinations = [combiPyrDown];
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*CV\_\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+\)/g)[0];
}
genBenchmarkCase(paramsContent);
} else {
runButton.onclick = function() {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
disableButton();
}
}
}
};
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenCV.js Performance Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
font-size: 13px;
}
.top-margin {
margin-top:10px;
}
h1, h4 {
margin: 24px 0 0;
}
h1 {
font-size: 2.0em;
}
h4 {
font-size: 1.2em;
}
pre {
font-family: 'Consolas', 'Monaco', monospace, serif;
font-size: 12px;
tab-size: 2;
}
input[type=checkbox] {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container" id="container">
<div class="row">
<div class="col-12">
<h1>OpenCV.js Performance Test</h1>
<div>
<h4>Modules</h4>
<h7>Image Processing</h7>
</div>
<div>
<h4>Kernels</h4>
<h7>Remap</h7>
</div>
<div>
<h4>Parameters Filter</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (640x480, CV_16UC1, CV_16SC2, INTER_NEAREST)
</div>
<div class='row labels-wrapper' id='labelitem'></div>
<div class="row top-margin">
</div>
<div>
<button type="button" id="runButton" class="btn btn-primary disabled" disabled="disabled">Loading</button>
(It will take several minutes)</div>
<div class="row top-margin">
</div>
<div>
<pre id="log"></pre>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js"></script>
<script src="../../opencv.js" type="text/javascript"></script>
<script src="../base.js"></script>
<script src="../perf_helpfunc.js"></script>
<script src="./perf_remap.js"></script>
</body>
</html>

@ -0,0 +1,182 @@
const isNodeJs = (typeof window) === 'undefined'? true : false;
if (isNodeJs) {
var Benchmark = require('benchmark');
var cv = require('../../opencv');
var HelpFunc = require('../perf_helpfunc');
var Base = require('../base');
} else {
var paramsElement = document.getElementById('params');
var runButton = document.getElementById('runButton');
var logElement = document.getElementById('log');
}
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.getCvSize();
} else {
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
const RemapSize = [cvSize.szVGA, cvSize.sz1080p];
const RemapSrcType = ["CV_16UC1", "CV_16SC1", "CV_32FC1"];
const RemapType = ["CV_16SC2", "CV_32FC1", "CV_32FC2"];
const InterType = ["INTER_NEAREST", "INTER_LINEAR", "INTER_CUBIC", "INTER_LANCZOS4"];
const combiRemap = combine(RemapSize, RemapSrcType, RemapType, InterType);
function addRemapCase(suite, type) {
suite.add('remap', function() {
cv.remap(src, dst, map1, map2, interType);
}, {
'setup': function() {
let size = this.params.size;
let matType = cv[this.params.matType];
let mapType = cv[this.params.mapType];
let interType = cv[this.params.interType];
let src = new cv.Mat(size, matType);
let dst = new cv.Mat(size, matType);
let map1 = new cv.Mat(size, mapType);
let map2;
if (mapType == cv.CV_32FC1) {
map2 = new cv.Mat(size, mapType);
} else if (interType != cv.INTER_NEAREST && mapType == cv.CV_16SC2) {
map2 = new cv.Mat.zeros(size, cv.CV_16UC1);
} else {
map2 = new cv.Mat();
}
for (let j = 0; j < map1.rows; j++) {
for (let i = 0; i < map1.cols; i++) {
let randNum = Math.random();
let view, view1;
switch(matType) {
case cv.CV_16UC1:
view = src.ushortPtr(j,i);
view[0] = Math.floor(randNum*256);
break;
case cv.CV_16SC1:
view = src.shortPtr(j,i);
view[0] = Math.floor(randNum*256);
break;
case cv.CV_32FC1:
view = src.floatPtr(j,i);
view[0] = randNum*256;
break;
default:
console.error("Unknown conversion type 1");
break;
}
switch(mapType) {
case cv.CV_32FC1:
view1 = map1.floatPtr(j,i);
let view2 = map2.floatPtr(j,i);
view1[0] = src.cols - i - 1;
view2[0] = j;
break;
case cv.CV_32FC2:
view1 = map1.floatPtr(j,i);
view1[0] = src.cols - i - 1;
view1[1] = j;
break;
case cv.CV_16SC2:
view1 = map1.shortPtr(j,i);
view1[0] = src.cols - i - 1;
view1[1] = j;
break;
default:
console.error("Unknown conversion type 2");
break;
}
}
}
},
'teardown': function() {
src.delete();
dst.delete();
map1.delete();
map2.delete();
}
});
}
function addRemapModeCase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let matType = combination[i][1];
let mapType = combination[i][2];
let interType = combination[i][3];
let params = {size: size, matType:matType, mapType:mapType, interType:interType};
addKernelCase(suite, params, type, addRemapCase);
}
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*CV\_\w+,[\ ]*INTER\_\w+\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*CV\_\w+,[\ ]*INTER\_\w+\)/g)[0];
let paramObjs = [];
paramObjs.push({name:"size", value:"", reg:[""], index:0});
paramObjs.push({name:"matType", value:"", reg:["/CV\_[0-9]+[FSUfsu]C[0-9]/"], index:1});
paramObjs.push({name:"mapType", value:"", reg:["/CV\_[0-9]+[FSUfsu]C[0-9]/g"], index:2, loc:1});
paramObjs.push({name:"interType", value: "", reg:["/INTER\_\\w+/"], index:3});
let locationList = decodeParams2Case(params, paramObjs, remapCombinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
addRemapModeCase(suite, [remapCombinations[first][second]], first);
}
} else {
log("no filter or getting invalid params, run all the cases");
addRemapModeCase(suite, combiRemap, 0);
}
setBenchmarkSuite(suite, "remap", currentCaseId);
log(`Running ${totalCaseNum} tests from remap`);
suite.run({ 'async': true }); // run the benchmark
}
let remapCombinations = [combiRemap];
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*CV\_\w+,[\ ]*INTER\_\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*CV\_\w+,[\ ]*INTER\_\w+\)/g)[0];
}
genBenchmarkCase(paramsContent);
} else {
runButton.onclick = function() {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
disableButton();
}
}
}
};
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -11,18 +11,17 @@ if (isNodeJs) {
var logElement = document.getElementById('log'); var logElement = document.getElementById('log');
} }
cv.onRuntimeInitialized = () => { function perf() {
console.log('opencv.js loaded'); console.log('opencv.js loaded');
if (isNodeJs) { if (isNodeJs) {
global.cv = cv; global.cv = cv;
global.combine = HelpFunc.combine; global.combine = HelpFunc.combine;
global.fillGradient = HelpFunc.fillGradient;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize; global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.cvSize; global.cvSize = Base.getCvSize();
} else { } else {
runButton.removeAttribute('disabled'); enableButton();
runButton.setAttribute('class', 'btn btn-primary'); cvSize = getCvSize();
runButton.innerHTML = 'Run';
} }
let totalCaseNum, currentCaseId; let totalCaseNum, currentCaseId;
@ -59,164 +58,50 @@ cv.onRuntimeInitialized = () => {
const scalesAreaFast = [2]; const scalesAreaFast = [2];
const combiAreaFast = combine(matTypesAreaFast, sizesAreaFast, scalesAreaFast); const combiAreaFast = combine(matTypesAreaFast, sizesAreaFast, scalesAreaFast);
function addResizeUpLinearCase(suite, combination) { function addResizeCase(suite, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let matType = combination[i][0];
let from = combination[i][1];
let to = combination[i][2];
suite.add('resize', function() { suite.add('resize', function() {
if (type == "area") {
cv.resize(src, dst, dst.size(), 0, 0, cv.INTER_AREA);
} else {
cv.resize(src, dst, to, 0, 0, cv.INTER_LINEAR_EXACT); cv.resize(src, dst, to, 0, 0, cv.INTER_LINEAR_EXACT);
}, {
'setup': function() {
let from = this.params.from;
let to = this.params.to;
let matType = cv[this.params.matType];
let src = new cv.Mat(from, matType);
let dst = new cv.Mat(to, matType);
fillGradient(cv, src);
},
'teardown': function() {
src.delete();
dst.delete();
}
});
// set init params
let index = suite.length - 1;
suite[index].params = {
from: from,
to: to,
matType: matType
};
} }
}
function addResizeDownLinearCase(suite, combination) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let matType = combination[i][0];
let from = combination[i][1];
let to = combination[i][2];
suite.add('resize', function() {
cv.resize(src, dst, to, 0, 0, cv.INTER_LINEAR_EXACT);
}, { }, {
'setup': function() { 'setup': function() {
let from = this.params.from; let from = this.params.from;
let to = this.params.to; let to = this.params.to;
let matType = cv[this.params.matType]; let matType = cv[this.params.matType];
let src = new cv.Mat(from, matType); let src = new cv.Mat(from, matType);
let dst = new cv.Mat(to, matType); let type = this.params.modeType;
let dst;
if (type == "area") {
dst = new cv.Mat(from.height/scale, from.width/scale, matType);
} else {
dst = new cv.Mat(to, matType);
fillGradient(cv, src); fillGradient(cv, src);
}
}, },
'teardown': function() { 'teardown': function() {
src.delete(); src.delete();
dst.delete(); dst.delete();
} }
}); });
// set init params
let index = suite.length - 1;
suite[index].params = {
from: from,
to: to,
matType: matType
};
}
} }
function addResizeAreaFastCase(suite, combination) { function addResizeModeCase(suite, combination, type) {
totalCaseNum += combination.length; totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) { for (let i = 0; i < combination.length; ++i) {
let matType = combination[i][0]; let matType = combination[i][0];
let from = combination[i][1]; let from = combination[i][1];
let params;
if (type == "area") {
let scale = combination[i][2]; let scale = combination[i][2];
from.width = (Math.floor(from.width/scale))*scale; params = { from: from, scale: scale, matType: matType, modeType: type };
from.height = (Math.floor(from.height/scale))*scale; } else {
let to = { let to = combination[i][2];
width: from.width/scale, params = { from: from, to: to, matType: matType, modeType: type};
height: from.height/scale}; // for params print
suite.add('resize', function() {
cv.resize(src, dst, dst.size(), 0, 0, cv.INTER_AREA);
}, {
'setup': function() {
let from = this.params.from;
let scale = this.params.scale;
let matType = cv[this.params.matType];
let src = new cv.Mat(from, matType);
let dst = new cv.Mat(from.height/scale, from.width/scale, matType);
},
'teardown': function() {
src.delete();
dst.delete();
}
});
// set init params
let index = suite.length - 1;
suite[index].params = {
from: from,
scale: scale,
matType: matType
};
}
}
function decodeParams2Case(suite, params) {
let sizeString = (params.match(/[0-9]+x[0-9]+/g) || []).slice(0, 2).toString();
let sizes = (sizeString.match(/[0-9]+/g) || []);
let size1Str = sizes.slice(0, 2).toString();
let size2Str = sizes.slice(2, 5).toString();
let matType = (params.match(/CV\_[0-9]+[A-z][A-z][0-9]/) || []).toString();
let size1 = cvtStr2cvSize(size1Str);
let size2 = cvtStr2cvSize(size2Str);
// check if the params match and add case
for (let i = 0; i < combinations.length; ++i) {
let combination = combinations[i];
for (let j = 0; j < combination.length; ++j) {
if (matType === combination[j][0] && size1 === combination[j][1] && size2 === combination[j][2]) {
resizeFunc[i](suite, [combination[j]]);
}
}
}
}
function log(message) {
console.log(message);
if (!isNodeJs) {
logElement.innerHTML += `\n${'\t'.repeat(1) + message}`;
}
} }
addKernelCase(suite, params, type, addResizeCase)
function setBenchmarkSuite(suite) {
suite
// add listeners
.on('cycle', function(event) {
++currentCaseId;
let params = event.target.params;
let matType = params.matType;
let size1 = params.from;
let size2 = params.to;
log(`=== ${event.target.name} ${currentCaseId} ===`);
log(`params: (${matType},${parseInt(size1.width)}x${parseInt(size1.height)},`+
`${parseInt(size2.width)}x${parseInt(size2.height)})`);
log('elapsed time:' +String(event.target.times.elapsed*1000)+' ms');
log('mean time:' +String(event.target.stats.mean*1000)+' ms');
log('stddev time:' +String(event.target.stats.deviation*1000)+' ms');
log(String(event.target));
})
.on('error', function(event) { log(`test case ${event.target.name} failed`); })
.on('complete', function(event) {
log(`\n ###################################`)
log(`Finished testing ${event.currentTarget.length} cases \n`);
if (!isNodeJs) {
runButton.removeAttribute('disabled');
runButton.setAttribute('class', 'btn btn-primary');
runButton.innerHTML = 'Run';
} }
});
} }
function genBenchmarkCase(paramsContent) { function genBenchmarkCase(paramsContent) {
@ -225,19 +110,28 @@ cv.onRuntimeInitialized = () => {
currentCaseId = 0; currentCaseId = 0;
if (/\(\w+,[\ ]*[0-9]+x[0-9]+,[\ ]*[0-9]+x[0-9]+\)/g.test(paramsContent.toString())) { if (/\(\w+,[\ ]*[0-9]+x[0-9]+,[\ ]*[0-9]+x[0-9]+\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\(\w+,[\ ]*[0-9]+x[0-9]+,[\ ]*[0-9]+x[0-9]+\)/g)[0]; let params = paramsContent.toString().match(/\(\w+,[\ ]*[0-9]+x[0-9]+,[\ ]*[0-9]+x[0-9]+\)/g)[0];
decodeParams2Case(suite, params); let paramObjs = [];
paramObjs.push({name:"matType", value:"", reg:["/CV\_[0-9]+[A-z][A-z][0-9]/"], index:0});
paramObjs.push({name:"size1", value:"", reg:[""], index:1});
paramObjs.push({name:"size2", value:"", reg:[""], index:2});
let locationList = decodeParams2Case(params, paramObjs,combinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
addResizeModeCase(suite, [combinations[first][second]], "linear");
}
} else { } else {
log("no filter or getting invalid params, run all the cases"); log("no filter or getting invalid params, run all the cases");
addResizeUpLinearCase(suite, combiUpLinear); addResizeModeCase(suite, combiUpLinear, "linear");
addResizeDownLinearCase(suite, combiDownLinear); addResizeModeCase(suite, combiDownLinear, "linear");
} }
setBenchmarkSuite(suite); setBenchmarkSuite(suite, "resize", currentCaseId);
log(`Running ${totalCaseNum} tests from Resize`); log(`Running ${totalCaseNum} tests from Resize`);
suite.run({ 'async': true }); // run the benchmark suite.run({ 'async': true }); // run the benchmark
} }
// init // init
let resizeFunc = [addResizeUpLinearCase, addResizeDownLinearCase];//, addResizeAreaFastCase];
let combinations = [combiUpLinear, combiDownLinear];//, combiAreaFast]; let combinations = [combiUpLinear, combiDownLinear];//, combiAreaFast];
// set test filter params // set test filter params
@ -253,10 +147,19 @@ cv.onRuntimeInitialized = () => {
let paramsContent = paramsElement.value; let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent); genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) { if (totalCaseNum !== 0) {
runButton.setAttribute("disabled", "disabled"); disableButton();
runButton.setAttribute('class', 'btn btn-primary disabled');
runButton.innerHTML = "Running";
} }
} }
} }
}; };
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenCV.js Performance Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
font-size: 13px;
}
.top-margin {
margin-top:10px;
}
h1, h4 {
margin: 24px 0 0;
}
h1 {
font-size: 2.0em;
}
h4 {
font-size: 1.2em;
}
pre {
font-family: 'Consolas', 'Monaco', monospace, serif;
font-size: 12px;
tab-size: 2;
}
input[type=checkbox] {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container" id="container">
<div class="row">
<div class="col-12">
<h1>OpenCV.js Performance Test</h1>
<div>
<h4>Modules</h4>
<h7>Image Processing</h7>
</div>
<div>
<h4>Kernels</h4>
<h7>Scharr</h7>
</div>
<div>
<h4>Parameters Filter</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (640x480, CV_16SC1, (0,1), BORDER_REPLICATE)
</div>
<div class='row labels-wrapper' id='labelitem'></div>
<div class="row top-margin">
</div>
<div>
<button type="button" id="runButton" class="btn btn-primary disabled" disabled="disabled">Loading</button>
(It will take several minutes)</div>
<div class="row top-margin">
</div>
<div>
<pre id="log"></pre>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js"></script>
<script src="../../opencv.js" type="text/javascript"></script>
<script src="../base.js"></script>
<script src="../perf_helpfunc.js"></script>
<script src="./perf_scharr.js"></script>
</body>
</html>

@ -0,0 +1,156 @@
const isNodeJs = (typeof window) === 'undefined'? true : false;
if (isNodeJs) {
var Benchmark = require('benchmark');
var cv = require('../../opencv');
var HelpFunc = require('../perf_helpfunc');
var Base = require('../base');
} else {
var paramsElement = document.getElementById('params');
var runButton = document.getElementById('runButton');
var logElement = document.getElementById('log');
}
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.getCvSize();
} else {
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
const ScharrSize = [cvSize.szODD, cvSize.szQVGA, cvSize.szVGA];
const Scharrdxdy = ["(1,0)", "(0,1)"];
const BorderType3x3 = ["BORDER_REPLICATE", "BORDER_CONSTANT"];
const BorderType3x3ROI = ["BORDER_DEFAULT", "BORDER_REPLICATE|BORDER_ISOLATED", "BORDER_CONSTANT|BORDER_ISOLATED"];
const combiScharrBorder3x3 = combine(ScharrSize, ["CV_16SC1", "CV_32FC1"], Scharrdxdy, BorderType3x3);
const combiScharrBorder3x3ROI = combine(ScharrSize, ["CV_16SC1", "CV_32FC1"], Scharrdxdy, BorderType3x3ROI);
function addScharrCase(suite, type) {
suite.add('scharr', function() {
cv.Scharr(src, dst, ddepth, dx, dy, 1, 0, borderType);
}, {
'setup': function() {
let size = this.params.size;
let ddepth = cv[this.params.ddepth];
let dxdy = this.params.dxdy;
let type = this.params.type;
let src, dst;
if (type == 0) {
src = new cv.Mat(size[1], size[0], cv.CV_8U);
dst = new cv.Mat(size[1], size[0], ddepth);
} else {
src = new cv.Mat(size[1]+10, size[0]+10, cv.CV_8U);
dst = new cv.Mat(size[1]+10, size[0]+10, ddepth);
src = src.colRange(5, size[0]+5);
src = src.rowRange(5, size[1]+5);
dst = dst.colRange(5, size[0]+5);
dst = dst.rowRange(5, size[1]+5);
}
let dx = parseInt(dxdy[1]);
let dy = parseInt(dxdy[3]);
let borderTypeArray = this.params.borderType;
let borderType;
if (borderTypeArray.length == 1) {
borderType = cv[borderTypeArray[0]];
} else {
borderType = cv[borderTypeArray[0]] | cv[borderTypeArray[1]];
}
},
'teardown': function() {
src.delete();
dst.delete();
}
});
}
function addScharrModeCase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let ddepth = combination[i][1];
let dxdy = combination[i][2];
let borderType = combination[i][3];
let sizeArray = [size.width, size.height];
let borderTypeArray = borderType.split("|");
let params = {size: sizeArray, ddepth: ddepth, dxdy: dxdy, borderType:borderTypeArray, type:type};
addKernelCase(suite, params, type, addScharrCase);
}
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
let params = "";
let paramObjs = [];
paramObjs.push({name:"size", value:"", reg:[""], index:0});
paramObjs.push({name:"ddepth", value:"", reg:["/CV\_[0-9]+[FSUfsu]C1/g"], index:1});
paramObjs.push({name:"dxdy", value:"", reg:["/\\([0-2],[0-2]\\)/"], index:2});
if (/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\)/g.test(paramsContent.toString())) {
params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\)/g)[0];
paramObjs.push({name:"boderType", value:"", reg:["/BORDER\_\\w+/"], index:3});
} else if (/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\|\w+\)/g.test(paramsContent.toString())) {
params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\|\w+\)/g)[0];
paramObjs.push({name:"boderType", value:"", reg:["/BORDER\_\\w+\\|BORDER\_\\w+/"], index:3});
}
if (params != ""){
let locationList = decodeParams2Case(params, paramObjs,scharrCombinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
addScharrModeCase(suite, [scharrCombinations[first][second]], first);
}
} else {
log("no filter or getting invalid params, run all the cases");
addScharrModeCase(suite, combiScharrBorder3x3, 0);
addScharrModeCase(suite, combiScharrBorder3x3ROI, 1);
}
setBenchmarkSuite(suite, "scharr", currentCaseId);
log(`Running ${totalCaseNum} tests from Scharr`);
suite.run({ 'async': true }); // run the benchmark
}
let scharrCombinations = [combiScharrBorder3x3, combiScharrBorder3x3ROI];
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\)/g)[0];
} else if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\|\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\|\w+\)/g)[0];
}
genBenchmarkCase(paramsContent);
} else {
runButton.onclick = function() {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
disableButton();
}
}
}
};
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenCV.js Performance Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
font-size: 13px;
}
.top-margin {
margin-top:10px;
}
h1, h4 {
margin: 24px 0 0;
}
h1 {
font-size: 2.0em;
}
h4 {
font-size: 1.2em;
}
pre {
font-family: 'Consolas', 'Monaco', monospace, serif;
font-size: 12px;
tab-size: 2;
}
input[type=checkbox] {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container" id="container">
<div class="row">
<div class="col-12">
<h1>OpenCV.js Performance Test</h1>
<div>
<h4>Modules</h4>
<h7>Image Processing</h7>
</div>
<div>
<h4>Kernels</h4>
<h7>Sobel</h7>
</div>
<div>
<h4>Parameters Filter</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (640x480, CV_16SC1, (0,1), BORDER_REPLICATE)
</div>
<div class='row labels-wrapper' id='labelitem'></div>
<div class="row top-margin">
</div>
<div>
<button type="button" id="runButton" class="btn btn-primary disabled" disabled="disabled">Loading</button>
(It will take several minutes)</div>
<div class="row top-margin">
</div>
<div>
<pre id="log"></pre>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js"></script>
<script src="../../opencv.js" type="text/javascript"></script>
<script src="../base.js"></script>
<script src="../perf_helpfunc.js"></script>
<script src="./perf_sobel.js"></script>
</body>
</html>

@ -0,0 +1,170 @@
const isNodeJs = (typeof window) === 'undefined'? true : false;
if (isNodeJs) {
var Benchmark = require('benchmark');
var cv = require('../../opencv');
var HelpFunc = require('../perf_helpfunc');
var Base = require('../base');
} else {
var paramsElement = document.getElementById('params');
var runButton = document.getElementById('runButton');
var logElement = document.getElementById('log');
}
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.getCvSize();
} else {
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
const SobelSize = [cvSize.szODD, cvSize.szQVGA, cvSize.szVGA];
const Sobel3x3dxdy = ["(0,1)", "(1,0)", "(1,1)", "(0,2)", "(2,0)", "(2,2)"];
const Sobeldxdy = ["(0,1)", "(1,0)", "(1,1)", "(0,2)", "(2,0)"];
const BorderType3x3 = ["BORDER_REPLICATE", "BORDER_CONSTANT"];
const BorderType3x3ROI = ["BORDER_DEFAULT", "BORDER_REPLICATE|BORDER_ISOLATED", "BORDER_CONSTANT|BORDER_ISOLATED"];
const BorderType = ["BORDER_REPLICATE", "BORDER_CONSTANT", "BORDER_REFLECT", "BORDER_REFLECT101"];
const BorderTypeROI = ["BORDER_DEFAULT", "BORDER_REPLICATE|BORDER_ISOLATED", "BORDER_CONSTANT|BORDER_ISOLATED", "BORDER_REFLECT|BORDER_ISOLATED", "BORDER_REFLECT101|BORDER_ISOLATED"]
const combiSobelBorder3x3 = combine(SobelSize, ["CV_16SC1", "CV_32FC1"], Sobel3x3dxdy, BorderType3x3);
const combiSobelBorder3x3ROI = combine(SobelSize, ["CV_16SC1", "CV_32FC1"], Sobel3x3dxdy, BorderType3x3ROI);
const combiSobelBorder5x5 = combine(SobelSize, ["CV_16SC1", "CV_32FC1"], Sobeldxdy, BorderType);
const combiSobelBorder5x5ROI = combine(SobelSize, ["CV_16SC1", "CV_32FC1"], Sobeldxdy, BorderTypeROI);
function addSobelCase(suite, type) {
suite.add('sobel', function() {
cv.Sobel(src, dst, ddepth, dx, dy, ksize, 1, 0, borderType);
}, {
'setup': function() {
let size = this.params.size;
let ddepth = cv[this.params.ddepth];
let dxdy = this.params.dxdy;
let ksize = this.params.ksize;
let type = this.params.type;
let src, dst;
if (type %2 == 0) {
src = new cv.Mat(size[1], size[0], cv.CV_8U);
dst = new cv.Mat(size[1], size[0], ddepth);
} else {
src = new cv.Mat(size[1]+10, size[0]+10, cv.CV_8U);
dst = new cv.Mat(size[1]+10, size[0]+10, ddepth);
src = src.colRange(5, size[0]+5);
src = src.rowRange(5, size[1]+5);
dst = dst.colRange(5, size[0]+5);
dst = dst.rowRange(5, size[1]+5);
}
let dx = parseInt(dxdy[1]);
let dy = parseInt(dxdy[3]);
let borderTypeArray = this.params.borderType;
let borderType;
if (borderTypeArray.length == 1) {
borderType = cv[borderTypeArray[0]];
} else {
borderType = cv[borderTypeArray[0]] | cv[borderTypeArray[1]];
}
},
'teardown': function() {
src.delete();
dst.delete();
}
});
}
function addSobelModeCase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let ddepth = combination[i][1];
let dxdy = combination[i][2];
let borderType = combination[i][3];
let sizeArray = [size.width, size.height];
let ksize;
if (type < 2) {
ksize = 3;
} else {
ksize = 5;
}
let borderTypeArray = borderType.split("|");
let params = {size: sizeArray, ddepth: ddepth, dxdy: dxdy, ksize:ksize, borderType:borderTypeArray, type:type};
addKernelCase(suite, params, type, addSobelCase);
}
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
let params = "";
let paramObjs = [];
paramObjs.push({name:"size", value:"", reg:[""], index:0});
paramObjs.push({name:"ddepth", value:"", reg:["/CV\_[0-9]+[FSUfsu]C1/g"], index:1});
paramObjs.push({name:"dxdy", value:"", reg:["/\\([0-2],[0-2]\\)/"], index:2});
if (/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\)/g.test(paramsContent.toString())) {
params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\)/g)[0];
paramObjs.push({name:"boderType", value:"", reg:["/BORDER\_\\w+/"], index:3});
} else if (/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\|\w+\)/g.test(paramsContent.toString())) {
params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\|\w+\)/g)[0];
paramObjs.push({name:"boderType", value:"", reg:["/BORDER\_\\w+\\|BORDER\_\\w+/"], index:3});
}
if (params != ""){
let locationList = decodeParams2Case(params, paramObjs,sobelCombinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
addSobelModeCase(suite, [sobelCombinations[first][second]], first);
}
} else {
log("no filter or getting invalid params, run all the cases");
addSobelModeCase(suite, combiSobelBorder3x3, 0);
addSobelModeCase(suite, combiSobelBorder3x3ROI, 1);
addSobelModeCase(suite, combiSobelBorder5x5, 2);
addSobelModeCase(suite, combiSobelBorder5x5ROI, 3);
}
setBenchmarkSuite(suite, "sobel", currentCaseId);
log(`Running ${totalCaseNum} tests from Sobel`);
suite.run({ 'async': true }); // run the benchmark
}
let sobelCombinations = [combiSobelBorder3x3, combiSobelBorder3x3ROI, combiSobelBorder5x5, combiSobelBorder5x5ROI];
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\)/g)[0];
} else if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\|\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\([0-2],[0-2]\),[\ ]*\w+\|\w+\)/g)[0];
}
genBenchmarkCase(paramsContent);
} else {
runButton.onclick = function() {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
disableButton();
}
}
}
};
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -11,17 +11,17 @@ if (isNodeJs) {
var logElement = document.getElementById('log'); var logElement = document.getElementById('log');
} }
cv.onRuntimeInitialized = () => { function perf() {
console.log('opencv.js loaded'); console.log('opencv.js loaded');
if (isNodeJs) { if (isNodeJs) {
global.cv = cv; global.cv = cv;
global.combine = HelpFunc.combine; global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize; global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.cvSize; global.cvSize = Base.getCvSize();
} else { } else {
runButton.removeAttribute('disabled'); enableButton();
runButton.setAttribute('class', 'btn btn-primary'); cvSize = getCvSize();
runButton.innerHTML = 'Run';
} }
let totalCaseNum, currentCaseId; let totalCaseNum, currentCaseId;
@ -32,24 +32,30 @@ cv.onRuntimeInitialized = () => {
const combiSizeMatTypeThreshType = combine(typicalMatSizes, matTypes, threshTypes); const combiSizeMatTypeThreshType = combine(typicalMatSizes, matTypes, threshTypes);
const combiSizeOnly = combine(typicalMatSizes, ['CV_8UC1'], ['THRESH_BINARY|THRESH_OTSU']); const combiSizeOnly = combine(typicalMatSizes, ['CV_8UC1'], ['THRESH_BINARY|THRESH_OTSU']);
function addSizeMatTypeThreshTypeCase(suite, combination) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let matSize = combination[i][0];
let matType = combination[i][1];
let threshType = combination[i][2];
function addThresholdCase(suite, type) {
suite.add('threshold', function() { suite.add('threshold', function() {
if (type == "sizeonly") {
cv.threshold(src, dst, threshold, thresholdMax, cv.THRESH_BINARY|cv.THRESH_OTSU);
} else {
cv.threshold(src, dst, threshold, thresholdMax, threshType); cv.threshold(src, dst, threshold, thresholdMax, threshType);
}
}, { }, {
'setup': function() { 'setup': function() {
let matSize = this.params.matSize; let matSize = this.params.matSize;
let matType = cv[this.params.matType]; let type = this.params.modeType;
let threshType = cv[this.params.threshType]; let src, dst, matType, threshType;
if (type == "sizeonly") {
src = new cv.Mat(matSize, cv.CV_8UC1);
dst = new cv.Mat(matSize, cv.CV_8UC1);
} else {
matType = cv[this.params.matType];
threshType = cv[this.params.threshType];
src = new cv.Mat(matSize, matType);
dst = new cv.Mat(matSize, matType);
}
let threshold = 127.0; let threshold = 127.0;
let thresholdMax = 210.0; let thresholdMax = 210.0;
let src = new cv.Mat(matSize, matType);
let dst = new cv.Mat(matSize, matType);
let srcView = src.data; let srcView = src.data;
srcView[0] = 0; srcView[0] = 0;
srcView[1] = 100; srcView[1] = 100;
@ -60,145 +66,71 @@ cv.onRuntimeInitialized = () => {
dst.delete(); dst.delete();
} }
}); });
// set init params
let index = suite.length - 1;
suite[index].params = {
matSize: matSize,
matType: matType,
threshType: threshType
};
}
} }
function addSizeOnlyCase(suite, combination) { function addThresholdModecase(suite, combination, type) {
totalCaseNum += combination.length; totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) { for (let i = 0; i < combination.length; ++i) {
let matSize = combination[i][0]; let matSize = combination[i][0];
let matType = 'CV_8UC1';
suite.add('threshold', function() { let threshType = 'THRESH_BINARY|THRESH_OTSU';
cv.threshold(src, dst, threshold, thresholdMax, cv.THRESH_BINARY|cv.THRESH_OTSU); if (type != "sizeonly") {
}, { matType = combination[i][1];
'setup': function() { threshType = combination[i][2];
let matSize = this.params.matSize;
let threshold = 127.0;
let thresholdMax = 210.0;
let src = new cv.Mat(matSize, cv.CV_8UC1);
let dst = new cv.Mat(matSize, cv.CV_8UC1);
let srcView = src.data;
srcView[0] = 0;
srcView[1] = 100;
srcView[2] = 200;
},
'teardown': function() {
src.delete();
dst.delete();
}
});
// set init params
let index = suite.length - 1;
suite[index].params = {
matSize: matSize,
matType: 'CV_8UC1',
threshType: 'THRESH_BINARY|THRESH_OTSU'
};
}
}
function decodeParams2Case(suite, params, isSizeOnly) {
let sizeString = params.match(/[0-9]+x[0-9]+/g).toString();
let sizes = sizeString.match(/[0-9]+/g);
let size1Str = sizes.slice(0, 2).toString();
let matSize = cvtStr2cvSize(size1Str);
let matType, threshType;
if (isSizeOnly) {
matType = 'CV_8UC1';
threshType = 'THRESH_BINARY|THRESH_OTSU';
} else {
matType = (params.match(/CV\_[0-9]+[A-z][A-z][0-9]/) || []).toString();
threshType = (params.match(/THRESH\_[A-z]+\_?[A-z]*/) || []).toString();
}
// check if the params match and add case
for (let i = 0; i < combinations.length; ++i) {
let combination = combinations[i];
for (let j = 0; j < combination.length; ++j) {
if (matSize === combination[j][0] && matType === combination[j][1] && threshType === combination[j][2]) {
thresholdFunc[i](suite, [combination[j]]);
}
}
}
} }
let params = {matSize: matSize, matType: matType, threshType: threshType, modeType: type};
function log(message) { addKernelCase(suite, params, type, addThresholdCase);
console.log(message);1
if (!isNodeJs) {
logElement.innerHTML += `\n${'\t'.repeat(1) + message}`;
} }
} }
function setBenchmarkSuite(suite) {
suite
// add listeners
.on('cycle', function(event) {
++currentCaseId;
let params = event.target.params;
let matSize = params.matSize;
let matType = params.matType;
let threshType = params.threshType;
log(`=== ${event.target.name} ${currentCaseId} ===`);
log(`params: (${parseInt(matSize.width)}x${parseInt(matSize.height)},`+
`${matType},${threshType})`);
log('elapsed time:' +String(event.target.times.elapsed*1000)+' ms');
log('mean time:' +String(event.target.stats.mean*1000)+' ms');
log('stddev time:' +String(event.target.stats.deviation*1000)+' ms');
log(String(event.target));
})
.on('error', function(event) { log(`test case ${event.target.name} failed`); })
.on('complete', function(event) {
log(`\n ###################################`)
log(`Finished testing ${event.currentTarget.length} cases \n`);
if (!isNodeJs) {
runButton.removeAttribute('disabled');
runButton.setAttribute('class', 'btn btn-primary');
runButton.innerHTML = 'Run';
}
});
}
function genBenchmarkCase(paramsContent) { function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite; let suite = new Benchmark.Suite;
totalCaseNum = 0; totalCaseNum = 0;
currentCaseId = 0; currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\w+\)/g.test(paramsContent.toString())) { let params = "";
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\w+\)/g)[0]; let paramObjs = [];
let isSizeOnly = 0; paramObjs.push({name:"size", value:"", reg:[""], index:0});
decodeParams2Case(suite, params, isSizeOnly);
if (/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*THRESH\_\w+\)/g.test(paramsContent.toString())) {
params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*THRESH\_\w+\)/g)[0];
paramObjs.push({name:"matType", value:"", reg:["/CV\_[0-9]+[A-z][A-z][0-9]/"], index:1});
paramObjs.push({name:"threshType", value:"", reg:["/THRESH\_[A-z]+\_?[A-z]*/"], index:2});
} else if (/[\ ]*[0-9]+x[0-9]+[\ ]*/g.test(paramsContent.toString())) { } else if (/[\ ]*[0-9]+x[0-9]+[\ ]*/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/[\ ]*[0-9]+x[0-9]+[\ ]*/g)[0]; params = paramsContent.toString().match(/[\ ]*[0-9]+x[0-9]+[\ ]*/g)[0];
let isSizeOnly = 1; paramObjs.push({name:"matType", value:"CV_8UC1", reg:[""], index:1});
decodeParams2Case(suite, params, isSizeOnly); paramObjs.push({name:"threshType", value:"THRESH_BINARY|THRESH_OTSU", reg:[""], index:2});
}
if(params != ""){
let locationList = decodeParams2Case(params, paramObjs,combinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
if (first == 0) {
addThresholdModecase(suite, [combinations[first][second]], "normal");
} else {
addThresholdModecase(suite, [combinations[first][second]], "sizeonly");
}
} }
else { } else {
log("no filter or getting invalid params, run all the cases"); log("no filter or getting invalid params, run all the cases");
addSizeMatTypeThreshTypeCase(suite, combiSizeMatTypeThreshType); addThresholdModecase(suite, combiSizeMatTypeThreshType, "normal");
addSizeOnlyCase(suite, combiSizeOnly); addThresholdModecase(suite, combiSizeOnly, "sizeonly");
} }
setBenchmarkSuite(suite); setBenchmarkSuite(suite, "threshold", currentCaseId);
log(`Running ${totalCaseNum} tests from Threshold`); log(`Running ${totalCaseNum} tests from Threshold`);
suite.run({ 'async': true }); // run the benchmark suite.run({ 'async': true }); // run the benchmark
} }
// init // init
let thresholdFunc = [addSizeMatTypeThreshTypeCase, addSizeOnlyCase];
let combinations = [combiSizeMatTypeThreshType, combiSizeOnly]; let combinations = [combiSizeMatTypeThreshType, combiSizeOnly];
// set test filter params // set test filter params
if (isNodeJs) { if (isNodeJs) {
const args = process.argv.slice(2); const args = process.argv.slice(2);
let paramsContent = ''; let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\w+\)/g.test(args.toString())) { if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*THRESH\_\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\w+\)/g)[0]; paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*CV\_\w+,[\ ]*THRESH\_\w+\)/g)[0];
} else if (/--test_param_filter=[\ ]*[0-9]+x[0-9]+[\ ]*/g.test(args.toString())) { } else if (/--test_param_filter=[\ ]*[0-9]+x[0-9]+[\ ]*/g.test(args.toString())) {
paramsContent = args.toString().match(/[\ ]*[0-9]+x[0-9]+[\ ]*/g)[0]; paramsContent = args.toString().match(/[\ ]*[0-9]+x[0-9]+[\ ]*/g)[0];
} }
@ -208,10 +140,19 @@ cv.onRuntimeInitialized = () => {
let paramsContent = paramsElement.value; let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent); genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) { if (totalCaseNum !== 0) {
runButton.setAttribute("disabled", "disabled"); disableButton();
runButton.setAttribute('class', 'btn btn-primary disabled');
runButton.innerHTML = "Running";
} }
} }
} }
}; };
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenCV.js Performance Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
font-size: 13px;
}
.top-margin {
margin-top:10px;
}
h1, h4 {
margin: 24px 0 0;
}
h1 {
font-size: 2.0em;
}
h4 {
font-size: 1.2em;
}
pre {
font-family: 'Consolas', 'Monaco', monospace, serif;
font-size: 12px;
tab-size: 2;
}
input[type=checkbox] {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container" id="container">
<div class="row">
<div class="col-12">
<h1>OpenCV.js Performance Test</h1>
<div>
<h4>Modules</h4>
<h7>Image Processing</h7>
</div>
<div>
<h4>Kernels</h4>
<h7>warpAffine</h7>
</div>
<div>
<h4>Parameters Filter</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (640x480, INTER_NEAREST, BORDER_CONSTANT)
</div>
<div class='row labels-wrapper' id='labelitem'></div>
<div class="row top-margin">
</div>
<div>
<button type="button" id="runButton" class="btn btn-primary disabled" disabled="disabled">Loading</button>
(It will take several minutes)</div>
<div class="row top-margin">
</div>
<div>
<pre id="log"></pre>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js"></script>
<script src="../../opencv.js" type="text/javascript"></script>
<script src="../base.js"></script>
<script src="../perf_helpfunc.js"></script>
<script src="./perf_warpAffine.js"></script>
</body>
</html>

@ -0,0 +1,130 @@
const isNodeJs = (typeof window) === 'undefined'? true : false;
if (isNodeJs) {
var Benchmark = require('benchmark');
var cv = require('../../opencv');
var HelpFunc = require('../perf_helpfunc');
var Base = require('../base');
} else {
var paramsElement = document.getElementById('params');
var runButton = document.getElementById('runButton');
var logElement = document.getElementById('log');
}
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.getCvSize();
} else {
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
const WarpAffineSize = [cvSize.szVGA, cvSize.sz720p, cvSize.sz1080p];
const InterType = ["INTER_NEAREST", "INTER_LINEAR"];
const BorderMode = ["BORDER_CONSTANT", "BORDER_REPLICATE"]
const combiWarpAffine = combine(WarpAffineSize, InterType, BorderMode);
function addWarpAffineCase(suite, type) {
suite.add('warpAffine', function() {
cv.warpAffine(src, dst, warpMat, sz, interType, borderMode, borderColor);
}, {
'setup': function() {
let sz = this.params.size;
let interType = cv[this.params.interType];
let borderMode = cv[this.params.borderMode];
let srcSize = new cv.Size(512, 512);
let borderColor = new cv.Scalar.all(150);
let src = new cv.Mat(srcSize, cv.CV_8UC4);
let dst = new cv.Mat(sz, cv.CV_8UC4);
fillGradient(cv, src);
if (borderMode == cv.BORDER_CONSTANT) {
smoothBorder(cv, src, borderMode, 1);
}
let point = new cv.Point(src.cols/2.0, src.rows/2.0);
let warpMat = cv.getRotationMatrix2D(point, 30.0, 2.2);
},
'teardown': function() {
src.delete();
dst.delete();
warpMat.delete();
}
});
}
function addWarpAffineModeCase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let interType = combination[i][1];
let borderMode = combination[i][2];
let params = {size: size, interType:interType, borderMode:borderMode};
addKernelCase(suite, params, type, addWarpAffineCase);
}
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*INTER\_\w+,[\ ]*BORDER\_\w+\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*INTER\_\w+,[\ ]*BORDER\_\w+\)/g)[0];
let paramObjs = [];
paramObjs.push({name:"size", value:"", reg:[""], index:0});
paramObjs.push({name:"interType", value: "", reg:["/INTER\_\\w+/"], index:1});
paramObjs.push({name:"borderMode", value: "", reg:["/BORDER\_\\w+/"], index:2});
let locationList = decodeParams2Case(params, paramObjs, warpAffineCombinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
addWarpAffineModeCase(suite, [warpAffineCombinations[first][second]], first);
}
} else {
log("no filter or getting invalid params, run all the cases");
addWarpAffineModeCase(suite, combiWarpAffine, 0);
}
setBenchmarkSuite(suite, "warpAffine", currentCaseId);
log(`Running ${totalCaseNum} tests from warpAffine`);
suite.run({ 'async': true }); // run the benchmark
}
let warpAffineCombinations = [combiWarpAffine];
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*INTER\_\w+,[\ ]*BORDER\_\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*INTER\_\w+,[\ ]*BORDER\_\w+\)/g)[0];
}
genBenchmarkCase(paramsContent);
} else {
runButton.onclick = function() {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
disableButton();
}
}
}
};
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenCV.js Performance Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
font-size: 13px;
}
.top-margin {
margin-top:10px;
}
h1, h4 {
margin: 24px 0 0;
}
h1 {
font-size: 2.0em;
}
h4 {
font-size: 1.2em;
}
pre {
font-family: 'Consolas', 'Monaco', monospace, serif;
font-size: 12px;
tab-size: 2;
}
input[type=checkbox] {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container" id="container">
<div class="row">
<div class="col-12">
<h1>OpenCV.js Performance Test</h1>
<div>
<h4>Modules</h4>
<h7>Image Processing</h7>
</div>
<div>
<h4>Kernels</h4>
<h7>warpPerspective</h7>
</div>
<div>
<h4>Parameters Filter</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (640x480, INTER_NEAREST, BORDER_CONSTANT)
</div>
<div class='row labels-wrapper' id='labelitem'></div>
<div class="row top-margin">
</div>
<div>
<button type="button" id="runButton" class="btn btn-primary disabled" disabled="disabled">Loading</button>
(It will take several minutes)</div>
<div class="row top-margin">
</div>
<div>
<pre id="log"></pre>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js"></script>
<script src="../../opencv.js" type="text/javascript"></script>
<script src="../base.js"></script>
<script src="../perf_helpfunc.js"></script>
<script src="./perf_warpPerspective.js"></script>
</body>
</html>

@ -0,0 +1,143 @@
const isNodeJs = (typeof window) === 'undefined'? true : false;
if (isNodeJs) {
var Benchmark = require('benchmark');
var cv = require('../../opencv');
var HelpFunc = require('../perf_helpfunc');
var Base = require('../base');
} else {
var paramsElement = document.getElementById('params');
var runButton = document.getElementById('runButton');
var logElement = document.getElementById('log');
}
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.getCvSize();
} else {
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
const WarpPersSize = [cvSize.szVGA, cvSize.sz720p, cvSize.sz1080p];
const InterType = ["INTER_NEAREST", "INTER_LINEAR"];
const BorderMode = ["BORDER_CONSTANT", "BORDER_REPLICATE"]
const combiWarpPers = combine(WarpPersSize, InterType, BorderMode);
function addWarpPerspectiveCase(suite, type) {
suite.add('warpPerspective', function() {
cv.warpPerspective(src, dst, warpMat, sz, interType, borderMode, borderColor);
}, {
'setup': function() {
let sz = this.params.size;
let interType = cv[this.params.interType];
let borderMode = cv[this.params.borderMode];
let srcSize = new cv.Size(512, 512);
let borderColor = new cv.Scalar.all(150);
let src = new cv.Mat(srcSize, cv.CV_8UC4);
let dst = new cv.Mat(sz, cv.CV_8UC4);
fillGradient(cv, src);
if (borderMode == cv.BORDER_CONSTANT) {
smoothBorder(cv, src, borderMode, 1);
}
let rotMat = cv.getRotationMatrix2D(new cv.Point(src.cols/2.0, src.rows/2.0), 30.0, 2.2);
let warpMat = new cv.Mat(3, 3, cv.CV_64FC1);
for(r=0; r<2; r++) {
for(c=0; c<3; c++) {
view = warpMat.doublePtr(r,c)
view[0] = rotMat.doubleAt(r, c);
}
}
view = warpMat.doublePtr(2,0);
view[0] = 0.3/sz.width;
view = warpMat.doublePtr(2,1);
view[0] = 0.3/sz.height;
view = warpMat.doublePtr(2,2);
view[0] = 1;
},
'teardown': function() {
src.delete();
dst.delete();
warpMat.delete();
}
});
}
function addWarpPerspectiveModeCase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let size = combination[i][0];
let interType = combination[i][1];
let borderMode = combination[i][2];
let params = {size: size, interType:interType, borderMode:borderMode};
addKernelCase(suite, params, type, addWarpPerspectiveCase);
}
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*INTER\_\w+,[\ ]*BORDER\_\w+\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*INTER\_\w+,[\ ]*BORDER\_\w+\)/g)[0];
let paramObjs = [];
paramObjs.push({name:"size", value:"", reg:[""], index:0});
paramObjs.push({name:"interType", value: "", reg:["/INTER\_\\w+/"], index:1});
paramObjs.push({name:"borderMode", value: "", reg:["/BORDER\_\\w+/"], index:2});
let locationList = decodeParams2Case(params, paramObjs, warpPersCombinations);
for (let i = 0; i < locationList.length; i++){
let first = locationList[i][0];
let second = locationList[i][1];
addWarpPerspectiveModeCase(suite, [warpPersCombinations[first][second]], first);
}
} else {
log("no filter or getting invalid params, run all the cases");
addWarpPerspectiveModeCase(suite, combiWarpPers, 0);
}
setBenchmarkSuite(suite, "warpPerspective", currentCaseId);
log(`Running ${totalCaseNum} tests from warpPerspective`);
suite.run({ 'async': true }); // run the benchmark
}
let warpPersCombinations = [combiWarpPers];
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*INTER\_\w+,[\ ]*BORDER\_\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*INTER\_\w+,[\ ]*BORDER\_\w+\)/g)[0];
}
genBenchmarkCase(paramsContent);
} else {
runButton.onclick = function() {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
disableButton();
}
}
}
};
async function main() {
if (cv instanceof Promise) {
cv = await cv;
perf();
} else {
cv.onRuntimeInitialized = perf;
}
}
main();

@ -0,0 +1,96 @@
async function loadOpenCV(paths, onloadCallback) {
let OPENCV_URL = "";
let asmPath = "";
let wasmPath = "";
let simdPath = "";
let threadsPath = "";
let threadsSimdPath = "";
if(!(paths instanceof Object)) {
throw new Error("The first input should be a object that points the path to the OpenCV.js");
}
if ("asm" in paths) {
asmPath = paths["asm"];
}
if ("wasm" in paths) {
wasmPath = paths["wasm"];
}
if ("threads" in paths) {
threadsPath = paths["threads"];
}
if ("simd" in paths) {
simdPath = paths["simd"];
}
if ("threadsSimd" in paths) {
threadsSimdPath = paths["threadsSimd"];
}
let wasmSupported = !(typeof WebAssembly === 'undefined');
if (!wasmSupported && OPENCV_URL === "" && asmPath != "") {
OPENCV_URL = asmPath;
console.log("The OpenCV.js for Asm.js is loaded now");
} else if (!wasmSupported && asmPath == ""){
throw new Error("The browser supports the Asm.js only, but the path of OpenCV.js for Asm.js is empty");
}
let simdSupported = wasmSupported ? await wasmFeatureDetect.simd() : false;
let threadsSupported = wasmSupported ? await wasmFeatureDetect.threads() : false;
if (simdSupported && threadsSupported && threadsSimdPath != "") {
OPENCV_URL = threadsSimdPath;
console.log("The OpenCV.js with simd and threads optimization is loaded now");
} else if (simdSupported && simdPath != "") {
if (threadsSupported && threadsSimdPath === "") {
console.log("The browser supports simd and threads, but the path of OpenCV.js with simd and threads optimization is empty");
}
OPENCV_URL = simdPath;
console.log("The OpenCV.js with simd optimization is loaded now.");
} else if (threadsSupported && threadsPath != "") {
if (simdSupported && threadsSimdPath === "") {
console.log("The browser supports simd and threads, but the path of OpenCV.js with simd and threads optimization is empty");
}
OPENCV_URL = threadsPath;
console.log("The OpenCV.js with threads optimization is loaded now");
} else if (wasmSupported && wasmPath != "") {
if(simdSupported && threadsSupported) {
console.log("The browser supports simd and threads, but the path of OpenCV.js with simd and threads optimization is empty");
}
if (simdSupported) {
console.log("The browser supports simd optimization, but the path of OpenCV.js with simd optimization is empty");
}
if (threadsSupported) {
console.log("The browser supports threads optimization, but the path of OpenCV.js with threads optimization is empty");
}
OPENCV_URL = wasmPath;
console.log("The OpenCV.js for wasm is loaded now");
} else if (wasmSupported) {
console.log("The browser supports wasm, but the path of OpenCV.js for wasm is empty");
}
if (OPENCV_URL === "") {
throw new Error("No available OpenCV.js, please check your paths");
}
let script = document.createElement('script');
script.setAttribute('async', '');
script.setAttribute('type', 'text/javascript');
script.addEventListener('load', () => {
onloadCallback();
});
script.addEventListener('error', () => {
console.log('Failed to load opencv.js');
});
script.src = OPENCV_URL;
let node = document.getElementsByTagName('script')[0];
if (node.src != OPENCV_URL) {
node.parentNode.insertBefore(script, node);
}
}

@ -203,6 +203,9 @@ class Builder:
def build_doc(self): def build_doc(self):
execute(["make", "-j", str(multiprocessing.cpu_count()), "doxygen"]) execute(["make", "-j", str(multiprocessing.cpu_count()), "doxygen"])
def build_loader(self):
execute(["make", "-j", str(multiprocessing.cpu_count()), "opencv_js_loader"])
#=================================================================================================== #===================================================================================================
@ -223,6 +226,7 @@ if __name__ == "__main__":
parser.add_argument('--build_test', action="store_true", help="Build tests") parser.add_argument('--build_test', action="store_true", help="Build tests")
parser.add_argument('--build_perf', action="store_true", help="Build performance tests") parser.add_argument('--build_perf', action="store_true", help="Build performance tests")
parser.add_argument('--build_doc', action="store_true", help="Build tutorials") parser.add_argument('--build_doc', action="store_true", help="Build tutorials")
parser.add_argument('--build_loader', action="store_true", help="Build OpenCV.js loader")
parser.add_argument('--clean_build_dir', action="store_true", help="Clean build dir") parser.add_argument('--clean_build_dir', action="store_true", help="Clean build dir")
parser.add_argument('--skip_config', action="store_true", help="Skip cmake config") parser.add_argument('--skip_config', action="store_true", help="Skip cmake config")
parser.add_argument('--config_only', action="store_true", help="Only do cmake config") parser.add_argument('--config_only', action="store_true", help="Only do cmake config")
@ -294,6 +298,11 @@ if __name__ == "__main__":
log.info("=====") log.info("=====")
builder.build_doc() builder.build_doc()
if args.build_loader:
log.info("=====")
log.info("===== Building OpenCV.js loader")
log.info("=====")
builder.build_loader()
log.info("=====") log.info("=====")
log.info("===== Build finished") log.info("===== Build finished")
@ -318,3 +327,8 @@ if __name__ == "__main__":
opencvjs_tutorial_path = find_file("tutorial_js_root.html", os.path.join(builder.build_dir, "doc", "doxygen", "html")) opencvjs_tutorial_path = find_file("tutorial_js_root.html", os.path.join(builder.build_dir, "doc", "doxygen", "html"))
if check_file(opencvjs_tutorial_path): if check_file(opencvjs_tutorial_path):
log.info("OpenCV.js tutorials location: %s", opencvjs_tutorial_path) log.info("OpenCV.js tutorials location: %s", opencvjs_tutorial_path)
if args.build_loader:
opencvjs_loader_path = os.path.join(builder.build_dir, "bin", "loader.js")
if check_file(opencvjs_loader_path):
log.info("OpenCV.js loader location: %s", opencvjs_loader_path)

@ -236,8 +236,8 @@ class SiamRPNTracker:
img(np.ndarray): bgr based input image frame img(np.ndarray): bgr based input image frame
bbox: (x, y, w, h): bounding box bbox: (x, y, w, h): bounding box
""" """
x,y,h,w = bbox x, y, w, h = bbox
self.center_pos = np.array([x + (h - 1) / 2, y + (w - 1) / 2]) self.center_pos = np.array([x + (w - 1) / 2, y + (h - 1) / 2])
self.h = h self.h = h
self.w = w self.w = w
w_z = self.w + self.track_context_amount * np.add(h, w) w_z = self.w + self.track_context_amount * np.add(h, w)

Loading…
Cancel
Save