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. 31
      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. 374
      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. 227
      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. 231
      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. 6
      samples/dnn/siamrpnpp.py

@ -140,6 +140,7 @@ append_if_exist(Protobuf_SRCS
${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})
target_include_directories(libprotobuf SYSTEM PUBLIC $<BUILD_INTERFACE:${PROTOBUF_ROOT}/src>)
set_target_properties(libprotobuf

@ -32,6 +32,15 @@ source ./emsdk_env.sh
echo ${EMSCRIPTEN}
@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
--------------------------
@ -76,6 +85,31 @@ Building OpenCV.js from Source
python ./platforms/js/build_js.py build_wasm --build_wasm
@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.
For example:

@ -90,7 +90,7 @@ namespace cv { namespace debug_build_guard { } using namespace debug_build_guard
// keep current value (through OpenCV port file)
#elif defined __GNUC__ || (defined (__cpluscplus) && (__cpluscplus >= 201103))
#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__
#elif defined(__STDC_VERSION__) && (__STDC_VERSION >= 199901)
#define CV_Func __func__

@ -207,13 +207,7 @@ struct v_uint64x2
uint64 get0() const
{
#ifdef __wasm_unimplemented_simd128__
return (uint64)wasm_i64x2_extract_lane(val, 0);
#else
uint64 des[2];
wasm_v128_store(des, val);
return des[0];
#endif
}
v128_t val;
@ -235,13 +229,7 @@ struct v_int64x2
int64 get0() const
{
#ifdef __wasm_unimplemented_simd128__
return wasm_i64x2_extract_lane(val, 0);
#else
int64 des[2];
wasm_v128_store(des, val);
return des[0];
#endif
}
v128_t val;
@ -263,13 +251,7 @@ struct v_float64x2
double get0() const
{
#ifdef __wasm_unimplemented_simd128__
return wasm_f64x2_extract_lane(val, 0);
#else
double des[2];
wasm_v128_store(des, val);
return des[0];
#endif
}
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_int32x4, int, s32, i32x4, int)
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_int64x2, int64, s64, i64x2, int64)
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 ///////////////
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>
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 a1 = wasm_u64x2_shr(wasm_i64x2_add(a.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));
#else
fallback::v_uint64x2 a_(a), b_(b);
return fallback::v_rshr_pack<n>(a_, b_);
#endif
}
template<int n>
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 a1 = wasm_i64x2_shr(wasm_i64x2_add(a.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));
#else
fallback::v_int64x2 a_(a), b_(b);
return fallback::v_rshr_pack<n>(a_, b_);
#endif
}
template<int n>
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>
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 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);
@ -2148,15 +2106,10 @@ inline void v_rshr_pack_store(unsigned* ptr, const v_uint64x2& a)
for (int i=0; i<2; ++i) {
ptr[i] = t_ptr[i];
}
#else
fallback::v_uint64x2 _a(a);
fallback::v_rshr_pack_store<n>(ptr, _a);
#endif
}
template<int n>
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 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);
@ -2165,10 +2118,6 @@ inline void v_rshr_pack_store(int* ptr, const v_int64x2& a)
for (int i=0; i<2; ++i) {
ptr[i] = t_ptr[i];
}
#else
fallback::v_int64x2 _a(a);
fallback::v_rshr_pack_store<n>(ptr, _a);
#endif
}
template<int n>
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& g, const v_uint64x2& h)
{
#ifdef __wasm_unimplemented_simd128__
v128_t maxval = wasm_i32x4_splat(255);
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));
@ -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 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));
#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,
@ -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_mul)
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_sub)
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_mul)
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
#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,
v_uint64x2& c, v_uint64x2& d)
{
#ifdef __wasm_unimplemented_simd128__
v_uint64x2 a0, a1, b0, b1;
v_expand(a, a0, a1);
v_expand(b, b0, b1);
c.val = ((__u64x2)(a0.val) * (__u64x2)(b0.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)
@ -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)
{
#ifdef __wasm_unimplemented_simd128__
v128_t a0 = wasm_i64x2_shr(wasm_i64x2_shl(a.val, 32), 32);
v128_t a1 = wasm_i64x2_shr(a.val, 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 d = (v128_t)((__i64x2)a1 * (__i64x2)b1);
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)
{
#ifdef __wasm_unimplemented_simd128__
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
@ -2515,32 +2412,32 @@ inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b, const
// 16 >> 64
inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b)
{
fallback::v_uint16x8 a_(a);
fallback::v_uint16x8 b_(b);
return fallback::v_dotprod_expand(a_, b_);
v128_t a0 = wasm_u32x4_shr(wasm_i32x4_shl(a.val, 16), 16);
v128_t a1 = wasm_u32x4_shr(a.val, 16);
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)
{
fallback::v_uint16x8 a_(a);
fallback::v_uint16x8 b_(b);
fallback::v_uint64x2 c_(c);
return fallback::v_dotprod_expand(a_, b_, c_);
}
{ return v_dotprod_expand(a, b) + c; }
inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b)
{
fallback::v_int16x8 a_(a);
fallback::v_int16x8 b_(b);
return fallback::v_dotprod_expand(a_, b_);
v128_t a0 = wasm_i32x4_shr(wasm_i32x4_shl(a.val, 16), 16);
v128_t a1 = wasm_i32x4_shr(a.val, 16);
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)
{
fallback::v_int16x8 a_(a);
fallback::v_int16x8 b_(b);
fallback::v_int64x2 c_(c);
return fallback::v_dotprod_expand(a_, b_, c_);
}
{ return v_dotprod_expand(a, b) + c; }
// 32 >> 64f
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)
{
#ifdef __wasm_unimplemented_simd128__
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)
{
#ifdef __wasm_unimplemented_simd128__
const v128_t _1_0 = wasm_f32x4_splat(1.0);
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)
{
#ifdef __wasm_unimplemented_simd128__
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)
{
#ifdef __wasm_unimplemented_simd128__
const v128_t _1_0 = wasm_f64x2_splat(1.0);
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) \
@ -2666,12 +2543,7 @@ inline v_float32x4 v_abs(const v_float32x4& x)
{ return v_float32x4(wasm_f32x4_abs(x.val)); }
inline v_float64x2 v_abs(const v_float64x2& x)
{
#ifdef __wasm_unimplemented_simd128__
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
@ -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_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_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) \
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_int32x4, i32x4, i32x4)
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)
#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) \
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)
{
#ifdef __wasm_unimplemented_simd128__
v128_t z = wasm_i64x2_splat(0x7fffffffffffffff);
v128_t t = wasm_i64x2_splat(0x7ff0000000000000);
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)
@ -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)
{
#ifdef __wasm_unimplemented_simd128__
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));
#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) \
{ \
fallback::_Tpvec a_(a), b_(b); \
return fallback::v_magnitude(a_, 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##_sqrt(wasm_##suffix##_add(a_Square, b_Square))); \
} \
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) \
{ \
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_float64x2)
OPENCV_HAL_IMPL_WASM_MISC_FLT_OP(v_float32x4, f32x4)
OPENCV_HAL_IMPL_WASM_MISC_FLT_OP(v_float64x2, f64x2)
#define OPENCV_HAL_IMPL_WASM_SHIFT_OP(_Tpuvec, _Tpsvec, suffix, ssuffix) \
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_uint16x8, v_int16x8, i16x8, u16x8)
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)
#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
{
@ -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_uint16x8, unsigned)
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,
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_int32x4, i32x4, int)
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_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_uint32x4)
OPENCV_HAL_IMPL_WASM_SELECT(v_int32x4)
// OPENCV_HAL_IMPL_WASM_SELECT(v_uint64x2)
// OPENCV_HAL_IMPL_WASM_SELECT(v_int64x2)
OPENCV_HAL_IMPL_WASM_SELECT(v_uint64x2)
OPENCV_HAL_IMPL_WASM_SELECT(v_int64x2)
OPENCV_HAL_IMPL_WASM_SELECT(v_float32x4)
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,
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.
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
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
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.
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;
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[2-(blue<<1)] = (S[-1] + S[1]) >> 1;
D[2-(blue<<1)] = (S[-1] + S[1] + 1) >> 1;
D += dcn;
++S;
++x;
@ -1584,7 +1584,7 @@ public:
{
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[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[4] = S[1];

@ -180,3 +180,22 @@ endforeach()
add_custom_target(${PROJECT_NAME}_perf ALL
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");
}
const cvSize = {
szODD: new cv.Size(127, 61),
szQVGA: new cv.Size(320, 240),
szVGA: new cv.Size(640, 480),
szqHD: new cv.Size(960, 540),
sz720p: new cv.Size(1280, 720),
sz1080p: new cv.Size(1920, 1080),
sz130x60: new cv.Size(130, 60),
sz213x120: new cv.Size(120 * 1280 / 720, 120),
let gCvSize;
function getCvSize() {
if (gCvSize === undefined) {
gCvSize = {
szODD: new cv.Size(127, 61),
szQVGA: new cv.Size(320, 240),
szVGA: new cv.Size(640, 480),
szSVGA: new cv.Size(800, 600),
szqHD: new cv.Size(960, 540),
szXGA: new cv.Size(1024, 768),
sz720p: new cv.Size(1280, 720),
szSXGA: new cv.Size(1280, 1024),
sz1080p: new cv.Size(1920, 1080),
sz130x60: new cv.Size(130, 60),
sz213x120: new cv.Size(120 * 1280 / 720, 120),
};
}
return gCvSize;
}
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) {
let size;
let cvSize = getCvSize();
switch(strSize) {
case "127,61": size = cvSize.szODD;break;
case '320,240': size = cvSize.szQVGA;break;
case '640,480': size = cvSize.szVGA;break;
case '800,600': size = cvSize.szSVGA;break;
case '960,540': size = cvSize.szqHD;break;
case '1024,768': size = cvSize.szXGA;break;
case '1280,720': size = cvSize.sz720p;break;
case '1280,1024': size = cvSize.szSXGA;break;
case '1920,1080': size = cvSize.sz1080p;break;
case "130,60": size = cvSize.sz130x60;break;
case '213,120': size = cvSize.sz213x120;break;
@ -52,8 +95,209 @@ function permute (source, target) {
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') {
exports.enableButton = enableButton;
exports.disableButton = disableButton;
exports.fillGradient = fillGradient;
exports.smoothBorder = smoothBorder;
exports.cvtStr2cvSize = cvtStr2cvSize;
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');
}
cv.onRuntimeInitialized = () => {
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.cvSize;
global.cvSize = Base.getCvSize();
} else {
runButton.removeAttribute('disabled');
runButton.setAttribute('class', 'btn btn-primary');
runButton.innerHTML = 'Run';
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
@ -73,126 +73,77 @@ cv.onRuntimeInitialized = () => {
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
// https://github.com/opencv/opencv/commit/4e679e1cc5b075ec006b29a58b4fe117523fba1d
const CvtMode16U = [
"COLOR_BGR2BGRA", "COLOR_BGR2GRAY",
"COLOR_BGR2RGB", "COLOR_BGR2RGBA", "COLOR_BGR2XYZ",
"COLOR_BGR2YCrCb", "COLOR_BGR2YUV",
"COLOR_BGRA2BGR", "COLOR_BGRA2GRAY", "COLOR_BGRA2RGBA",
"CX_BGRA2XYZ",
"CX_BGRA2YCrCb", "CX_BGRA2YUV",
"COLOR_GRAY2BGR", "COLOR_GRAY2BGRA",
"COLOR_RGB2GRAY",
"COLOR_RGB2XYZ", "COLOR_RGB2YCrCb", "COLOR_RGB2YUV",
"COLOR_RGBA2BGR", "COLOR_RGBA2GRAY",
"CX_RGBA2XYZ",
"CX_RGBA2YCrCb", "CX_RGBA2YUV",
function constructCvtMode16U() {
let cvtMode16U = [];
cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "BGR", ["BGRA", "GRAY", "RGB", "RGBA", "XYZ", "YCrCb", "YUV"]));
cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "BGRA", ["BGR", "GRAY", "RGBA"]));
cvtMode16U = cvtMode16U.concat(constructMode("CX_", "BGRA", ["XYZ", "YCrCb", "YUV"]));
cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "GRAY", ["BGR", "BGRA"]));
cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "RGB", ["GRAY", "XYZ", "YCrCb", "YUV"]));
cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "RGBA", ["BGR", "GRAY"]));
cvtMode16U = cvtMode16U.concat(constructMode("CX_", "RGBA", ["XYZ", "YCrCb", "YUV"]));
cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "XYZ", ["BGR", "RGB"]));
cvtMode16U = cvtMode16U.concat(constructMode("CX_", "XYZ", ["BGRA", "RGBA"]));
cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "YCrCb", ["BGR", "RGB"]));
cvtMode16U = cvtMode16U.concat(constructMode("CX_", "YCrCb", ["BGRA", "RGBA"]));
cvtMode16U = cvtMode16U.concat(constructMode("COLOR_", "YUV", ["BGR", "RGB"]));
cvtMode16U = cvtMode16U.concat(constructMode("CX_", "YUV", ["BGRA", "RGBA"]));
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 combiCvtMode16U = combine(CvtMode16USize, CvtMode16U);
const CvtMode32F = [
"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_BGRA2BGR", "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_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",
function constructCvtMode32F(source) {
let cvtMode32F = source;
cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "BGR", ["HLS", "HLS_FULL", "HSV", "HSV_FULL", "Lab", "Luv"]));
cvtMode32F = cvtMode32F.concat(constructMode("CX_", "BGRA", ["HLS", "HLS_FULL", "HSV", "HSV_FULL", "Lab", "Luv"]));
cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "HLS", ["BGR", "BGR_FULL", "RGB", "RGB_FULL"]));
cvtMode32F = cvtMode32F.concat(constructMode("CX_", "HLS", ["BGRA", "BGRA_FULL", "RGBA", "RGBA_FULL"]));
cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "HSV", ["BGR", "BGR_FULL", "RGB", "RGB_FULL"]));
cvtMode32F = cvtMode32F.concat(constructMode("CX_", "HSV", ["BGRA", "BGRA_FULL", "RGBA", "RGBA_FULL"]));
cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "Lab", ["BGR", "LBGR", "RGB", "LRGB"]));
cvtMode32F = cvtMode32F.concat(constructMode("CX_", "Lab", ["BGRA", "LBGRA", "RGBA", "LRGBA"]));
cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "Luv", ["BGR", "LBGR", "RGB", "LRGB"]));
cvtMode32F = cvtMode32F.concat(constructMode("CX_", "Luv", ["BGRA", "LBGRA", "RGBA", "LRGBA"]));
cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "LBGR", ["Lab", "Luv"]));
cvtMode32F = cvtMode32F.concat(constructMode("CX_", "LBGRA", ["Lab", "Luv"]));
cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "LRGB", ["Lab", "Luv"]));
cvtMode32F = cvtMode32F.concat(constructMode("CX_", "LRGBA", ["Lab", "Luv"]));
cvtMode32F = cvtMode32F.concat(constructMode("COLOR_", "RGB", ["HLS", "HLS_FULL", "HSV", "HSV_FULL", "Lab", "Luv"]));
cvtMode32F = cvtMode32F.concat(constructMode("CX_", "RGBA", ["HLS", "HLS_FULL", "HSV", "HSV_FULL", "Lab", "Luv"]));
return cvtMode32F;
}
"COLOR_Luv2BGR", "COLOR_Luv2LBGR", "COLOR_Luv2LRGB", "COLOR_Luv2RGB",
"CX_Luv2BGRA", "CX_Luv2LBGRA", "CX_Luv2LRGBA", "CX_Luv2RGBA",
const CvtMode32F = constructCvtMode32F(CvtMode16U);
"COLOR_RGB2GRAY",
"COLOR_RGB2HLS", "COLOR_RGB2HLS_FULL", "COLOR_RGB2HSV", "COLOR_RGB2HSV_FULL",
"COLOR_RGB2Lab", "COLOR_RGB2Luv", "COLOR_RGB2XYZ", "COLOR_RGB2YCrCb", "COLOR_RGB2YUV",
const CvtMode32FSize = [cvSize.szODD, cvSize.szVGA, cvSize.sz1080p];
const combiCvtMode32F = combine(CvtMode32FSize, CvtMode32F);
"COLOR_RGBA2BGR", "COLOR_RGBA2GRAY",
"CX_RGBA2HLS", "CX_RGBA2HLS_FULL", "CX_RGBA2HSV", "CX_RGBA2HSV_FULL",
"CX_RGBA2Lab", "CX_RGBA2Luv", "CX_RGBA2XYZ",
"CX_RGBA2YCrCb", "CX_RGBA2YUV",
function constructeCvtMode(source) {
let cvtMode = source
cvtMode = cvtMode.concat(constructMode("COLOR_", "BGR", ["BGR555", "BGR565"]));
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",
"COLOR_YUV2BGR", "COLOR_YUV2RGB", "CX_YUV2BGRA", "CX_YUV2RGBA"
];
const CvtMode32FSize = [cvSize.szODD, cvSize.szVGA, cvSize.sz1080p];
const combiCvtMode32F = combine(CvtMode32FSize, CvtMode32F);
const CvtModeSize = [cvSize.szODD, cvSize.szVGA, cvSize.sz1080p];
// combiCvtMode permute size and mode
const combiCvtMode = combine(CvtModeSize, CvtMode);
const CvtModeBayer = [
"COLOR_BayerBG2BGR", "COLOR_BayerBG2BGRA", "COLOR_BayerBG2BGR_VNG", "COLOR_BayerBG2GRAY",
@ -357,7 +308,7 @@ cv.onRuntimeInitialized = () => {
return [mat1Type, mat2Type];
}
function addCvtColorCase(suite) {
function addCvtColorCase(suite, type) {
suite.add('cvtColor', function() {
cv.cvtColor(mat1, mat2, mode, 0);
}, {
@ -375,154 +326,22 @@ cv.onRuntimeInitialized = () => {
});
}
function addCvtModeCase(suite, combination) {
function addCvtModeCase(suite, combination, type) {
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 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
};
};
}
function addCvtMode3Case(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
};
};
}
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';
let sizeArray;
if (type == 0) {
sizeArray = [size.width, size.height];
} else {
sizeArray = [size.width, size.height+size.height/2];
}
});
let params = {size:sizeArray, matType: matType, mode: mode};
addKernelCase(suite, params, type, addCvtColorCase);
};
}
function genBenchmarkCase(paramsContent) {
@ -531,23 +350,33 @@ cv.onRuntimeInitialized = () => {
currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*\w+\)/g.test(paramsContent.toString())) {
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 {
log("no filter or getting invalid params, run all the cases");
addCvtModeCase(suite, combiCvtMode);
addCvtModeBayerCase(suite, combiCvtModeBayer);
addCvtMode2Case(suite, combiCvtMode2);
addCvtMode3Case(suite, combiCvtMode3);
addCvtModeCase(suite, combiCvtMode, 0);
addCvtModeCase(suite, combiCvtModeBayer, 0);
addCvtModeCase(suite, combiCvtMode2, 1);
addCvtModeCase(suite, combiCvtMode3, 1);
}
setBenchmarkSuite(suite);
setBenchmarkSuite(suite, "cvtcolor", currentCaseId);
log(`Running ${totalCaseNum} tests from CvtColor`);
suite.run({ 'async': true }); // run the benchmark
}
// init
let cvtFunc = [addCvtModeCase, addCvtModeBayerCase, addCvtMode2Case, addCvtMode3Case];//, addEdgeAwareBayerModeCase];
let combinations = [combiCvtMode, combiCvtModeBayer, combiCvtMode2, combiCvtMode3];//, combiEdgeAwareBayer];
// set test filter params
@ -563,10 +392,19 @@ cv.onRuntimeInitialized = () => {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
runButton.setAttribute("disabled", "disabled");
runButton.setAttribute('class', 'btn btn-primary disabled');
runButton.innerHTML = "Running";
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>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');
}
cv.onRuntimeInitialized = () => {
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.fillGradient = HelpFunc.fillGradient;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.cvSize;
global.cvSize = Base.getCvSize();
} else {
runButton.removeAttribute('disabled');
runButton.setAttribute('class', 'btn btn-primary');
runButton.innerHTML = 'Run';
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
@ -59,185 +58,80 @@ cv.onRuntimeInitialized = () => {
const scalesAreaFast = [2];
const combiAreaFast = combine(matTypesAreaFast, sizesAreaFast, scalesAreaFast);
function addResizeUpLinearCase(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() {
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() {
function addResizeCase(suite, type) {
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);
}, {
'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);
}
}, {
'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 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);
},
'teardown': function() {
src.delete();
dst.delete();
}
});
// set init params
let index = suite.length - 1;
suite[index].params = {
from: from,
to: to,
matType: matType
};
}
},
'teardown': function() {
src.delete();
dst.delete();
}
});
}
function addResizeAreaFastCase(suite, combination) {
function addResizeModeCase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let matType = combination[i][0];
let from = combination[i][1];
let scale = combination[i][2];
from.width = (Math.floor(from.width/scale))*scale;
from.height = (Math.floor(from.height/scale))*scale;
let to = {
width: from.width/scale,
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]]);
}
let params;
if (type == "area") {
let scale = combination[i][2];
params = { from: from, scale: scale, matType: matType, modeType: type };
} else {
let to = combination[i][2];
params = { from: from, to: to, matType: matType, modeType: type};
}
addKernelCase(suite, params, type, addResizeCase)
}
}
function log(message) {
console.log(message);
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 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) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
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];
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 {
log("no filter or getting invalid params, run all the cases");
addResizeUpLinearCase(suite, combiUpLinear);
addResizeDownLinearCase(suite, combiDownLinear);
addResizeModeCase(suite, combiUpLinear, "linear");
addResizeModeCase(suite, combiDownLinear, "linear");
}
setBenchmarkSuite(suite);
setBenchmarkSuite(suite, "resize", currentCaseId);
log(`Running ${totalCaseNum} tests from Resize`);
suite.run({ 'async': true }); // run the benchmark
}
// init
let resizeFunc = [addResizeUpLinearCase, addResizeDownLinearCase];//, addResizeAreaFastCase];
let combinations = [combiUpLinear, combiDownLinear];//, combiAreaFast];
// set test filter params
@ -253,10 +147,19 @@ cv.onRuntimeInitialized = () => {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
runButton.setAttribute("disabled", "disabled");
runButton.setAttribute('class', 'btn btn-primary disabled');
runButton.innerHTML = "Running";
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>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');
}
cv.onRuntimeInitialized = () => {
function perf() {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.cvSize;
global.cvSize = Base.getCvSize();
} else {
runButton.removeAttribute('disabled');
runButton.setAttribute('class', 'btn btn-primary');
runButton.innerHTML = 'Run';
enableButton();
cvSize = getCvSize();
}
let totalCaseNum, currentCaseId;
@ -32,173 +32,105 @@ cv.onRuntimeInitialized = () => {
const combiSizeMatTypeThreshType = combine(typicalMatSizes, matTypes, threshTypes);
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];
suite.add('threshold', function() {
function addThresholdCase(suite, type) {
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);
}, {
'setup': function() {
let matSize = this.params.matSize;
let matType = cv[this.params.matType];
let threshType = cv[this.params.threshType];
let threshold = 127.0;
let thresholdMax = 210.0;
let src = new cv.Mat(matSize, matType);
let dst = new cv.Mat(matSize, matType);
let srcView = src.data;
srcView[0] = 0;
srcView[1] = 100;
srcView[2] = 200;
},
'teardown': function() {
src.delete();
dst.delete();
}
}, {
'setup': function() {
let matSize = this.params.matSize;
let type = this.params.modeType;
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);
}
});
// set init params
let index = suite.length - 1;
suite[index].params = {
matSize: matSize,
matType: matType,
threshType: threshType
};
}
let threshold = 127.0;
let thresholdMax = 210.0;
let srcView = src.data;
srcView[0] = 0;
srcView[1] = 100;
srcView[2] = 200;
},
'teardown': function() {
src.delete();
dst.delete();
}
});
}
function addSizeOnlyCase(suite, combination) {
function addThresholdModecase(suite, combination, type) {
totalCaseNum += combination.length;
for (let i = 0; i < combination.length; ++i) {
let matSize = combination[i][0];
suite.add('threshold', function() {
cv.threshold(src, dst, threshold, thresholdMax, cv.THRESH_BINARY|cv.THRESH_OTSU);
}, {
'setup': function() {
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 matType = 'CV_8UC1';
let threshType = 'THRESH_BINARY|THRESH_OTSU';
if (type != "sizeonly") {
matType = combination[i][1];
threshType = combination[i][2];
}
let params = {matSize: matSize, matType: matType, threshType: threshType, modeType: type};
addKernelCase(suite, params, type, addThresholdCase);
}
}
function log(message) {
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) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
currentCaseId = 0;
if (/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\w+\)/g.test(paramsContent.toString())) {
let params = paramsContent.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\w+\)/g)[0];
let isSizeOnly = 0;
decodeParams2Case(suite, params, isSizeOnly);
let params = "";
let paramObjs = [];
paramObjs.push({name:"size", value:"", reg:[""], index:0});
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())) {
let params = paramsContent.toString().match(/[\ ]*[0-9]+x[0-9]+[\ ]*/g)[0];
let isSizeOnly = 1;
decodeParams2Case(suite, params, isSizeOnly);
params = paramsContent.toString().match(/[\ ]*[0-9]+x[0-9]+[\ ]*/g)[0];
paramObjs.push({name:"matType", value:"CV_8UC1", reg:[""], index:1});
paramObjs.push({name:"threshType", value:"THRESH_BINARY|THRESH_OTSU", reg:[""], index:2});
}
else {
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 {
log("no filter or getting invalid params, run all the cases");
addSizeMatTypeThreshTypeCase(suite, combiSizeMatTypeThreshType);
addSizeOnlyCase(suite, combiSizeOnly);
addThresholdModecase(suite, combiSizeMatTypeThreshType, "normal");
addThresholdModecase(suite, combiSizeOnly, "sizeonly");
}
setBenchmarkSuite(suite);
setBenchmarkSuite(suite, "threshold", currentCaseId);
log(`Running ${totalCaseNum} tests from Threshold`);
suite.run({ 'async': true }); // run the benchmark
}
// init
let thresholdFunc = [addSizeMatTypeThreshTypeCase, addSizeOnlyCase];
let combinations = [combiSizeMatTypeThreshType, combiSizeOnly];
// set test filter params
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\w+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\([0-9]+x[0-9]+,[\ ]*\w+,[\ ]*\w+\)/g)[0];
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]+,[\ ]*CV\_\w+,[\ ]*THRESH\_\w+\)/g)[0];
} 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];
}
@ -208,10 +140,19 @@ cv.onRuntimeInitialized = () => {
let paramsContent = paramsElement.value;
genBenchmarkCase(paramsContent);
if (totalCaseNum !== 0) {
runButton.setAttribute("disabled", "disabled");
runButton.setAttribute('class', 'btn btn-primary disabled');
runButton.innerHTML = "Running";
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>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):
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_perf', action="store_true", help="Build performance tests")
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('--skip_config', action="store_true", help="Skip cmake config")
parser.add_argument('--config_only', action="store_true", help="Only do cmake config")
@ -294,6 +298,11 @@ if __name__ == "__main__":
log.info("=====")
builder.build_doc()
if args.build_loader:
log.info("=====")
log.info("===== Building OpenCV.js loader")
log.info("=====")
builder.build_loader()
log.info("=====")
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"))
if check_file(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)

@ -234,10 +234,10 @@ class SiamRPNTracker:
"""
Args:
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
self.center_pos = np.array([x + (h - 1) / 2, y + (w - 1) / 2])
x, y, w, h = bbox
self.center_pos = np.array([x + (w - 1) / 2, y + (h - 1) / 2])
self.h = h
self.w = w
w_z = self.w + self.track_context_amount * np.add(h, w)

Loading…
Cancel
Save