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

pull/15593/head
Alexander Alekhin 5 years ago committed by Alexander Alekhin
commit e2a5a6a05c
  1. 84
      doc/js_tutorials/js_setup/js_setup/js_setup.markdown
  2. 9
      modules/core/include/opencv2/core/cv_cpu_dispatch.h
  3. 1
      modules/core/include/opencv2/core/cvdef.h
  4. 5
      modules/core/include/opencv2/core/hal/intrin.hpp
  5. 56
      modules/core/include/opencv2/core/hal/intrin_avx.hpp
  6. 6
      modules/core/include/opencv2/core/hal/intrin_cpp.hpp
  7. 20
      modules/core/include/opencv2/core/hal/intrin_neon.hpp
  8. 44
      modules/core/include/opencv2/core/hal/intrin_sse.hpp
  9. 4
      modules/core/include/opencv2/core/hal/intrin_vsx.hpp
  10. 4025
      modules/core/include/opencv2/core/hal/intrin_wasm.hpp
  11. 10
      modules/core/src/mathfuncs_core.simd.hpp
  12. 17
      modules/core/src/ocl.cpp
  13. 4
      modules/core/src/parallel.cpp
  14. 24
      modules/core/test/test_io.cpp
  15. 6
      modules/dnn/src/dnn.cpp
  16. 21
      modules/dnn/src/layers/convolution_layer.cpp
  17. 15
      modules/dnn/src/layers/recurrent_layers.cpp
  18. 49
      modules/dnn/test/test_layers.cpp
  19. 3
      modules/dnn/test/test_model.cpp
  20. 2
      modules/imgcodecs/src/grfmt_tiff.cpp
  21. 6
      modules/imgcodecs/src/loadsave.cpp
  22. 84
      modules/imgproc/src/pyramids.cpp
  23. 37
      modules/js/CMakeLists.txt
  24. 35
      modules/js/perf/README.md
  25. 18
      modules/js/perf/base.js
  26. 19
      modules/js/perf/package.json
  27. 59
      modules/js/perf/perf_helpfunc.js
  28. 73
      modules/js/perf/perf_imgproc/perf_cvtcolor.html
  29. 572
      modules/js/perf/perf_imgproc/perf_cvtcolor.js
  30. 73
      modules/js/perf/perf_imgproc/perf_resize.html
  31. 262
      modules/js/perf/perf_imgproc/perf_resize.js
  32. 73
      modules/js/perf/perf_imgproc/perf_threshold.html
  33. 217
      modules/js/perf/perf_imgproc/perf_threshold.js
  34. 84
      modules/js/src/core_bindings.cpp
  35. 8
      modules/js/src/make_umd.py
  36. 2
      modules/ml/src/ann_mlp.cpp
  37. 3
      modules/ml/src/boost.cpp
  38. 1
      modules/ml/src/em.cpp
  39. 5
      modules/ml/src/inner_functions.cpp
  40. 2
      modules/ml/src/knearest.cpp
  41. 6
      modules/ml/src/lr.cpp
  42. 1
      modules/ml/src/nbayes.cpp
  43. 3
      modules/ml/src/rtrees.cpp
  44. 2
      modules/ml/src/svm.cpp
  45. 1
      modules/ml/src/svmsgd.cpp
  46. 3
      modules/ml/src/tree.cpp
  47. 7
      modules/ml/test/test_lr.cpp
  48. 8
      modules/ml/test/test_mltests2.cpp
  49. 9
      platforms/ios/build_framework.py
  50. 42
      platforms/js/build_js.py

@ -107,6 +107,90 @@ Building OpenCV.js from Source
@note
It requires `node` installed in your development environment.
-# [optional] To build `opencv.js` with threads optimization, append `--threads` option.
For example:
@code{.bash}
python ./platforms/js/build_js.py build_js --build_wasm --threads
@endcode
The default threads number is the logic core number of your device. You can use `cv.parallel_pthreads_set_threads_num(number)` to set threads number by yourself and use `cv.parallel_pthreads_get_threads_num()` to get the current threads number.
@note
You should build wasm version of `opencv.js` if you want to enable this optimization. And the threads optimization only works in browser, not in node.js. You need to enable the `WebAssembly threads support` feature first with your browser. For example, if you use Chrome, please enable this flag in chrome://flags.
-# [optional] To build `opencv.js` with wasm simd optimization, append `--simd` option.
For example:
@code{.bash}
python ./platforms/js/build_js.py build_js --build_wasm --simd
@endcode
The simd optimization is experimental as wasm simd is still in development.
@note
Now only emscripten LLVM upstream backend supports wasm simd, refering to https://emscripten.org/docs/porting/simd.html. So you need to setup upstream backend environment with the following command first:
@code{.bash}
./emsdk update
./emsdk install latest-upstream
./emsdk activate latest-upstream
source ./emsdk_env.sh
@endcode
@note
You should build wasm version of `opencv.js` if you want to enable this optimization. For browser, you need to enable the `WebAssembly SIMD support` feature first. For example, if you use Chrome, please enable this flag in chrome://flags. For Node.js, you need to run script with flag `--experimental-wasm-simd`.
@note
The simd version of `opencv.js` built by latest LLVM upstream may not work with the stable browser or old version of Node.js. Please use the latest version of unstable browser or Node.js to get new features, like `Chrome Dev`.
-# [optional] To build wasm intrinsics tests, append `--build_wasm_intrin_test` option.
For example:
@code{.bash}
python ./platforms/js/build_js.py build_js --build_wasm --simd --build_wasm_intrin_test
@endcode
For wasm intrinsics tests, you can use the following function to test all the cases:
@code{.js}
cv.test_hal_intrin_all()
@endcode
And the failed cases will be logged in the JavaScript debug console.
If you only want to test single data type of wasm intrinsics, you can use the following functions:
@code{.js}
cv.test_hal_intrin_uint8()
cv.test_hal_intrin_int8()
cv.test_hal_intrin_uint16()
cv.test_hal_intrin_int16()
cv.test_hal_intrin_uint32()
cv.test_hal_intrin_int32()
cv.test_hal_intrin_uint64()
cv.test_hal_intrin_int64()
cv.test_hal_intrin_float32()
cv.test_hal_intrin_float64()
@endcode
-# [optional] To build performance tests, append `--build_perf` option.
For example:
@code{.bash}
python ./platforms/js/build_js.py build_js --build_perf
@endcode
To run performance tests, launch a local web server in \<build_dir\>/bin folder. For example, node http-server which serves on `localhost:8080`.
There are some kernels now in the performance test like `cvtColor`, `resize` and `threshold`. For example, if you want to test `threshold`, please navigate the web browser to `http://localhost:8080/perf/perf_imgproc/perf_threshold.html`. You need to input the test parameter like `(1920x1080, CV_8UC1, THRESH_BINARY)`, and then click the `Run` button to run the case. And if you don't input the parameter, it will run all the cases of this kernel.
You can also run tests using Node.js.
For example, run `threshold` with parameter `(1920x1080, CV_8UC1, THRESH_BINARY)`:
@code{.sh}
cd bin/perf
npm install
node perf_threshold.js --test_param_filter="(1920x1080, CV_8UC1, THRESH_BINARY)"
@endcode
Building OpenCV.js with Docker
---------------------------------------

@ -157,6 +157,11 @@
# define CV_MSA 1
#endif
#ifdef __EMSCRIPTEN__
# define CV_WASM_SIMD 1
# include <wasm_simd128.h>
#endif
#endif // CV_ENABLE_INTRINSICS && !CV_DISABLE_OPTIMIZATION && !__CUDACC__
#if defined CV_CPU_COMPILE_AVX && !defined CV_CPU_BASELINE_COMPILE_AVX
@ -328,3 +333,7 @@ struct VZeroUpperGuard {
#ifndef CV_MSA
# define CV_MSA 0
#endif
#ifndef CV_WASM_SIMD
# define CV_WASM_SIMD 0
#endif

@ -695,6 +695,7 @@ __CV_ENUM_FLAGS_BITWISE_XOR_EQ (EnumType, EnumType)
#endif
#define CV_CXX_MOVE_SEMANTICS 1
#define CV_CXX_MOVE(x) std::move(x)
#define CV_CXX_STD_ARRAY 1
#include <array>
#ifndef CV_OVERRIDE

@ -168,7 +168,7 @@ using namespace CV_CPU_OPTIMIZATION_HAL_NAMESPACE;
# undef CV_MSA
#endif
#if CV_SSE2 || CV_NEON || CV_VSX || CV_MSA
#if CV_SSE2 || CV_NEON || CV_VSX || CV_MSA || CV_WASM_SIMD
#define CV__SIMD_FORWARD 128
#include "opencv2/core/hal/intrin_forward.hpp"
#endif
@ -190,6 +190,9 @@ using namespace CV_CPU_OPTIMIZATION_HAL_NAMESPACE;
#include "opencv2/core/hal/intrin_msa.hpp"
#elif CV_WASM_SIMD
#include "opencv2/core/hal/intrin_wasm.hpp"
#else
#define CV_SIMD128_CPP 1

@ -1241,6 +1241,11 @@ inline int v_signmask(const v_int32x8& a)
inline int v_signmask(const v_uint32x8& a)
{ return v_signmask(v_reinterpret_as_f32(a)); }
inline int v_signmask(const v_int64x4& a)
{ return v_signmask(v_reinterpret_as_f64(a)); }
inline int v_signmask(const v_uint64x4& a)
{ return v_signmask(v_reinterpret_as_f64(a)); }
inline int v_scan_forward(const v_int8x32& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))); }
inline int v_scan_forward(const v_uint8x32& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))); }
inline int v_scan_forward(const v_int16x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 2; }
@ -1253,40 +1258,23 @@ inline int v_scan_forward(const v_uint64x4& a) { return trailingZeros32(v_signma
inline int v_scan_forward(const v_float64x4& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 8; }
/** Checks **/
#define OPENCV_HAL_IMPL_AVX_CHECK(_Tpvec, and_op, allmask) \
inline bool v_check_all(const _Tpvec& a) \
{ \
int mask = v_signmask(v_reinterpret_as_s8(a)); \
return and_op(mask, allmask) == allmask; \
} \
inline bool v_check_any(const _Tpvec& a) \
{ \
int mask = v_signmask(v_reinterpret_as_s8(a)); \
return and_op(mask, allmask) != 0; \
}
OPENCV_HAL_IMPL_AVX_CHECK(v_uint8x32, OPENCV_HAL_1ST, -1)
OPENCV_HAL_IMPL_AVX_CHECK(v_int8x32, OPENCV_HAL_1ST, -1)
OPENCV_HAL_IMPL_AVX_CHECK(v_uint16x16, OPENCV_HAL_AND, (int)0xaaaaaaaa)
OPENCV_HAL_IMPL_AVX_CHECK(v_int16x16, OPENCV_HAL_AND, (int)0xaaaaaaaa)
OPENCV_HAL_IMPL_AVX_CHECK(v_uint32x8, OPENCV_HAL_AND, (int)0x88888888)
OPENCV_HAL_IMPL_AVX_CHECK(v_int32x8, OPENCV_HAL_AND, (int)0x88888888)
#define OPENCV_HAL_IMPL_AVX_CHECK_FLT(_Tpvec, allmask) \
inline bool v_check_all(const _Tpvec& a) \
{ \
int mask = v_signmask(a); \
return mask == allmask; \
} \
inline bool v_check_any(const _Tpvec& a) \
{ \
int mask = v_signmask(a); \
return mask != 0; \
}
OPENCV_HAL_IMPL_AVX_CHECK_FLT(v_float32x8, 255)
OPENCV_HAL_IMPL_AVX_CHECK_FLT(v_float64x4, 15)
#define OPENCV_HAL_IMPL_AVX_CHECK(_Tpvec, allmask) \
inline bool v_check_all(const _Tpvec& a) { return v_signmask(a) == allmask; } \
inline bool v_check_any(const _Tpvec& a) { return v_signmask(a) != 0; }
OPENCV_HAL_IMPL_AVX_CHECK(v_uint8x32, -1)
OPENCV_HAL_IMPL_AVX_CHECK(v_int8x32, -1)
OPENCV_HAL_IMPL_AVX_CHECK(v_uint32x8, 255)
OPENCV_HAL_IMPL_AVX_CHECK(v_int32x8, 255)
OPENCV_HAL_IMPL_AVX_CHECK(v_uint64x4, 15)
OPENCV_HAL_IMPL_AVX_CHECK(v_int64x4, 15)
OPENCV_HAL_IMPL_AVX_CHECK(v_float32x8, 255)
OPENCV_HAL_IMPL_AVX_CHECK(v_float64x4, 15)
#define OPENCV_HAL_IMPL_AVX_CHECK_SHORT(_Tpvec) \
inline bool v_check_all(const _Tpvec& a) { return (v_signmask(v_reinterpret_as_s8(a)) & 0xaaaaaaaa) == 0xaaaaaaaa; } \
inline bool v_check_any(const _Tpvec& a) { return (v_signmask(v_reinterpret_as_s8(a)) & 0xaaaaaaaa) != 0; }
OPENCV_HAL_IMPL_AVX_CHECK_SHORT(v_uint16x16)
OPENCV_HAL_IMPL_AVX_CHECK_SHORT(v_int16x16)
////////// Other math /////////

@ -1080,7 +1080,7 @@ Example:
v_int32x4 r; // set to {-1, -1, 1, 1}
int mask = v_signmask(r); // mask = 3 <== 00000000 00000000 00000000 00000011
@endcode
For all types except 64-bit. */
*/
template<typename _Tp, int n> inline int v_signmask(const v_reg<_Tp, n>& a)
{
int mask = 0;
@ -1109,7 +1109,7 @@ template <typename _Tp, int n> inline int v_scan_forward(const v_reg<_Tp, n>& a)
/** @brief Check if all packed values are less than zero
Unsigned values will be casted to signed: `uchar 254 => char -2`.
For all types except 64-bit. */
*/
template<typename _Tp, int n> inline bool v_check_all(const v_reg<_Tp, n>& a)
{
for( int i = 0; i < n; i++ )
@ -1121,7 +1121,7 @@ template<typename _Tp, int n> inline bool v_check_all(const v_reg<_Tp, n>& a)
/** @brief Check if any of packed values is less than zero
Unsigned values will be casted to signed: `uchar 254 => char -2`.
For all types except 64-bit. */
*/
template<typename _Tp, int n> inline bool v_check_any(const v_reg<_Tp, n>& a)
{
for( int i = 0; i < n; i++ )

@ -1139,9 +1139,17 @@ inline bool v_check_any(const v_##_Tpvec& a) \
OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint8x16, u8, 7)
OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint16x8, u16, 15)
OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint32x4, u32, 31)
#if CV_SIMD128_64F
OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint64x2, u64, 63)
#endif
inline bool v_check_all(const v_uint64x2& a)
{
uint64x2_t v0 = vshrq_n_u64(a.val, 63);
return (vgetq_lane_u64(v0, 0) & vgetq_lane_u64(v0, 1)) == 1;
}
inline bool v_check_any(const v_uint64x2& a)
{
uint64x2_t v0 = vshrq_n_u64(a.val, 63);
return (vgetq_lane_u64(v0, 0) | vgetq_lane_u64(v0, 1)) != 0;
}
inline bool v_check_all(const v_int8x16& a)
{ return v_check_all(v_reinterpret_as_u8(a)); }
@ -1161,13 +1169,13 @@ inline bool v_check_any(const v_int32x4& a)
inline bool v_check_any(const v_float32x4& a)
{ return v_check_any(v_reinterpret_as_u32(a)); }
#if CV_SIMD128_64F
inline bool v_check_all(const v_int64x2& a)
{ return v_check_all(v_reinterpret_as_u64(a)); }
inline bool v_check_all(const v_float64x2& a)
{ return v_check_all(v_reinterpret_as_u64(a)); }
inline bool v_check_any(const v_int64x2& a)
{ return v_check_any(v_reinterpret_as_u64(a)); }
#if CV_SIMD128_64F
inline bool v_check_all(const v_float64x2& a)
{ return v_check_all(v_reinterpret_as_u64(a)); }
inline bool v_check_any(const v_float64x2& a)
{ return v_check_any(v_reinterpret_as_u64(a)); }
#endif

@ -1591,31 +1591,25 @@ inline v_uint32x4 v_popcount(const v_int32x4& a)
inline v_uint64x2 v_popcount(const v_int64x2& a)
{ return v_popcount(v_reinterpret_as_u64(a)); }
#define OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(_Tpvec, suffix, pack_op, and_op, signmask, allmask) \
inline int v_signmask(const _Tpvec& a) \
{ \
return and_op(_mm_movemask_##suffix(pack_op(a.val)), signmask); \
} \
inline bool v_check_all(const _Tpvec& a) \
{ return and_op(_mm_movemask_##suffix(a.val), allmask) == allmask; } \
inline bool v_check_any(const _Tpvec& a) \
{ return and_op(_mm_movemask_##suffix(a.val), allmask) != 0; }
#define OPENCV_HAL_PACKS(a) _mm_packs_epi16(a, a)
inline __m128i v_packq_epi32(__m128i a)
{
__m128i b = _mm_packs_epi32(a, a);
return _mm_packs_epi16(b, b);
}
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_uint8x16, epi8, OPENCV_HAL_NOP, OPENCV_HAL_1ST, 65535, 65535)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_int8x16, epi8, OPENCV_HAL_NOP, OPENCV_HAL_1ST, 65535, 65535)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_uint16x8, epi8, OPENCV_HAL_PACKS, OPENCV_HAL_AND, 255, (int)0xaaaa)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_int16x8, epi8, OPENCV_HAL_PACKS, OPENCV_HAL_AND, 255, (int)0xaaaa)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_uint32x4, epi8, v_packq_epi32, OPENCV_HAL_AND, 15, (int)0x8888)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_int32x4, epi8, v_packq_epi32, OPENCV_HAL_AND, 15, (int)0x8888)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_float32x4, ps, OPENCV_HAL_NOP, OPENCV_HAL_1ST, 15, 15)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_float64x2, pd, OPENCV_HAL_NOP, OPENCV_HAL_1ST, 3, 3)
#define OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(_Tpvec, suffix, cast_op, allmask) \
inline int v_signmask(const _Tpvec& a) { return _mm_movemask_##suffix(cast_op(a.val)); } \
inline bool v_check_all(const _Tpvec& a) { return _mm_movemask_##suffix(cast_op(a.val)) == allmask; } \
inline bool v_check_any(const _Tpvec& a) { return _mm_movemask_##suffix(cast_op(a.val)) != 0; }
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_uint8x16, epi8, OPENCV_HAL_NOP, 65535)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_int8x16, epi8, OPENCV_HAL_NOP, 65535)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_uint32x4, ps, _mm_castsi128_ps, 15)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_int32x4, ps, _mm_castsi128_ps, 15)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_uint64x2, pd, _mm_castsi128_pd, 3)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_int64x2, pd, _mm_castsi128_pd, 3)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_float32x4, ps, OPENCV_HAL_NOP, 15)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_float64x2, pd, OPENCV_HAL_NOP, 3)
#define OPENCV_HAL_IMPL_SSE_CHECK_SIGNS_SHORT(_Tpvec) \
inline int v_signmask(const _Tpvec& a) { return _mm_movemask_epi8(_mm_packs_epi16(a.val, a.val)) & 255; } \
inline bool v_check_all(const _Tpvec& a) { return (_mm_movemask_epi8(a.val) & 0xaaaa) == 0xaaaa; } \
inline bool v_check_any(const _Tpvec& a) { return (_mm_movemask_epi8(a.val) & 0xaaaa) != 0; }
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS_SHORT(v_uint16x8)
OPENCV_HAL_IMPL_SSE_CHECK_SIGNS_SHORT(v_int16x8)
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))); }

@ -899,6 +899,8 @@ inline bool v_check_all(const v_uint16x8& a)
{ return v_check_all(v_reinterpret_as_s16(a)); }
inline bool v_check_all(const v_uint32x4& a)
{ return v_check_all(v_reinterpret_as_s32(a)); }
inline bool v_check_all(const v_uint64x2& a)
{ return v_check_all(v_reinterpret_as_s64(a)); }
inline bool v_check_all(const v_float32x4& a)
{ return v_check_all(v_reinterpret_as_s32(a)); }
inline bool v_check_all(const v_float64x2& a)
@ -913,6 +915,8 @@ inline bool v_check_any(const v_uint16x8& a)
{ return v_check_any(v_reinterpret_as_s16(a)); }
inline bool v_check_any(const v_uint32x4& a)
{ return v_check_any(v_reinterpret_as_s32(a)); }
inline bool v_check_any(const v_uint64x2& a)
{ return v_check_any(v_reinterpret_as_s64(a)); }
inline bool v_check_any(const v_float32x4& a)
{ return v_check_any(v_reinterpret_as_s32(a)); }
inline bool v_check_any(const v_float64x2& a)

File diff suppressed because it is too large Load Diff

@ -31,6 +31,11 @@ using namespace cv;
namespace {
static const float atan2_p1 = 0.9997878412794807f*(float)(180/CV_PI);
static const float atan2_p3 = -0.3258083974640975f*(float)(180/CV_PI);
static const float atan2_p5 = 0.1555786518463281f*(float)(180/CV_PI);
static const float atan2_p7 = -0.04432655554792128f*(float)(180/CV_PI);
#ifdef __EMSCRIPTEN__
static inline float atan_f32(float y, float x)
{
@ -42,11 +47,6 @@ static inline float atan_f32(float y, float x)
return a; // range [0; 360)
}
#else
static const float atan2_p1 = 0.9997878412794807f*(float)(180/CV_PI);
static const float atan2_p3 = -0.3258083974640975f*(float)(180/CV_PI);
static const float atan2_p5 = 0.1555786518463281f*(float)(180/CV_PI);
static const float atan2_p7 = -0.04432655554792128f*(float)(180/CV_PI);
static inline float atan_f32(float y, float x)
{
float ax = std::abs(x), ay = std::abs(y);

@ -267,6 +267,9 @@ static const String getBuildExtraOptions()
return param_buildExtraOptions;
}
static const bool CV_OPENCL_ENABLE_MEM_USE_HOST_PTR = utils::getConfigurationParameterBool("OPENCV_OPENCL_ENABLE_MEM_USE_HOST_PTR", true);
static const size_t CV_OPENCL_ALIGNMENT_MEM_USE_HOST_PTR = utils::getConfigurationParameterSizeT("OPENCV_OPENCL_ALIGNMENT_MEM_USE_HOST_PTR", 4);
#endif // HAVE_OPENCL
struct UMat2D
@ -4671,6 +4674,9 @@ public:
bool allocate(UMatData* u, AccessFlag accessFlags, UMatUsageFlags usageFlags) const CV_OVERRIDE
{
#ifndef HAVE_OPENCL
return false;
#else
if(!u)
return false;
@ -4746,8 +4752,12 @@ public:
#endif
{
tempUMatFlags = UMatData::TEMP_UMAT;
if (u->origdata == cv::alignPtr(u->origdata, 4) // There are OpenCL runtime issues for less aligned data
&& !(u->originalUMatData && u->originalUMatData->handle) // Avoid sharing of host memory between OpenCL buffers
if (CV_OPENCL_ENABLE_MEM_USE_HOST_PTR
// There are OpenCL runtime issues for less aligned data
&& (CV_OPENCL_ALIGNMENT_MEM_USE_HOST_PTR != 0
&& u->origdata == cv::alignPtr(u->origdata, (int)CV_OPENCL_ALIGNMENT_MEM_USE_HOST_PTR))
// Avoid sharing of host memory between OpenCL buffers
&& !(u->originalUMatData && u->originalUMatData->handle)
)
{
handle = clCreateBuffer(ctx_handle, CL_MEM_USE_HOST_PTR|createFlags,
@ -4777,6 +4787,7 @@ public:
u->markHostCopyObsolete(true);
opencl_allocator_stats.onAllocate(u->size);
return true;
#endif // HAVE_OPENCL
}
/*void sync(UMatData* u) const
@ -4905,7 +4916,7 @@ public:
(CL_MAP_READ | CL_MAP_WRITE),
0, u->size, 0, 0, 0, &retval);
CV_OCL_CHECK_RESULT(retval, cv::format("clEnqueueMapBuffer(handle=%p, sz=%lld) => %p", (void*)u->handle, (long long int)u->size, data).c_str());
CV_Assert(u->origdata == data);
CV_Assert(u->origdata == data && "Details: https://github.com/opencv/opencv/issues/6293");
if (u->originalUMatData)
{
CV_Assert(u->originalUMatData->data == data);

@ -54,7 +54,7 @@
#endif
#if defined __linux__ || defined __APPLE__ || defined __GLIBC__ \
|| defined __HAIKU__
|| defined __HAIKU__ || defined __EMSCRIPTEN__
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
@ -808,7 +808,7 @@ int cv::getNumberOfCPUs(void)
#elif defined __ANDROID__
static int ncpus = getNumberOfCPUsImpl();
return ncpus;
#elif defined __linux__ || defined __GLIBC__ || defined __HAIKU__
#elif defined __linux__ || defined __GLIBC__ || defined __HAIKU__ || defined __EMSCRIPTEN__
return (int)sysconf( _SC_NPROCESSORS_ONLN );
#elif defined __APPLE__
int numCPU=0;

@ -707,10 +707,10 @@ static void test_filestorage_basic(int write_flags, const char* suffix_name, boo
EXPECT_EQ(_em_in.depth(), _em_out.depth());
EXPECT_TRUE(_em_in.empty());
EXPECT_EQ(_2d_in.rows , _2d_out.rows);
EXPECT_EQ(_2d_in.cols , _2d_out.cols);
EXPECT_EQ(_2d_in.dims , _2d_out.dims);
EXPECT_EQ(_2d_in.depth(), _2d_out.depth());
ASSERT_EQ(_2d_in.rows , _2d_out.rows);
ASSERT_EQ(_2d_in.cols , _2d_out.cols);
ASSERT_EQ(_2d_in.dims , _2d_out.dims);
ASSERT_EQ(_2d_in.depth(), _2d_out.depth());
errors = 0;
for(int i = 0; i < _2d_out.rows; ++i)
@ -731,16 +731,16 @@ static void test_filestorage_basic(int write_flags, const char* suffix_name, boo
}
}
EXPECT_EQ(_nd_in.rows , _nd_out.rows);
EXPECT_EQ(_nd_in.cols , _nd_out.cols);
EXPECT_EQ(_nd_in.dims , _nd_out.dims);
EXPECT_EQ(_nd_in.depth(), _nd_out.depth());
ASSERT_EQ(_nd_in.rows , _nd_out.rows);
ASSERT_EQ(_nd_in.cols , _nd_out.cols);
ASSERT_EQ(_nd_in.dims , _nd_out.dims);
ASSERT_EQ(_nd_in.depth(), _nd_out.depth());
EXPECT_EQ(0, cv::norm(_nd_in, _nd_out, NORM_INF));
EXPECT_EQ(_rd_in.rows , _rd_out.rows);
EXPECT_EQ(_rd_in.cols , _rd_out.cols);
EXPECT_EQ(_rd_in.dims , _rd_out.dims);
EXPECT_EQ(_rd_in.depth(), _rd_out.depth());
ASSERT_EQ(_rd_in.rows , _rd_out.rows);
ASSERT_EQ(_rd_in.cols , _rd_out.cols);
ASSERT_EQ(_rd_in.dims , _rd_out.dims);
ASSERT_EQ(_rd_in.depth(), _rd_out.depth());
EXPECT_EQ(0, cv::norm(_rd_in, _rd_out, NORM_INF));
}
}

@ -2540,6 +2540,12 @@ struct Net::Impl
int requiredOutputs = layers[id].requiredOutputs.size();
inOutShapes[id].supportInPlace =
layers[id].getLayerInstance()->getMemoryShapes(is, requiredOutputs, os, ints);
for (int i = 0; i < ints.size(); i++)
CV_Assert(total(ints[i]) > 0);
for (int i = 0; i < os.size(); i++)
CV_Assert(total(os[i]) > 0);
}
void getLayersShapes(const ShapesVec& netInputShapes,

@ -241,10 +241,14 @@ public:
MatShape computeColRowShape(const MatShape &inpShape, const MatShape &outShape) const CV_OVERRIDE
{
Size out(outShape[3], outShape[2]);
int dims = inpShape.size();
int inpD = dims == 5 ? inpShape[2] : 1;
int inpH = inpShape[dims - 2];
int inpW = inpShape.back();
int inpGroupCn = blobs[0].size[1];
int ksize = inpGroupCn * kernel.height * kernel.width;
return shape(out.area(), ksize);
int ksize = inpGroupCn * std::accumulate(kernel_size.begin(), kernel_size.end(),
1, std::multiplies<size_t>());
return shape(inpD * inpH * inpW, ksize);
}
virtual bool supportBackend(int backendId) CV_OVERRIDE
@ -1304,14 +1308,17 @@ public:
MatShape computeColRowShape(const MatShape &inpShape, const MatShape &outShape) const CV_OVERRIDE
{
int dims = inpShape.size();
int inpCn = inpShape[1];
int inpH = inpShape[2];
int inpW = inpShape[3];
int inpD = dims == 5 ? inpShape[2] : 1;
int inpH = inpShape[dims - 2];
int inpW = inpShape.back();
int outCn = outShape[1];
int ngroups = inpCn / blobs[0].size[0];
int outGroupCn = outCn / ngroups;
int ksize = outGroupCn * kernel.height * kernel.width;
return shape(ksize, inpH * inpW);
int ksize = outGroupCn * std::accumulate(kernel_size.begin(), kernel_size.end(),
1, std::multiplies<size_t>());
return shape(ksize, inpD * inpH * inpW);
}
virtual bool supportBackend(int backendId) CV_OVERRIDE

@ -92,6 +92,7 @@ class LSTMLayerImpl CV_FINAL : public LSTMLayer
bool produceCellOutput;
float forgetBias, cellClip;
bool useCellClip, usePeephole;
bool reverse; // If true, go in negative direction along the time axis
public:
@ -133,6 +134,7 @@ public:
cellClip = params.get<float>("cell_clip", 0.0f);
useCellClip = params.get<bool>("use_cell_clip", false);
usePeephole = params.get<bool>("use_peephole", false);
reverse = params.get<bool>("reverse", false);
allocated = false;
outTailShape.clear();
@ -288,7 +290,18 @@ public:
Mat hOutTs = output[0].reshape(1, numSamplesTotal);
Mat cOutTs = produceCellOutput ? output[1].reshape(1, numSamplesTotal) : Mat();
for (int ts = 0; ts < numTimeStamps; ts++)
int tsStart, tsEnd, tsInc;
if (reverse) {
tsStart = numTimeStamps - 1;
tsEnd = -1;
tsInc = -1;
}
else {
tsStart = 0;
tsEnd = numTimeStamps;
tsInc = 1;
}
for (int ts = tsStart; ts != tsEnd; ts += tsInc)
{
Range curRowRange(ts*numSamples, (ts + 1)*numSamples);
Mat xCurr = xTs.rowRange(curRowRange);

@ -461,6 +461,55 @@ TEST(Layer_RNN_Test_Accuracy_with_, CaffeRecurrent)
normAssert(h_ref, output[0]);
}
TEST(Layer_LSTM_Test_Accuracy_, Reverse)
{
// This handcrafted setup calculates (approximately) the prefix sum of the
// input, assuming the inputs are suitably small.
cv::Mat input(2, 1, CV_32FC1);
input.at<float>(0, 0) = 1e-5f;
input.at<float>(1, 0) = 2e-5f;
cv::Mat Wx(4, 1, CV_32FC1);
Wx.at<float>(0, 0) = 0.f; // Input gate
Wx.at<float>(1, 0) = 0.f; // Forget gate
Wx.at<float>(2, 0) = 0.f; // Output gate
Wx.at<float>(3, 0) = 1.f; // Update signal
cv::Mat Wh(4, 1, CV_32FC1);
Wh.at<float>(0, 0) = 0.f; // Input gate
Wh.at<float>(1, 0) = 0.f; // Forget gate
Wh.at<float>(2, 0) = 0.f; // Output gate
Wh.at<float>(3, 0) = 0.f; // Update signal
cv::Mat bias(4, 1, CV_32FC1);
bias.at<float>(0, 0) = 1e10f; // Input gate - always allows input to c
bias.at<float>(1, 0) = 1e10f; // Forget gate - never forget anything on c
bias.at<float>(2, 0) = 1e10f; // Output gate - always output everything
bias.at<float>(3, 0) = 0.f; // Update signal
LayerParams lp;
lp.set("reverse", true);
lp.set("use_timestamp_dim", true);
lp.blobs.clear();
lp.blobs.push_back(Wh);
lp.blobs.push_back(Wx);
lp.blobs.push_back(bias);
cv::Ptr<cv::dnn::LSTMLayer> layer = LSTMLayer::create(lp);
std::vector<cv::Mat> outputs;
std::vector<cv::Mat> inputs;
inputs.push_back(input);
runLayer(layer, inputs, outputs);
ASSERT_EQ(1, outputs.size());
cv::Mat out = outputs[0];
ASSERT_EQ(3, out.dims);
ASSERT_EQ(shape(2, 1, 1), shape(out));
float* data = reinterpret_cast<float*>(out.data);
EXPECT_NEAR(std::tanh(1e-5f) + std::tanh(2e-5f), data[0], 1e-10);
EXPECT_NEAR(std::tanh(2e-5f), data[1], 1e-10);
}
class Layer_RNN_Test : public ::testing::Test
{

@ -105,7 +105,8 @@ TEST_P(Test_Model, Classify)
}
TEST_P(Test_Model, DetectRegion)
// disabled: https://github.com/opencv/opencv/pull/15593
TEST_P(Test_Model, DISABLED_DetectRegion)
{
applyTestTag(CV_TEST_TAG_LONG, CV_TEST_TAG_MEMORY_1GB);

@ -824,6 +824,7 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
for (size_t page = 0; page < img_vec.size(); page++)
{
const Mat& img = img_vec[page];
CV_Assert(!img.empty());
int channels = img.channels();
int width = img.cols, height = img.rows;
int type = img.type();
@ -883,6 +884,7 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
const int bitsPerByte = 8;
size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte;
CV_Assert(fileStep > 0);
int rowsPerStrip = (int)((1 << 13) / fileStep);
readParam(params, TIFFTAG_ROWSPERSTRIP, rowsPerStrip);

@ -664,6 +664,8 @@ static bool imwrite_( const String& filename, const std::vector<Mat>& img_vec,
for (size_t page = 0; page < img_vec.size(); page++)
{
Mat image = img_vec[page];
CV_Assert(!image.empty());
CV_Assert( image.channels() == 1 || image.channels() == 3 || image.channels() == 4 );
Mat temp;
@ -710,6 +712,9 @@ bool imwrite( const String& filename, InputArray _img,
const std::vector<int>& params )
{
CV_TRACE_FUNCTION();
CV_Assert(!_img.empty());
std::vector<Mat> img_vec;
if (_img.isMatVector() || _img.isUMatVector())
_img.getMatVector(img_vec);
@ -870,6 +875,7 @@ bool imencode( const String& ext, InputArray _image,
CV_TRACE_FUNCTION();
Mat image = _image.getMat();
CV_Assert(!image.empty());
int channels = image.channels();
CV_Assert( channels == 1 || channels == 3 || channels == 4 );

@ -87,13 +87,13 @@ template<typename T1, typename T2> int PyrUpVecV(T1**, T2**, int) { return 0; }
template<> int PyrDownVecH<uchar, int, 1>(const uchar* src, int* row, int width)
{
int x = 0;
const uchar *src0 = src, *src2 = src + 2, *src4 = src + 3;
const uchar *src01 = src, *src23 = src + 2, *src4 = src + 3;
v_int16 v_1_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040001));
v_int16 v_6_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040006));
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src0 += v_int16::nlanes, src2 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(v_reinterpret_as_s16(vx_load_expand(src0)), v_1_4) +
v_dotprod(v_reinterpret_as_s16(vx_load_expand(src2)), v_6_4) +
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src01 += v_int16::nlanes, src23 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(v_reinterpret_as_s16(vx_load_expand(src01)), v_1_4) +
v_dotprod(v_reinterpret_as_s16(vx_load_expand(src23)), v_6_4) +
(v_reinterpret_as_s32(vx_load_expand(src4)) >> 16));
vx_cleanup();
@ -102,13 +102,13 @@ template<> int PyrDownVecH<uchar, int, 1>(const uchar* src, int* row, int width)
template<> int PyrDownVecH<uchar, int, 2>(const uchar* src, int* row, int width)
{
int x = 0;
const uchar *src0 = src, *src2 = src + 4, *src4 = src + 6;
const uchar *src01 = src, *src23 = src + 4, *src4 = src + 6;
v_int16 v_1_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040001));
v_int16 v_6_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040006));
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src0 += v_int16::nlanes, src2 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(v_interleave_pairs(v_reinterpret_as_s16(vx_load_expand(src0))), v_1_4) +
v_dotprod(v_interleave_pairs(v_reinterpret_as_s16(vx_load_expand(src2))), v_6_4) +
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src01 += v_int16::nlanes, src23 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(v_interleave_pairs(v_reinterpret_as_s16(vx_load_expand(src01))), v_1_4) +
v_dotprod(v_interleave_pairs(v_reinterpret_as_s16(vx_load_expand(src23))), v_6_4) +
(v_reinterpret_as_s32(v_interleave_pairs(vx_load_expand(src4))) >> 16));
vx_cleanup();
@ -150,13 +150,13 @@ template<> int PyrDownVecH<uchar, int, 3>(const uchar* src, int* row, int width)
template<> int PyrDownVecH<uchar, int, 4>(const uchar* src, int* row, int width)
{
int x = 0;
const uchar *src0 = src, *src2 = src + 8, *src4 = src + 12;
const uchar *src01 = src, *src23 = src + 8, *src4 = src + 12;
v_int16 v_1_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040001));
v_int16 v_6_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040006));
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src0 += v_int16::nlanes, src2 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(v_interleave_quads(v_reinterpret_as_s16(vx_load_expand(src0))), v_1_4) +
v_dotprod(v_interleave_quads(v_reinterpret_as_s16(vx_load_expand(src2))), v_6_4) +
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src01 += v_int16::nlanes, src23 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(v_interleave_quads(v_reinterpret_as_s16(vx_load_expand(src01))), v_1_4) +
v_dotprod(v_interleave_quads(v_reinterpret_as_s16(vx_load_expand(src23))), v_6_4) +
(v_reinterpret_as_s32(v_interleave_quads(vx_load_expand(src4))) >> 16));
vx_cleanup();
@ -166,13 +166,13 @@ template<> int PyrDownVecH<uchar, int, 4>(const uchar* src, int* row, int width)
template<> int PyrDownVecH<short, int, 1>(const short* src, int* row, int width)
{
int x = 0;
const short *src0 = src, *src2 = src + 2, *src4 = src + 3;
const short *src01 = src, *src23 = src + 2, *src4 = src + 3;
v_int16 v_1_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040001));
v_int16 v_6_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040006));
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src0 += v_int16::nlanes, src2 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(vx_load(src0), v_1_4) +
v_dotprod(vx_load(src2), v_6_4) +
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src01 += v_int16::nlanes, src23 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(vx_load(src01), v_1_4) +
v_dotprod(vx_load(src23), v_6_4) +
(v_reinterpret_as_s32(vx_load(src4)) >> 16));
vx_cleanup();
@ -181,13 +181,13 @@ template<> int PyrDownVecH<short, int, 1>(const short* src, int* row, int width)
template<> int PyrDownVecH<short, int, 2>(const short* src, int* row, int width)
{
int x = 0;
const short *src0 = src, *src2 = src + 4, *src4 = src + 6;
const short *src01 = src, *src23 = src + 4, *src4 = src + 6;
v_int16 v_1_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040001));
v_int16 v_6_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040006));
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src0 += v_int16::nlanes, src2 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(v_interleave_pairs(vx_load(src0)), v_1_4) +
v_dotprod(v_interleave_pairs(vx_load(src2)), v_6_4) +
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src01 += v_int16::nlanes, src23 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(v_interleave_pairs(vx_load(src01)), v_1_4) +
v_dotprod(v_interleave_pairs(vx_load(src23)), v_6_4) +
(v_reinterpret_as_s32(v_interleave_pairs(vx_load(src4))) >> 16));
vx_cleanup();
@ -247,15 +247,15 @@ template<> int PyrDownVecH<short, int, 4>(const short* src, int* row, int width)
template<> int PyrDownVecH<ushort, int, 1>(const ushort* src, int* row, int width)
{
int x = 0;
const ushort *src0 = src, *src2 = src + 2, *src4 = src + 3;
const ushort *src01 = src, *src23 = src + 2, *src4 = src + 3;
v_int16 v_1_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040001));
v_int16 v_6_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040006));
v_uint16 v_half = vx_setall_u16(0x8000);
v_int32 v_half15 = vx_setall_s32(0x00078000);
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src0 += v_int16::nlanes, src2 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(v_reinterpret_as_s16(v_sub_wrap(vx_load(src0), v_half)), v_1_4) +
v_dotprod(v_reinterpret_as_s16(v_sub_wrap(vx_load(src2), v_half)), v_6_4) +
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src01 += v_int16::nlanes, src23 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(v_reinterpret_as_s16(v_sub_wrap(vx_load(src01), v_half)), v_1_4) +
v_dotprod(v_reinterpret_as_s16(v_sub_wrap(vx_load(src23), v_half)), v_6_4) +
v_reinterpret_as_s32(v_reinterpret_as_u32(vx_load(src4)) >> 16) + v_half15);
vx_cleanup();
@ -264,15 +264,15 @@ template<> int PyrDownVecH<ushort, int, 1>(const ushort* src, int* row, int widt
template<> int PyrDownVecH<ushort, int, 2>(const ushort* src, int* row, int width)
{
int x = 0;
const ushort *src0 = src, *src2 = src + 4, *src4 = src + 6;
const ushort *src01 = src, *src23 = src + 4, *src4 = src + 6;
v_int16 v_1_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040001));
v_int16 v_6_4 = v_reinterpret_as_s16(vx_setall_u32(0x00040006));
v_uint16 v_half = vx_setall_u16(0x8000);
v_int32 v_half15 = vx_setall_s32(0x00078000);
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src0 += v_int16::nlanes, src2 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(v_interleave_pairs(v_reinterpret_as_s16(v_sub_wrap(vx_load(src0), v_half))), v_1_4) +
v_dotprod(v_interleave_pairs(v_reinterpret_as_s16(v_sub_wrap(vx_load(src2), v_half))), v_6_4) +
for (; x <= width - v_int32::nlanes; x += v_int32::nlanes, src01 += v_int16::nlanes, src23 += v_int16::nlanes, src4 += v_int16::nlanes, row += v_int32::nlanes)
v_store(row, v_dotprod(v_interleave_pairs(v_reinterpret_as_s16(v_sub_wrap(vx_load(src01), v_half))), v_1_4) +
v_dotprod(v_interleave_pairs(v_reinterpret_as_s16(v_sub_wrap(vx_load(src23), v_half))), v_6_4) +
v_reinterpret_as_s32(v_reinterpret_as_u32(v_interleave_pairs(vx_load(src4))) >> 16) + v_half15);
vx_cleanup();
@ -344,15 +344,15 @@ template<> int PyrDownVecH<ushort, int, 4>(const ushort* src, int* row, int widt
template<> int PyrDownVecH<float, float, 1>(const float* src, float* row, int width)
{
int x = 0;
const float *src0 = src, *src2 = src + 2, *src4 = src + 4;
const float *src01 = src, *src23 = src + 2, *src4 = src + 3;
v_float32 _4 = vx_setall_f32(4.f), _6 = vx_setall_f32(6.f);
for (; x <= width - v_float32::nlanes; x += v_float32::nlanes, src0 += 2*v_float32::nlanes, src2 += 2*v_float32::nlanes, src4 += 2*v_float32::nlanes, row+=v_float32::nlanes)
for (; x <= width - v_float32::nlanes; x += v_float32::nlanes, src01 += 2*v_float32::nlanes, src23 += 2*v_float32::nlanes, src4 += 2*v_float32::nlanes, row+=v_float32::nlanes)
{
v_float32 r0, r1, r2, r3, r4, rtmp;
v_load_deinterleave(src0, r0, r1);
v_load_deinterleave(src2, r2, r3);
v_load_deinterleave(src4, r4, rtmp);
v_load_deinterleave(src01, r0, r1);
v_load_deinterleave(src23, r2, r3);
v_load_deinterleave(src4, rtmp, r4);
v_store(row, v_muladd(r2, _6, v_muladd(r1 + r3, _4, r0 + r4)));
}
vx_cleanup();
@ -362,14 +362,14 @@ template<> int PyrDownVecH<float, float, 1>(const float* src, float* row, int wi
template<> int PyrDownVecH<float, float, 2>(const float* src, float* row, int width)
{
int x = 0;
const float *src0 = src, *src2 = src + 4, *src4 = src + 6;
const float *src01 = src, *src23 = src + 4, *src4 = src + 6;
v_float32 _4 = vx_setall_f32(4.f), _6 = vx_setall_f32(6.f);
for (; x <= width - 2*v_float32::nlanes; x += 2*v_float32::nlanes, src0 += 4*v_float32::nlanes, src2 += 4*v_float32::nlanes, src4 += 4*v_float32::nlanes, row += 2*v_float32::nlanes)
for (; x <= width - 2*v_float32::nlanes; x += 2*v_float32::nlanes, src01 += 4*v_float32::nlanes, src23 += 4*v_float32::nlanes, src4 += 4*v_float32::nlanes, row += 2*v_float32::nlanes)
{
v_float32 r0a, r0b, r1a, r1b, r2a, r2b, r3a, r3b, r4a, r4b, rtmpa, rtmpb;
v_load_deinterleave(src0, r0a, r0b, r1a, r1b);
v_load_deinterleave(src2, r2a, r2b, r3a, r3b);
v_load_deinterleave(src01, r0a, r0b, r1a, r1b);
v_load_deinterleave(src23, r2a, r2b, r3a, r3b);
v_load_deinterleave(src4, rtmpa, rtmpb, r4a, r4b);
v_store_interleave(row, v_muladd(r2a, _6, v_muladd(r1a + r3a, _4, r0a + r4a)), v_muladd(r2b, _6, v_muladd(r1b + r3b, _4, r0b + r4b)));
}
@ -430,15 +430,15 @@ template<> int PyrDownVecH<float, float, 4>(const float* src, float* row, int wi
template<> int PyrDownVecH<double, double, 1>(const double* src, double* row, int width)
{
int x = 0;
const double *src0 = src, *src2 = src + 2, *src4 = src + 4;
const double *src01 = src, *src23 = src + 2, *src4 = src + 3;
v_float64 _4 = vx_setall_f64(4.f), _6 = vx_setall_f64(6.f);
for (; x <= width - v_float64::nlanes; x += v_float64::nlanes, src0 += 2*v_float64::nlanes, src2 += 2*v_float64::nlanes, src4 += 2*v_float64::nlanes, row += v_float64::nlanes)
for (; x <= width - v_float64::nlanes; x += v_float64::nlanes, src01 += 2*v_float64::nlanes, src23 += 2*v_float64::nlanes, src4 += 2*v_float64::nlanes, row += v_float64::nlanes)
{
v_float64 r0, r1, r2, r3, r4, rtmp;
v_load_deinterleave(src0, r0, r1);
v_load_deinterleave(src2, r2, r3);
v_load_deinterleave(src4, r4, rtmp);
v_load_deinterleave(src01, r0, r1);
v_load_deinterleave(src23, r2, r3);
v_load_deinterleave(src4, rtmp, r4);
v_store(row, v_muladd(r2, _6, v_muladd(r1 + r3, _4, r0 + r4)));
}
vx_cleanup();

@ -82,7 +82,17 @@ add_definitions("-std=c++11")
link_libraries(${OPENCV_MODULE_${the_module}_DEPS})
ocv_add_executable(${the_module} ${bindings_cpp})
OCV_OPTION(BUILD_WASM_INTRIN_TESTS "Build WASM intrin tests" OFF )
if(BUILD_WASM_INTRIN_TESTS)
add_definitions(-DTEST_WASM_INTRIN)
ocv_module_include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../ts/include")
ocv_module_include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../imgcodecs/include")
ocv_module_include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../videoio/include")
ocv_module_include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../highgui/include")
ocv_add_executable(${the_module} ${bindings_cpp} "${CMAKE_CURRENT_SOURCE_DIR}/../ts/src/ts_gtest.cpp")
else()
ocv_add_executable(${the_module} ${bindings_cpp})
endif()
set(COMPILE_FLAGS "")
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
@ -91,7 +101,7 @@ endif()
if(COMPILE_FLAGS)
set_target_properties(${the_module} PROPERTIES COMPILE_FLAGS ${COMPILE_FLAGS})
endif()
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} --memory-init-file 0 -s TOTAL_MEMORY=134217728 -s ALLOW_MEMORY_GROWTH=1")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} --memory-init-file 0 -s TOTAL_MEMORY=128MB -s WASM_MEM_MAX=1GB -s ALLOW_MEMORY_GROWTH=1")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s MODULARIZE=1 -s SINGLE_FILE=1")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s EXPORT_NAME=\"'cv'\" -s DEMANGLE_SUPPORT=1")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s FORCE_FILESYSTEM=1 --use-preload-plugins --bind --post-js ${JS_HELPER} ${COMPILE_FLAGS}")
@ -147,3 +157,26 @@ list(APPEND opencv_test_js_file_deps "${test_data_path}" "${opencv_test_js_bin_d
add_custom_target(${PROJECT_NAME}_test ALL
DEPENDS ${OCV_JS_PATH} ${opencv_test_js_file_deps})
# perf
set(opencv_perf_js_bin_dir "${EXECUTABLE_OUTPUT_PATH}/perf")
set(perf_dir ${CMAKE_CURRENT_SOURCE_DIR}/perf)
set(opencv_perf_js_file_deps "")
# make sure the build directory exists
file(MAKE_DIRECTORY "${opencv_perf_js_bin_dir}")
# gather and copy specific files for js perf
file(GLOB_RECURSE perf_files RELATIVE "${perf_dir}" "${perf_dir}/*")
foreach(f ${perf_files})
add_custom_command(OUTPUT "${opencv_perf_js_bin_dir}/${f}"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${perf_dir}/${f}" "${opencv_perf_js_bin_dir}/${f}"
DEPENDS "${perf_dir}/${f}"
COMMENT "Copying ${f}"
)
list(APPEND opencv_perf_js_file_deps "${perf_dir}/${f}" "${opencv_perf_js_bin_dir}/${f}")
endforeach()
add_custom_target(${PROJECT_NAME}_perf ALL
DEPENDS ${OCV_JS_PATH} ${opencv_perf_js_file_deps})

@ -0,0 +1,35 @@
# OpenCV.js Performance Test
## Node.js Version
### Prerequisites
1. node.js, npm: Make sure you have installed these beforehand with the system package manager.
2. Benchmark.js: Make sure you have installed Benchmark.js by npm before use. Please run `npm install` in the directory `<build_dir>/bin/perf`.
### How to Use
For example, if you want to test the performance of cvtColor, please run `perf_cvtcolor.js` by node in terminal:
```sh
node perf_cvtcolor.js
```
All tests of cvtColor will be run by above command.
If you just want to run one specific case, please use `--test_param_filter="()"` flag, like:
```sh
node perf_cvtcolor.js --test_param_filter="(1920x1080, COLOR_BGR2GRAY)"
```
## Browser Version
### How to Use
To run performance tests, please launch a local web server in <build_dir>/bin folder. For example, node http-server which serves on localhost:8080.
Navigate the web browser to the kernel page you want to test, like http://localhost:8080/perf/imgproc/cvtcolor.html.
You can input the paramater, and then click the `Run` button to run the specific case, or it will run all the cases.

@ -0,0 +1,18 @@
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),
}
if (typeof window === 'undefined') {
exports.cvSize = cvSize;
}

@ -0,0 +1,19 @@
{
"name": "opencv_js_perf",
"description": "Perfermance tests for opencv js bindings",
"version": "1.0.0",
"dependencies" : {
"benchmark" : "latest"
},
"repository": {
"type": "git",
"url": "https://github.com/opencv/opencv.git"
},
"keywords": [],
"author": "",
"license": "BSD-3-Clause",
"bugs": {
"url": "https://github.com/opencv/opencv/issues"
},
"homepage": "https://github.com/opencv/opencv"
}

@ -0,0 +1,59 @@
var fillGradient = function(cv, img, delta=5) {
let ch = img.channels();
console.assert(!img.empty() && img.depth() == cv.CV_8U && ch <= 4);
let n = 255 / delta;
for(let r = 0; r < img.rows; ++r) {
let kR = r % (2*n);
let valR = (kR<=n) ? delta*kR : delta*(2*n-kR);
for(let c = 0; c < img.cols; ++c) {
let kC = c % (2*n);
let valC = (kC<=n) ? delta*kC : delta*(2*n-kC);
let vals = [valR, valC, 200*r/img.rows, 255];
let p = img.ptr(r, c);
for(let i = 0; i < ch; ++i) p[i] = vals[i];
}
}
}
var cvtStr2cvSize = function(strSize) {
let size;
switch(strSize) {
case "127,61": size = cvSize.szODD;break;
case '320,240': size = cvSize.szQVGA;break;
case '640,480': size = cvSize.szVGA;break;
case '960,540': size = cvSize.szqHD;break;
case '1280,720': size = cvSize.sz720p;break;
case '1920,1080': size = cvSize.sz1080p;break;
case "130,60": size = cvSize.sz130x60;break;
case '213,120': size = cvSize.sz213x120;break;
default: console.error("unsupported size for this case");
}
return size;
}
var combine = function() {
let result = [[]];
for (let i = 0; i < arguments.length; ++i) {
result = permute(result, arguments[i]);
}
return result;
}
function permute (source, target) {
let result = [];
for (let i = 0; i < source.length; ++i) {
for (let j = 0; j < target.length; ++j) {
let tmp = source[i].slice();
tmp.push(target[j]);
result.push(tmp);
}
}
return result;
}
if (typeof window === 'undefined') {
exports.fillGradient = fillGradient;
exports.cvtStr2cvSize = cvtStr2cvSize;
exports.combine = combine;
}

@ -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>CvtColor</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,COLOR_RGBA2GRAY)
</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_cvtcolor.js"></script>
</body>
</html>

@ -0,0 +1,572 @@
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');
}
cv.onRuntimeInitialized = () => {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.cvSize;
} else {
runButton.removeAttribute('disabled');
runButton.setAttribute('class', 'btn btn-primary');
runButton.innerHTML = 'Run';
}
let totalCaseNum, currentCaseId;
//extra color conversions supported implicitly
{
cv.CX_BGRA2HLS = cv.COLOR_COLORCVT_MAX + cv.COLOR_BGR2HLS,
cv.CX_BGRA2HLS_FULL = cv.COLOR_COLORCVT_MAX + cv.COLOR_BGR2HLS_FULL,
cv.CX_BGRA2HSV = cv.COLOR_COLORCVT_MAX + cv.COLOR_BGR2HSV,
cv.CX_BGRA2HSV_FULL = cv.COLOR_COLORCVT_MAX + cv.COLOR_BGR2HSV_FULL,
cv.CX_BGRA2Lab = cv.COLOR_COLORCVT_MAX + cv.COLOR_BGR2Lab,
cv.CX_BGRA2Luv = cv.COLOR_COLORCVT_MAX + cv.COLOR_BGR2Luv,
cv.CX_BGRA2XYZ = cv.COLOR_COLORCVT_MAX + cv.COLOR_BGR2XYZ,
cv.CX_BGRA2YCrCb = cv.COLOR_COLORCVT_MAX + cv.COLOR_BGR2YCrCb,
cv.CX_BGRA2YUV = cv.COLOR_COLORCVT_MAX + cv.COLOR_BGR2YUV,
cv.CX_HLS2BGRA = cv.COLOR_COLORCVT_MAX + cv.COLOR_HLS2BGR,
cv.CX_HLS2BGRA_FULL = cv.COLOR_COLORCVT_MAX + cv.COLOR_HLS2BGR_FULL,
cv.CX_HLS2RGBA = cv.COLOR_COLORCVT_MAX + cv.COLOR_HLS2RGB,
cv.CX_HLS2RGBA_FULL = cv.COLOR_COLORCVT_MAX + cv.COLOR_HLS2RGB_FULL,
cv.CX_HSV2BGRA = cv.COLOR_COLORCVT_MAX + cv.COLOR_HSV2BGR,
cv.CX_HSV2BGRA_FULL = cv.COLOR_COLORCVT_MAX + cv.COLOR_HSV2BGR_FULL,
cv.CX_HSV2RGBA = cv.COLOR_COLORCVT_MAX + cv.COLOR_HSV2RGB,
cv.CX_HSV2RGBA_FULL = cv.COLOR_COLORCVT_MAX + cv.COLOR_HSV2RGB_FULL,
cv.CX_Lab2BGRA = cv.COLOR_COLORCVT_MAX + cv.COLOR_Lab2BGR,
cv.CX_Lab2LBGRA = cv.COLOR_COLORCVT_MAX + cv.COLOR_Lab2LBGR,
cv.CX_Lab2LRGBA = cv.COLOR_COLORCVT_MAX + cv.COLOR_Lab2LRGB,
cv.CX_Lab2RGBA = cv.COLOR_COLORCVT_MAX + cv.COLOR_Lab2RGB,
cv.CX_LBGRA2Lab = cv.COLOR_COLORCVT_MAX + cv.COLOR_LBGR2Lab,
cv.CX_LBGRA2Luv = cv.COLOR_COLORCVT_MAX + cv.COLOR_LBGR2Luv,
cv.CX_LRGBA2Lab = cv.COLOR_COLORCVT_MAX + cv.COLOR_LRGB2Lab,
cv.CX_LRGBA2Luv = cv.COLOR_COLORCVT_MAX + cv.COLOR_LRGB2Luv,
cv.CX_Luv2BGRA = cv.COLOR_COLORCVT_MAX + cv.COLOR_Luv2BGR,
cv.CX_Luv2LBGRA = cv.COLOR_COLORCVT_MAX + cv.COLOR_Luv2LBGR,
cv.CX_Luv2LRGBA = cv.COLOR_COLORCVT_MAX + cv.COLOR_Luv2LRGB,
cv.CX_Luv2RGBA = cv.COLOR_COLORCVT_MAX + cv.COLOR_Luv2RGB,
cv.CX_RGBA2HLS = cv.COLOR_COLORCVT_MAX + cv.COLOR_RGB2HLS,
cv.CX_RGBA2HLS_FULL = cv.COLOR_COLORCVT_MAX + cv.COLOR_RGB2HLS_FULL,
cv.CX_RGBA2HSV = cv.COLOR_COLORCVT_MAX + cv.COLOR_RGB2HSV,
cv.CX_RGBA2HSV_FULL = cv.COLOR_COLORCVT_MAX + cv.COLOR_RGB2HSV_FULL,
cv.CX_RGBA2Lab = cv.COLOR_COLORCVT_MAX + cv.COLOR_RGB2Lab,
cv.CX_RGBA2Luv = cv.COLOR_COLORCVT_MAX + cv.COLOR_RGB2Luv,
cv.CX_RGBA2XYZ = cv.COLOR_COLORCVT_MAX + cv.COLOR_RGB2XYZ,
cv.CX_RGBA2YCrCb = cv.COLOR_COLORCVT_MAX + cv.COLOR_RGB2YCrCb,
cv.CX_RGBA2YUV = cv.COLOR_COLORCVT_MAX + cv.COLOR_RGB2YUV,
cv.CX_XYZ2BGRA = cv.COLOR_COLORCVT_MAX + cv.COLOR_XYZ2BGR,
cv.CX_XYZ2RGBA = cv.COLOR_COLORCVT_MAX + cv.COLOR_XYZ2RGB,
cv.CX_YCrCb2BGRA = cv.COLOR_COLORCVT_MAX + cv.COLOR_YCrCb2BGR,
cv.CX_YCrCb2RGBA = cv.COLOR_COLORCVT_MAX + cv.COLOR_YCrCb2RGB,
cv.CX_YUV2BGRA = cv.COLOR_COLORCVT_MAX + cv.COLOR_YUV2BGR,
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",
"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 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",
"COLOR_Luv2BGR", "COLOR_Luv2LBGR", "COLOR_Luv2LRGB", "COLOR_Luv2RGB",
"CX_Luv2BGRA", "CX_Luv2LBGRA", "CX_Luv2LRGBA", "CX_Luv2RGBA",
"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_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 CvtMode32FSize = [cvSize.szODD, cvSize.szVGA, cvSize.sz1080p];
const combiCvtMode32F = combine(CvtMode32FSize, CvtMode32F);
const CvtModeBayer = [
"COLOR_BayerBG2BGR", "COLOR_BayerBG2BGRA", "COLOR_BayerBG2BGR_VNG", "COLOR_BayerBG2GRAY",
"COLOR_BayerGB2BGR", "COLOR_BayerGB2BGRA", "COLOR_BayerGB2BGR_VNG", "COLOR_BayerGB2GRAY",
"COLOR_BayerGR2BGR", "COLOR_BayerGR2BGRA", "COLOR_BayerGR2BGR_VNG", "COLOR_BayerGR2GRAY",
"COLOR_BayerRG2BGR", "COLOR_BayerRG2BGRA", "COLOR_BayerRG2BGR_VNG", "COLOR_BayerRG2GRAY"
];
const CvtModeBayerSize = [cvSize.szODD, cvSize.szVGA];
const combiCvtModeBayer = combine(CvtModeBayerSize, CvtModeBayer);
const CvtMode2 = [
"COLOR_YUV2BGR_NV12", "COLOR_YUV2BGRA_NV12", "COLOR_YUV2RGB_NV12", "COLOR_YUV2RGBA_NV12", "COLOR_YUV2BGR_NV21", "COLOR_YUV2BGRA_NV21", "COLOR_YUV2RGB_NV21", "COLOR_YUV2RGBA_NV21",
"COLOR_YUV2BGR_YV12", "COLOR_YUV2BGRA_YV12", "COLOR_YUV2RGB_YV12", "COLOR_YUV2RGBA_YV12", "COLOR_YUV2BGR_IYUV", "COLOR_YUV2BGRA_IYUV", "COLOR_YUV2RGB_IYUV", "COLOR_YUV2RGBA_IYUV",
"COLOR_YUV2GRAY_420", "COLOR_YUV2RGB_UYVY", "COLOR_YUV2BGR_UYVY", "COLOR_YUV2RGBA_UYVY", "COLOR_YUV2BGRA_UYVY", "COLOR_YUV2RGB_YUY2", "COLOR_YUV2BGR_YUY2", "COLOR_YUV2RGB_YVYU",
"COLOR_YUV2BGR_YVYU", "COLOR_YUV2RGBA_YUY2", "COLOR_YUV2BGRA_YUY2", "COLOR_YUV2RGBA_YVYU", "COLOR_YUV2BGRA_YVYU"
];
const CvtMode2Size = [cvSize.szVGA, cvSize.sz1080p, cvSize.sz130x60];
const combiCvtMode2 = combine(CvtMode2Size, CvtMode2);
const CvtMode3 = [
"COLOR_RGB2YUV_IYUV", "COLOR_BGR2YUV_IYUV", "COLOR_RGBA2YUV_IYUV", "COLOR_BGRA2YUV_IYUV",
"COLOR_RGB2YUV_YV12", "COLOR_BGR2YUV_YV12", "COLOR_RGBA2YUV_YV12", "COLOR_BGRA2YUV_YV12"
];
const CvtMode3Size = [cvSize.szVGA, cvSize.sz720p, cvSize.sz1080p, cvSize.sz130x60];
const combiCvtMode3 = combine(CvtMode3Size, CvtMode3);
const EdgeAwareBayerMode = [
"COLOR_BayerBG2BGR_EA", "COLOR_BayerGB2BGR_EA", "COLOR_BayerRG2BGR_EA", "COLOR_BayerGR2BGR_EA"
];
const EdgeAwareBayerModeSize = [cvSize.szVGA, cvSize.sz720p, cvSize.sz1080p, cvSize.sz130x60];
const combiEdgeAwareBayer = combine(EdgeAwareBayerModeSize, EdgeAwareBayerMode);
// This function returns an array. The 1st element is the channel number of
// source mat and 2nd element is the channel number of destination mat.
function getConversionInfo(cvtMode) {
switch(cvtMode) {
case "COLOR_BayerBG2GRAY": case "COLOR_BayerGB2GRAY":
case "COLOR_BayerGR2GRAY": case "COLOR_BayerRG2GRAY":
case "COLOR_YUV2GRAY_420":
return [1, 1];
case "COLOR_GRAY2BGR555": case "COLOR_GRAY2BGR565":
return [1, 2];
case "COLOR_BayerBG2BGR": case "COLOR_BayerBG2BGR_VNG":
case "COLOR_BayerGB2BGR": case "COLOR_BayerGB2BGR_VNG":
case "COLOR_BayerGR2BGR": case "COLOR_BayerGR2BGR_VNG":
case "COLOR_BayerRG2BGR": case "COLOR_BayerRG2BGR_VNG":
case "COLOR_GRAY2BGR":
case "COLOR_YUV2BGR_NV12": case "COLOR_YUV2RGB_NV12":
case "COLOR_YUV2BGR_NV21": case "COLOR_YUV2RGB_NV21":
case "COLOR_YUV2BGR_YV12": case "COLOR_YUV2RGB_YV12":
case "COLOR_YUV2BGR_IYUV": case "COLOR_YUV2RGB_IYUV":
return [1, 3];
case "COLOR_GRAY2BGRA":
case "COLOR_YUV2BGRA_NV12": case "COLOR_YUV2RGBA_NV12":
case "COLOR_YUV2BGRA_NV21": case "COLOR_YUV2RGBA_NV21":
case "COLOR_YUV2BGRA_YV12": case "COLOR_YUV2RGBA_YV12":
case "COLOR_YUV2BGRA_IYUV": case "COLOR_YUV2RGBA_IYUV":
case "COLOR_BayerBG2BGRA": case "COLOR_BayerGB2BGRA":
case "COLOR_BayerGR2BGRA": case "COLOR_BayerRG2BGRA":
return [1, 4];
case "COLOR_BGR5552GRAY": case "COLOR_BGR5652GRAY":
return [2, 1];
case "COLOR_BGR5552BGR": case "COLOR_BGR5552RGB":
case "COLOR_BGR5652BGR": case "COLOR_BGR5652RGB":
case "COLOR_YUV2RGB_UYVY": case "COLOR_YUV2BGR_UYVY":
case "COLOR_YUV2RGB_YUY2": case "COLOR_YUV2BGR_YUY2":
case "COLOR_YUV2RGB_YVYU": case "COLOR_YUV2BGR_YVYU":
return [2, 3];
case "COLOR_BGR5552BGRA": case "COLOR_BGR5552RGBA":
case "COLOR_BGR5652BGRA": case "COLOR_BGR5652RGBA":
case "COLOR_YUV2RGBA_UYVY": case "COLOR_YUV2BGRA_UYVY":
case "COLOR_YUV2RGBA_YUY2": case "COLOR_YUV2BGRA_YUY2":
case "COLOR_YUV2RGBA_YVYU": case "COLOR_YUV2BGRA_YVYU":
return [2, 4];
case "COLOR_BGR2GRAY": case "COLOR_RGB2GRAY":
case "COLOR_RGB2YUV_IYUV": case "COLOR_RGB2YUV_YV12":
case "COLOR_BGR2YUV_IYUV": case "COLOR_BGR2YUV_YV12":
return [3, 1];
case "COLOR_BGR2BGR555": case "COLOR_BGR2BGR565":
case "COLOR_RGB2BGR555": case "COLOR_RGB2BGR565":
return [3, 2];
case "COLOR_BGR2HLS": case "COLOR_BGR2HLS_FULL":
case "COLOR_BGR2HSV": case "COLOR_BGR2HSV_FULL":
case "COLOR_BGR2Lab": case "COLOR_BGR2Luv":
case "COLOR_BGR2RGB": case "COLOR_BGR2XYZ":
case "COLOR_BGR2YCrCb": case "COLOR_BGR2YUV":
case "COLOR_HLS2BGR": case "COLOR_HLS2BGR_FULL":
case "COLOR_HLS2RGB": case "COLOR_HLS2RGB_FULL":
case "COLOR_HSV2BGR": case "COLOR_HSV2BGR_FULL":
case "COLOR_HSV2RGB": case "COLOR_HSV2RGB_FULL":
case "COLOR_Lab2BGR": case "COLOR_Lab2LBGR":
case "COLOR_Lab2LRGB": case "COLOR_Lab2RGB":
case "COLOR_LBGR2Lab": case "COLOR_LBGR2Luv":
case "COLOR_LRGB2Lab": case "COLOR_LRGB2Luv":
case "COLOR_Luv2BGR": case "COLOR_Luv2LBGR":
case "COLOR_Luv2LRGB": case "COLOR_Luv2RGB":
case "COLOR_RGB2HLS": case "COLOR_RGB2HLS_FULL":
case "COLOR_RGB2HSV": case "COLOR_RGB2HSV_FULL":
case "COLOR_RGB2Lab": case "COLOR_RGB2Luv":
case "COLOR_RGB2XYZ": case "COLOR_RGB2YCrCb":
case "COLOR_RGB2YUV": case "COLOR_XYZ2BGR":
case "COLOR_XYZ2RGB": case "COLOR_YCrCb2BGR":
case "COLOR_YCrCb2RGB": case "COLOR_YUV2BGR":
case "COLOR_YUV2RGB":
return [3, 3];
case "COLOR_BGR2BGRA": case "COLOR_BGR2RGBA":
case "CX_HLS2BGRA": case "CX_HLS2BGRA_FULL":
case "CX_HLS2RGBA": case "CX_HLS2RGBA_FULL":
case "CX_HSV2BGRA": case "CX_HSV2BGRA_FULL":
case "CX_HSV2RGBA": case "CX_HSV2RGBA_FULL":
case "CX_Lab2BGRA": case "CX_Lab2LBGRA":
case "CX_Lab2LRGBA": case "CX_Lab2RGBA":
case "CX_Luv2BGRA": case "CX_Luv2LBGRA":
case "CX_Luv2LRGBA": case "CX_Luv2RGBA":
case "CX_XYZ2BGRA": case "CX_XYZ2RGBA":
case "CX_YCrCb2BGRA": case "CX_YCrCb2RGBA":
case "CX_YUV2BGRA": case "CX_YUV2RGBA":
return [3, 4];
case "COLOR_BGRA2GRAY": case "COLOR_RGBA2GRAY":
case "COLOR_RGBA2YUV_IYUV": case "COLOR_RGBA2YUV_YV12":
case "COLOR_BGRA2YUV_IYUV": case "COLOR_BGRA2YUV_YV12":
return [4, 1];
case "COLOR_BGRA2BGR555": case "COLOR_BGRA2BGR565":
case "COLOR_RGBA2BGR555": case "COLOR_RGBA2BGR565":
return [4, 2];
case "COLOR_BGRA2BGR": case "CX_BGRA2HLS":
case "CX_BGRA2HLS_FULL": case "CX_BGRA2HSV":
case "CX_BGRA2HSV_FULL": case "CX_BGRA2Lab":
case "CX_BGRA2Luv": case "CX_BGRA2XYZ":
case "CX_BGRA2YCrCb": case "CX_BGRA2YUV":
case "CX_LBGRA2Lab": case "CX_LBGRA2Luv":
case "CX_LRGBA2Lab": case "CX_LRGBA2Luv":
case "COLOR_RGBA2BGR": case "CX_RGBA2HLS":
case "CX_RGBA2HLS_FULL": case "CX_RGBA2HSV":
case "CX_RGBA2HSV_FULL": case "CX_RGBA2Lab":
case "CX_RGBA2Luv": case "CX_RGBA2XYZ":
case "CX_RGBA2YCrCb": case "CX_RGBA2YUV":
return [4, 3];
case "COLOR_BGRA2RGBA":
return [4, 4];
default:
console.error("Unknown conversion type");
break;
};
return [0, 0];
}
function getMatType(chPair) {
let dataType = "8U"; // now just support "8U" data type, we can set it as a param to extend the data type later.
let mat1Type, mat2Type;
if (chPair[0] === 0) {
mat1Type = `CV_${dataType}C`;
} else {
mat1Type = `CV_${dataType}C${chPair[0].toString()}`;
}
if (chPair[1] === 0) {
mat2Type = `CV_${dataType}C`;
} else {
mat2Type = `CV_${dataType}C${chPair[1].toString()}`;
}
return [mat1Type, mat2Type];
}
function addCvtColorCase(suite) {
suite.add('cvtColor', function() {
cv.cvtColor(mat1, mat2, mode, 0);
}, {
'setup': function() {
let size = this.params.size;
let matType = this.params.matType;
let mode = cv[this.params.mode]%cv.COLOR_COLORCVT_MAX;
let mat1 = new cv.Mat(size[1], size[0], cv[matType[0]]);
let mat2 = new cv.Mat(size[1], size[0], cv[matType[1]]);
},
'teardown': function() {
mat1.delete();
mat2.delete();
}
});
}
function addCvtModeCase(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 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';
}
});
}
function genBenchmarkCase(paramsContent) {
let suite = new Benchmark.Suite;
totalCaseNum = 0;
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);
} else {
log("no filter or getting invalid params, run all the cases");
addCvtModeCase(suite, combiCvtMode);
addCvtModeBayerCase(suite, combiCvtModeBayer);
addCvtMode2Case(suite, combiCvtMode2);
addCvtMode3Case(suite, combiCvtMode3);
}
setBenchmarkSuite(suite);
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
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";
}
}
}
};

@ -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>Resize</h7>
</div>
<div>
<h4>Parameters Filter</h4>
<input type="text" id="params" min="1" size="40" placeholder="default: run all the case"/> for example: (CV_8UC1,640x480,960x540)
</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_resize.js"></script>
</body>
</html>

@ -0,0 +1,262 @@
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');
}
cv.onRuntimeInitialized = () => {
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;
} else {
runButton.removeAttribute('disabled');
runButton.setAttribute('class', 'btn btn-primary');
runButton.innerHTML = 'Run';
}
let totalCaseNum, currentCaseId;
const matTypesUpLinear = ['CV_8UC1', 'CV_8UC2', 'CV_8UC3', 'CV_8UC4'];
const size1UpLinear = [cvSize.szVGA];
const size2UpLinear = [cvSize.szqHD, cvSize.sz720p];
const combiUpLinear = combine(matTypesUpLinear, size1UpLinear, size2UpLinear);
const combiDownLinear = [
['CV_8UC1', cvSize.szVGA, cvSize.szQVGA],
['CV_8UC2', cvSize.szVGA, cvSize.szQVGA],
['CV_8UC3', cvSize.szVGA, cvSize.szQVGA],
['CV_8UC4', cvSize.szVGA, cvSize.szQVGA],
['CV_8UC1', cvSize.szqHD, cvSize.szVGA],
['CV_8UC2', cvSize.szqHD, cvSize.szVGA],
['CV_8UC3', cvSize.szqHD, cvSize.szVGA],
['CV_8UC4', cvSize.szqHD, cvSize.szVGA],
['CV_8UC1', cvSize.sz720p, cvSize.sz213x120],// face detection min_face_size = 20%
['CV_8UC2', cvSize.sz720p, cvSize.sz213x120],// face detection min_face_size = 20%
['CV_8UC3', cvSize.sz720p, cvSize.sz213x120],// face detection min_face_size = 20%
['CV_8UC4', cvSize.sz720p, cvSize.sz213x120],// face detection min_face_size = 20%
['CV_8UC1', cvSize.sz720p, cvSize.szVGA],
['CV_8UC2', cvSize.sz720p, cvSize.szVGA],
['CV_8UC3', cvSize.sz720p, cvSize.szVGA],
['CV_8UC4', cvSize.sz720p, cvSize.szVGA],
['CV_8UC1', cvSize.sz720p, cvSize.szQVGA],
['CV_8UC2', cvSize.sz720p, cvSize.szQVGA],
['CV_8UC3', cvSize.sz720p, cvSize.szQVGA],
['CV_8UC4', cvSize.sz720p, cvSize.szQVGA]
];
const matTypesAreaFast = ['CV_8UC1', 'CV_8UC3', 'CV_8UC4', 'CV_16UC1', 'CV_16UC3', 'CV_16UC4'];
const sizesAreaFast = [cvSize.szVGA, cvSize.szqHD, cvSize.sz720p, cvSize.sz1080p];
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() {
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 addResizeAreaFastCase(suite, combination) {
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]]);
}
}
}
}
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);
} else {
log("no filter or getting invalid params, run all the cases");
addResizeUpLinearCase(suite, combiUpLinear);
addResizeDownLinearCase(suite, combiDownLinear);
}
setBenchmarkSuite(suite);
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
if (isNodeJs) {
const args = process.argv.slice(2);
let paramsContent = '';
if (/--test_param_filter=\(\w+,[\ ]*[0-9]+x[0-9]+,[\ ]*[0-9]+x[0-9]+\)/g.test(args.toString())) {
paramsContent = args.toString().match(/\(\w+,[\ ]*[0-9]+x[0-9]+,[\ ]*[0-9]+x[0-9]+\)/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";
}
}
}
};

@ -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>Threshold</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_8UC1, THRESH_BINARY)
</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_threshold.js"></script>
</body>
</html>

@ -0,0 +1,217 @@
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');
}
cv.onRuntimeInitialized = () => {
console.log('opencv.js loaded');
if (isNodeJs) {
global.cv = cv;
global.combine = HelpFunc.combine;
global.cvtStr2cvSize = HelpFunc.cvtStr2cvSize;
global.cvSize = Base.cvSize;
} else {
runButton.removeAttribute('disabled');
runButton.setAttribute('class', 'btn btn-primary');
runButton.innerHTML = 'Run';
}
let totalCaseNum, currentCaseId;
const typicalMatSizes = [cvSize.szVGA, cvSize.sz720p, cvSize.sz1080p, cvSize.szODD];
const matTypes = ['CV_8UC1', 'CV_16SC1', 'CV_32FC1', 'CV_64FC1'];
const threshTypes = ['THRESH_BINARY', 'THRESH_BINARY_INV', 'THRESH_TRUNC', 'THRESH_TOZERO', 'THRESH_TOZERO_INV'];
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() {
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();
}
});
// set init params
let index = suite.length - 1;
suite[index].params = {
matSize: matSize,
matType: matType,
threshType: threshType
};
}
}
function addSizeOnlyCase(suite, combination) {
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]]);
}
}
}
}
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);
} 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);
}
else {
log("no filter or getting invalid params, run all the cases");
addSizeMatTypeThreshTypeCase(suite, combiSizeMatTypeThreshType);
addSizeOnlyCase(suite, combiSizeOnly);
}
setBenchmarkSuite(suite);
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];
} 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];
}
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";
}
}
}
};

@ -71,6 +71,18 @@
#include <emscripten/bind.h>
@INCLUDES@
#include "../../../modules/core/src/parallel_impl.hpp"
#ifdef TEST_WASM_INTRIN
#include "../../../modules/core/include/opencv2/core/hal/intrin.hpp"
#include "../../../modules/core/include/opencv2/core/utils/trace.hpp"
#include "../../../modules/ts/include/opencv2/ts/ts_gtest.h"
namespace cv {
namespace hal {
#include "../../../modules/core/test/test_intrin_utils.hpp"
}
}
#endif
using namespace emscripten;
using namespace cv;
@ -368,6 +380,51 @@ namespace binding_utils
std::string getBuildInformation() {
return cv::getBuildInformation();
}
#ifdef TEST_WASM_INTRIN
void test_hal_intrin_uint8() {
cv::hal::test_hal_intrin_uint8();
}
void test_hal_intrin_int8() {
cv::hal::test_hal_intrin_int8();
}
void test_hal_intrin_uint16() {
cv::hal::test_hal_intrin_uint16();
}
void test_hal_intrin_int16() {
cv::hal::test_hal_intrin_int16();
}
void test_hal_intrin_uint32() {
cv::hal::test_hal_intrin_uint32();
}
void test_hal_intrin_int32() {
cv::hal::test_hal_intrin_int32();
}
void test_hal_intrin_uint64() {
cv::hal::test_hal_intrin_uint64();
}
void test_hal_intrin_int64() {
cv::hal::test_hal_intrin_int64();
}
void test_hal_intrin_float32() {
cv::hal::test_hal_intrin_float32();
}
void test_hal_intrin_float64() {
cv::hal::test_hal_intrin_float64();
}
void test_hal_intrin_all() {
cv::hal::test_hal_intrin_uint8();
cv::hal::test_hal_intrin_int8();
cv::hal::test_hal_intrin_uint16();
cv::hal::test_hal_intrin_int16();
cv::hal::test_hal_intrin_uint32();
cv::hal::test_hal_intrin_int32();
cv::hal::test_hal_intrin_uint64();
cv::hal::test_hal_intrin_int64();
cv::hal::test_hal_intrin_float32();
cv::hal::test_hal_intrin_float64();
}
#endif
}
EMSCRIPTEN_BINDINGS(binding_utils)
@ -542,10 +599,10 @@ EMSCRIPTEN_BINDINGS(binding_utils)
.field("distance", &cv::DMatch::distance);
emscripten::value_array<cv::Scalar_<double>> ("Scalar")
.element(index<0>())
.element(index<1>())
.element(index<2>())
.element(index<3>());
.element(emscripten::index<0>())
.element(emscripten::index<1>())
.element(emscripten::index<2>())
.element(emscripten::index<3>());
emscripten::value_object<binding_utils::MinMaxLoc>("MinMaxLoc")
.field("minVal", &binding_utils::MinMaxLoc::minVal)
@ -621,6 +678,25 @@ EMSCRIPTEN_BINDINGS(binding_utils)
function("getBuildInformation", &binding_utils::getBuildInformation);
#ifdef HAVE_PTHREADS_PF
function("parallel_pthreads_set_threads_num", &cv::parallel_pthreads_set_threads_num);
function("parallel_pthreads_get_threads_num", &cv::parallel_pthreads_get_threads_num);
#endif
#ifdef TEST_WASM_INTRIN
function("test_hal_intrin_uint8", &binding_utils::test_hal_intrin_uint8);
function("test_hal_intrin_int8", &binding_utils::test_hal_intrin_int8);
function("test_hal_intrin_uint16", &binding_utils::test_hal_intrin_uint16);
function("test_hal_intrin_int16", &binding_utils::test_hal_intrin_int16);
function("test_hal_intrin_uint32", &binding_utils::test_hal_intrin_uint32);
function("test_hal_intrin_int32", &binding_utils::test_hal_intrin_int32);
function("test_hal_intrin_uint64", &binding_utils::test_hal_intrin_uint64);
function("test_hal_intrin_int64", &binding_utils::test_hal_intrin_int64);
function("test_hal_intrin_float32", &binding_utils::test_hal_intrin_float32);
function("test_hal_intrin_float64", &binding_utils::test_hal_intrin_float64);
function("test_hal_intrin_all", &binding_utils::test_hal_intrin_all);
#endif
constant("CV_8UC1", CV_8UC1);
constant("CV_8UC2", CV_8UC2);
constant("CV_8UC3", CV_8UC3);

@ -87,9 +87,15 @@ def make_umd(opencvjs, cvjs):
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory();
} else {
} else if (typeof window === 'object') {
// Browser globals
root.cv = factory();
} else if (typeof importScripts === 'function') {
// Web worker
root.cv = factory;
} else {
// Other shells, e.g. d8
root.cv = factory();
}
}(this, function () {
%s

@ -848,6 +848,7 @@ public:
bool train( const Ptr<TrainData>& trainData, int flags ) CV_OVERRIDE
{
CV_Assert(!trainData.empty());
const int MAX_ITER = 1000;
const double DEFAULT_EPSILON = FLT_EPSILON;
@ -883,6 +884,7 @@ public:
}
int train_anneal(const Ptr<TrainData>& trainData)
{
CV_Assert(!trainData.empty());
SimulatedAnnealingANN_MLP s(*this, trainData);
trained = true; // Enable call to CalcError
int iter = simulatedAnnealingSolver(s, params.initialT, params.finalT, params.coolingRatio, params.itePerStep, NULL, params.rEnergy);

@ -88,6 +88,7 @@ public:
void startTraining( const Ptr<TrainData>& trainData, int flags ) CV_OVERRIDE
{
CV_Assert(!trainData.empty());
DTreesImpl::startTraining(trainData, flags);
sumResult.assign(w->sidx.size(), 0.);
@ -184,6 +185,7 @@ public:
bool train( const Ptr<TrainData>& trainData, int flags ) CV_OVERRIDE
{
CV_Assert(!trainData.empty());
startTraining(trainData, flags);
int treeidx, ntrees = bparams.weakCount >= 0 ? bparams.weakCount : 10000;
vector<int> sidx = w->sidx;
@ -482,6 +484,7 @@ public:
bool train( const Ptr<TrainData>& trainData, int flags ) CV_OVERRIDE
{
CV_Assert(!trainData.empty());
return impl.train(trainData, flags);
}

@ -112,6 +112,7 @@ public:
bool train(const Ptr<TrainData>& data, int) CV_OVERRIDE
{
CV_Assert(!data.empty());
Mat samples = data->getTrainSamples(), labels;
return trainEM(samples, labels, noArray(), noArray());
}

@ -59,9 +59,10 @@ bool StatModel::empty() const { return !isTrained(); }
int StatModel::getVarCount() const { return 0; }
bool StatModel::train( const Ptr<TrainData>&, int )
bool StatModel::train(const Ptr<TrainData>& trainData, int )
{
CV_TRACE_FUNCTION();
CV_Assert(!trainData.empty());
CV_Error(CV_StsNotImplemented, "");
return false;
}
@ -69,6 +70,7 @@ bool StatModel::train( const Ptr<TrainData>&, int )
bool StatModel::train( InputArray samples, int layout, InputArray responses )
{
CV_TRACE_FUNCTION();
CV_Assert(!samples.empty());
return train(TrainData::create(samples, layout, responses));
}
@ -134,6 +136,7 @@ public:
float StatModel::calcError(const Ptr<TrainData>& data, bool testerr, OutputArray _resp) const
{
CV_TRACE_FUNCTION_SKIP_NESTED();
CV_Assert(!data.empty());
Mat samples = data->getSamples();
Mat sidx = testerr ? data->getTestSampleIdx() : data->getTrainSampleIdx();
Mat weights = testerr ? data->getTestSampleWeights() : data->getTrainSampleWeights();

@ -73,6 +73,7 @@ public:
bool train( const Ptr<TrainData>& data, int flags )
{
CV_Assert(!data.empty());
Mat new_samples = data->getTrainSamples(ROW_SAMPLE);
Mat new_responses;
data->getTrainResponses().convertTo(new_responses, CV_32F);
@ -494,6 +495,7 @@ public:
bool train( const Ptr<TrainData>& data, int flags ) CV_OVERRIDE
{
CV_Assert(!data.empty());
return impl->train(data, flags);
}

@ -142,12 +142,10 @@ Ptr<LogisticRegression> LogisticRegression::load(const String& filepath, const S
bool LogisticRegressionImpl::train(const Ptr<TrainData>& trainData, int)
{
CV_TRACE_FUNCTION_SKIP_NESTED();
CV_Assert(!trainData.empty());
// return value
bool ok = false;
if (trainData.empty()) {
return false;
}
clear();
Mat _data_i = trainData->getSamples();
Mat _labels_i = trainData->getResponses();

@ -54,6 +54,7 @@ public:
bool train( const Ptr<TrainData>& trainData, int flags ) CV_OVERRIDE
{
CV_Assert(!trainData.empty());
const float min_variation = FLT_EPSILON;
Mat responses = trainData->getNormCatResponses();
Mat __cls_labels = trainData->getClassLabels();

@ -111,6 +111,7 @@ public:
void startTraining( const Ptr<TrainData>& trainData, int flags ) CV_OVERRIDE
{
CV_TRACE_FUNCTION();
CV_Assert(!trainData.empty());
DTreesImpl::startTraining(trainData, flags);
int nvars = w->data->getNVars();
int i, m = rparams.nactiveVars > 0 ? rparams.nactiveVars : cvRound(std::sqrt((double)nvars));
@ -133,6 +134,7 @@ public:
bool train( const Ptr<TrainData>& trainData, int flags ) CV_OVERRIDE
{
CV_TRACE_FUNCTION();
CV_Assert(!trainData.empty());
startTraining(trainData, flags);
int treeidx, ntrees = (rparams.termCrit.type & TermCriteria::COUNT) != 0 ?
rparams.termCrit.maxCount : 10000;
@ -464,6 +466,7 @@ public:
bool train( const Ptr<TrainData>& trainData, int flags ) CV_OVERRIDE
{
CV_TRACE_FUNCTION();
CV_Assert(!trainData.empty());
if (impl.getCVFolds() != 0)
CV_Error(Error::StsBadArg, "Cross validation for RTrees is not implemented");
return impl.train(trainData, flags);

@ -1613,6 +1613,7 @@ public:
bool train( const Ptr<TrainData>& data, int ) CV_OVERRIDE
{
CV_Assert(!data.empty());
clear();
checkParams();
@ -1739,6 +1740,7 @@ public:
ParamGrid nu_grid, ParamGrid coef_grid, ParamGrid degree_grid,
bool balanced ) CV_OVERRIDE
{
CV_Assert(!data.empty());
checkParams();
int svmType = params.svmType;

@ -230,6 +230,7 @@ float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const
bool SVMSGDImpl::train(const Ptr<TrainData>& data, int)
{
CV_Assert(!data.empty());
clear();
CV_Assert( isClassifier() ); //toDo: consider

@ -98,6 +98,7 @@ DTrees::Split::Split()
DTreesImpl::WorkData::WorkData(const Ptr<TrainData>& _data)
{
CV_Assert(!_data.empty());
data = _data;
vector<int> subsampleIdx;
Mat sidx0 = _data->getTrainSampleIdx();
@ -136,6 +137,7 @@ void DTreesImpl::clear()
void DTreesImpl::startTraining( const Ptr<TrainData>& data, int )
{
CV_Assert(!data.empty());
clear();
w = makePtr<WorkData>(data);
@ -223,6 +225,7 @@ void DTreesImpl::endTraining()
bool DTreesImpl::train( const Ptr<TrainData>& trainData, int flags )
{
CV_Assert(!trainData.empty());
startTraining(trainData, flags);
bool ok = addTree( w->sidx ) >= 0;
w.release();

@ -94,11 +94,7 @@ void CV_LRTest::run( int /*start_from*/ )
// initialize variables from the popular Iris Dataset
string dataFileName = ts->get_data_path() + "iris.data";
Ptr<TrainData> tdata = TrainData::loadFromCSV(dataFileName, 0);
if (tdata.empty()) {
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
return;
}
ASSERT_FALSE(tdata.empty()) << "Could not find test data file : " << dataFileName;
// run LR classifier train classifier
Ptr<LogisticRegression> p = LogisticRegression::create();
@ -156,6 +152,7 @@ void CV_LRTest_SaveLoad::run( int /*start_from*/ )
// initialize variables from the popular Iris Dataset
string dataFileName = ts->get_data_path() + "iris.data";
Ptr<TrainData> tdata = TrainData::loadFromCSV(dataFileName, 0);
ASSERT_FALSE(tdata.empty()) << "Could not find test data file : " << dataFileName;
Mat responses1, responses2;
Mat learnt_mat1, learnt_mat2;

@ -105,6 +105,7 @@ int str_to_ann_activation_function(String& str)
void ann_check_data( Ptr<TrainData> _data )
{
CV_TRACE_FUNCTION();
CV_Assert(!_data.empty());
Mat values = _data->getSamples();
Mat var_idx = _data->getVarIdx();
int nvars = (int)var_idx.total();
@ -118,6 +119,7 @@ void ann_check_data( Ptr<TrainData> _data )
Mat ann_get_new_responses( Ptr<TrainData> _data, map<int, int>& cls_map )
{
CV_TRACE_FUNCTION();
CV_Assert(!_data.empty());
Mat train_sidx = _data->getTrainSampleIdx();
int* train_sidx_ptr = train_sidx.ptr<int>();
Mat responses = _data->getResponses();
@ -150,6 +152,8 @@ Mat ann_get_new_responses( Ptr<TrainData> _data, map<int, int>& cls_map )
float ann_calc_error( Ptr<StatModel> ann, Ptr<TrainData> _data, map<int, int>& cls_map, int type, vector<float> *resp_labels )
{
CV_TRACE_FUNCTION();
CV_Assert(!ann.empty());
CV_Assert(!_data.empty());
float err = 0;
Mat samples = _data->getSamples();
Mat responses = _data->getResponses();
@ -264,13 +268,15 @@ TEST_P(ML_ANN_METHOD, Test)
String dataname = folder + "waveform" + '_' + methodName;
Ptr<TrainData> tdata2 = TrainData::loadFromCSV(original_path, 0);
ASSERT_FALSE(tdata2.empty()) << "Could not find test data file : " << original_path;
Mat samples = tdata2->getSamples()(Range(0, N), Range::all());
Mat responses(N, 3, CV_32FC1, Scalar(0));
for (int i = 0; i < N; i++)
responses.at<float>(i, static_cast<int>(tdata2->getResponses().at<float>(i, 0))) = 1;
Ptr<TrainData> tdata = TrainData::create(samples, ml::ROW_SAMPLE, responses);
ASSERT_FALSE(tdata.empty());
ASSERT_FALSE(tdata.empty()) << "Could not find test data file : " << original_path;
RNG& rng = theRNG();
rng.state = 0;
tdata->setTrainTestSplitRatio(0.8);

@ -49,7 +49,7 @@ def getXCodeMajor():
raise Exception("Failed to parse Xcode version")
class Builder:
def __init__(self, opencv, contrib, dynamic, bitcodedisabled, exclude, enablenonfree, targets, debug, debug_info):
def __init__(self, opencv, contrib, dynamic, bitcodedisabled, exclude, disable, enablenonfree, targets, debug, debug_info):
self.opencv = os.path.abspath(opencv)
self.contrib = None
if contrib:
@ -61,6 +61,7 @@ class Builder:
self.dynamic = dynamic
self.bitcodedisabled = bitcodedisabled
self.exclude = exclude
self.disable = disable
self.enablenonfree = enablenonfree
self.targets = targets
self.debug = debug
@ -154,6 +155,9 @@ class Builder:
args += ["-DBUILD_opencv_world=OFF"] if not self.dynamic else []
args += ["-DBUILD_opencv_%s=OFF" % m for m in self.exclude]
if len(self.disable) > 0:
args += ["-DWITH_%s=OFF" % f for f in self.disable]
return args
def getBuildCommand(self, archs, target):
@ -291,6 +295,7 @@ if __name__ == "__main__":
parser.add_argument('--opencv', metavar='DIR', default=folder, help='folder with opencv repository (default is "../.." relative to script location)')
parser.add_argument('--contrib', metavar='DIR', default=None, help='folder with opencv_contrib repository (default is "None" - build only main framework)')
parser.add_argument('--without', metavar='MODULE', default=[], action='append', help='OpenCV modules to exclude from the framework')
parser.add_argument('--disable', metavar='FEATURE', default=[], action='append', help='OpenCV features to disable (add WITH_*=OFF)')
parser.add_argument('--dynamic', default=False, action='store_true', help='build dynamic framework (default is "False" - builds static framework)')
parser.add_argument('--disable-bitcode', default=False, dest='bitcodedisabled', action='store_true', help='disable bitcode (enabled by default)')
parser.add_argument('--iphoneos_deployment_target', default=os.environ.get('IPHONEOS_DEPLOYMENT_TARGET', IPHONEOS_DEPLOYMENT_TARGET), help='specify IPHONEOS_DEPLOYMENT_TARGET')
@ -308,7 +313,7 @@ if __name__ == "__main__":
iphonesimulator_archs = args.iphonesimulator_archs.split(',')
print('Using iPhoneSimulator ARCHS=' + str(iphonesimulator_archs))
b = iOSBuilder(args.opencv, args.contrib, args.dynamic, args.bitcodedisabled, args.without, args.enablenonfree,
b = iOSBuilder(args.opencv, args.contrib, args.dynamic, args.bitcodedisabled, args.without, args.disable, args.enablenonfree,
[
(iphoneos_archs, "iPhoneOS"),
] if os.environ.get('BUILD_PRECOMMIT', None) else

@ -78,6 +78,7 @@ class Builder:
def get_cmake_cmd(self):
cmd = ["cmake",
"-DENABLE_PIC=FALSE", # To workaround emscripten upstream backend issue https://github.com/emscripten-core/emscripten/issues/8761
"-DCMAKE_BUILD_TYPE=Release",
"-DCMAKE_TOOLCHAIN_FILE='%s'" % self.get_toolchain_file(),
"-DCPU_BASELINE=''",
@ -103,7 +104,6 @@ class Builder:
"-DWITH_OPENNI2=OFF",
"-DWITH_PNG=OFF",
"-DWITH_TBB=OFF",
"-DWITH_PTHREADS_PF=OFF",
"-DWITH_TIFF=OFF",
"-DWITH_V4L=OFF",
"-DWITH_OPENCL=OFF",
@ -145,6 +145,21 @@ class Builder:
else:
cmd.append("-DBUILD_DOCS=OFF")
if self.options.threads:
cmd.append("-DWITH_PTHREADS_PF=ON")
else:
cmd.append("-DWITH_PTHREADS_PF=OFF")
if self.options.simd:
cmd.append("-DCV_ENABLE_INTRINSICS=ON")
else:
cmd.append("-DCV_ENABLE_INTRINSICS=OFF")
if self.options.build_wasm_intrin_test:
cmd.append("-DBUILD_WASM_INTRIN_TESTS=ON")
else:
cmd.append("-DBUILD_WASM_INTRIN_TESTS=OFF")
flags = self.get_build_flags()
if flags:
cmd += ["-DCMAKE_C_FLAGS='%s'" % flags,
@ -157,8 +172,14 @@ class Builder:
flags += "-s WASM=1 "
elif self.options.disable_wasm:
flags += "-s WASM=0 "
if self.options.threads:
flags += "-s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=4 "
else:
flags += "-s USE_PTHREADS=0 "
if self.options.enable_exception:
flags += "-s DISABLE_EXCEPTION_CATCHING=0 "
if self.options.simd:
flags += "-msimd128 "
return flags
def config(self):
@ -172,6 +193,9 @@ class Builder:
def build_test(self):
execute(["make", "-j", str(multiprocessing.cpu_count()), "opencv_js_test"])
def build_perf(self):
execute(["make", "-j", str(multiprocessing.cpu_count()), "opencv_js_perf"])
def build_doc(self):
execute(["make", "-j", str(multiprocessing.cpu_count()), "doxygen"])
@ -190,12 +214,16 @@ if __name__ == "__main__":
parser.add_argument('--emscripten_dir', default=emscripten_dir, help="Path to Emscripten to use for build")
parser.add_argument('--build_wasm', action="store_true", help="Build OpenCV.js in WebAssembly format")
parser.add_argument('--disable_wasm', action="store_true", help="Build OpenCV.js in Asm.js format")
parser.add_argument('--threads', action="store_true", help="Build OpenCV.js with threads optimization")
parser.add_argument('--simd', action="store_true", help="Build OpenCV.js with SIMD optimization")
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('--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")
parser.add_argument('--enable_exception', action="store_true", help="Enable exception handling")
parser.add_argument('--build_wasm_intrin_test', default=False, action="store_true", help="Build WASM intrin tests")
args = parser.parse_args()
log.basicConfig(format='%(message)s', level=log.DEBUG)
@ -240,6 +268,12 @@ if __name__ == "__main__":
log.info("=====")
builder.build_test()
if args.build_perf:
log.info("=====")
log.info("===== Building OpenCV.js performance tests")
log.info("=====")
builder.build_perf()
if args.build_doc:
log.info("=====")
log.info("===== Building OpenCV.js tutorials")
@ -260,6 +294,12 @@ if __name__ == "__main__":
if check_file(opencvjs_test_path):
log.info("OpenCV.js tests location: %s", opencvjs_test_path)
if args.build_perf:
opencvjs_perf_path = os.path.join(builder.build_dir, "bin", "perf")
opencvjs_perf_base_path = os.path.join(builder.build_dir, "bin", "perf", "base.js")
if check_file(opencvjs_perf_base_path):
log.info("OpenCV.js performance tests location: %s", opencvjs_perf_path)
if args.build_doc:
opencvjs_tutorial_path = find_file("tutorial_js_root.html", os.path.join(builder.build_dir, "doc", "doxygen", "html"))
if check_file(opencvjs_tutorial_path):

Loading…
Cancel
Save