diff --git a/3rdparty/carotene/hal/tegra_hal.hpp b/3rdparty/carotene/hal/tegra_hal.hpp index 2e07b7f526..7bf470eccc 100644 --- a/3rdparty/carotene/hal/tegra_hal.hpp +++ b/3rdparty/carotene/hal/tegra_hal.hpp @@ -119,7 +119,7 @@ private: \ #define TEGRA_BINARYOP(type, op, src1, sz1, src2, sz2, dst, sz, w, h) \ ( \ CAROTENE_NS::isSupportedConfiguration() ? \ - parallel_for_(Range(0, h), \ + parallel_for_(cv::Range(0, h), \ TegraGenOp_##op##_Invoker(src1, sz1, src2, sz2, dst, sz, w, h), \ (w * h) / static_cast(1<<16)), \ CV_HAL_ERROR_OK \ @@ -154,7 +154,7 @@ TegraUnaryOp_Invoker(bitwiseNot, bitwiseNot) #define TEGRA_UNARYOP(type, op, src1, sz1, dst, sz, w, h) \ ( \ CAROTENE_NS::isSupportedConfiguration() ? \ - parallel_for_(Range(0, h), \ + parallel_for_(cv::Range(0, h), \ TegraGenOp_##op##_Invoker(src1, sz1, dst, sz, w, h), \ (w * h) / static_cast(1<<16)), \ CV_HAL_ERROR_OK \ @@ -254,32 +254,32 @@ TegraGenOp_Invoker(cmpLE, cmpGE, 2, 1, 0, RANGE_DATA(ST, src2_data, src2_step), ( \ CAROTENE_NS::isSupportedConfiguration() ? \ ((op) == cv::CMP_EQ) ? \ - parallel_for_(Range(0, h), \ + parallel_for_(cv::Range(0, h), \ TegraGenOp_cmpEQ_Invoker(src1, sz1, src2, sz2, dst, sz, w, h), \ (w * h) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ ((op) == cv::CMP_NE) ? \ - parallel_for_(Range(0, h), \ + parallel_for_(cv::Range(0, h), \ TegraGenOp_cmpNE_Invoker(src1, sz1, src2, sz2, dst, sz, w, h), \ (w * h) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ ((op) == cv::CMP_GT) ? \ - parallel_for_(Range(0, h), \ + parallel_for_(cv::Range(0, h), \ TegraGenOp_cmpGT_Invoker(src1, sz1, src2, sz2, dst, sz, w, h), \ (w * h) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ ((op) == cv::CMP_GE) ? \ - parallel_for_(Range(0, h), \ + parallel_for_(cv::Range(0, h), \ TegraGenOp_cmpGE_Invoker(src1, sz1, src2, sz2, dst, sz, w, h), \ (w * h) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ ((op) == cv::CMP_LT) ? \ - parallel_for_(Range(0, h), \ + parallel_for_(cv::Range(0, h), \ TegraGenOp_cmpLT_Invoker(src1, sz1, src2, sz2, dst, sz, w, h), \ (w * h) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ ((op) == cv::CMP_LE) ? \ - parallel_for_(Range(0, h), \ + parallel_for_(cv::Range(0, h), \ TegraGenOp_cmpLE_Invoker(src1, sz1, src2, sz2, dst, sz, w, h), \ (w * h) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ @@ -310,7 +310,7 @@ TegraGenOp_Invoker(cmpLE, cmpGE, 2, 1, 0, RANGE_DATA(ST, src2_data, src2_step), #define TEGRA_BINARYOPSCALE(type, op, src1, sz1, src2, sz2, dst, sz, w, h, scales) \ ( \ CAROTENE_NS::isSupportedConfiguration() ? \ - parallel_for_(Range(0, h), \ + parallel_for_(cv::Range(0, h), \ TegraGenOp_##op##_Invoker(src1, sz1, src2, sz2, dst, sz, w, h, scales), \ (w * h) / static_cast(1<<16)), \ CV_HAL_ERROR_OK \ @@ -332,7 +332,7 @@ TegraBinaryOpScale_Invoker(divf, div, 1, scale) #define TEGRA_UNARYOPSCALE(type, op, src1, sz1, dst, sz, w, h, scales) \ ( \ CAROTENE_NS::isSupportedConfiguration() ? \ - parallel_for_(Range(0, h), \ + parallel_for_(cv::Range(0, h), \ TegraGenOp_##op##_Invoker(src1, sz1, dst, sz, w, h, scales), \ (w * h) / static_cast(1<<16)), \ CV_HAL_ERROR_OK \ @@ -928,17 +928,17 @@ TegraRowOp_Invoker(split4, split4, 1, 4, 0, RANGE_DATA(ST, src1_data, 4*sizeof(S ( \ CAROTENE_NS::isSupportedConfiguration() ? \ cn == 2 ? \ - parallel_for_(Range(0, len), \ + parallel_for_(cv::Range(0, len), \ TegraRowOp_split2_Invoker(src, dst[0], dst[1]), \ (len) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ cn == 3 ? \ - parallel_for_(Range(0, len), \ + parallel_for_(cv::Range(0, len), \ TegraRowOp_split3_Invoker(src, dst[0], dst[1], dst[2]), \ (len) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ cn == 4 ? \ - parallel_for_(Range(0, len), \ + parallel_for_(cv::Range(0, len), \ TegraRowOp_split4_Invoker(src, dst[0], dst[1], dst[2], dst[3]), \ (len) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ @@ -990,17 +990,17 @@ TegraRowOp_Invoker(combine4, combine4, 4, 1, 0, RANGE_DATA(ST, src1_data, sizeof ( \ CAROTENE_NS::isSupportedConfiguration() ? \ cn == 2 ? \ - parallel_for_(Range(0, len), \ + parallel_for_(cv::Range(0, len), \ TegraRowOp_combine2_Invoker(src[0], src[1], dst), \ (len) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ cn == 3 ? \ - parallel_for_(Range(0, len), \ + parallel_for_(cv::Range(0, len), \ TegraRowOp_combine3_Invoker(src[0], src[1], src[2], dst), \ (len) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ cn == 4 ? \ - parallel_for_(Range(0, len), \ + parallel_for_(cv::Range(0, len), \ TegraRowOp_combine4_Invoker(src[0], src[1], src[2], src[3], dst), \ (len) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ @@ -1033,7 +1033,7 @@ TegraRowOp_Invoker(phase, phase, 2, 1, 1, RANGE_DATA(ST, src1_data, sizeof(CAROT #define TEGRA_FASTATAN(y, x, dst, len, angleInDegrees) \ ( \ CAROTENE_NS::isSupportedConfiguration() ? \ - parallel_for_(Range(0, len), \ + parallel_for_(cv::Range(0, len), \ TegraRowOp_phase_Invoker(x, y, dst, angleInDegrees ? 1.0f : M_PI/180), \ (len) / static_cast(1<<16)), \ CV_HAL_ERROR_OK \ @@ -1049,7 +1049,7 @@ TegraRowOp_Invoker(magnitude, magnitude, 2, 1, 0, RANGE_DATA(ST, src1_data, size #define TEGRA_MAGNITUDE(x, y, dst, len) \ ( \ CAROTENE_NS::isSupportedConfiguration() ? \ - parallel_for_(Range(0, len), \ + parallel_for_(cv::Range(0, len), \ TegraRowOp_magnitude_Invoker(x, y, dst), \ (len) / static_cast(1<<16)), \ CV_HAL_ERROR_OK \ @@ -1563,17 +1563,17 @@ TegraCvtColor_Invoker(rgbx2bgrx, rgbx2bgrx, src_data + static_cast(range scn == 3 ? \ dcn == 3 ? \ swapBlue ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgb2bgr_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ CV_HAL_ERROR_NOT_IMPLEMENTED : \ dcn == 4 ? \ (swapBlue ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgb2bgrx_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgb2rgbx_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) ), \ CV_HAL_ERROR_OK : \ @@ -1581,16 +1581,16 @@ TegraCvtColor_Invoker(rgbx2bgrx, rgbx2bgrx, src_data + static_cast(range scn == 4 ? \ dcn == 3 ? \ (swapBlue ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgbx2bgr_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgbx2rgb_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) ), \ CV_HAL_ERROR_OK : \ dcn == 4 ? \ swapBlue ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgbx2bgrx_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ @@ -1613,19 +1613,19 @@ TegraCvtColor_Invoker(rgbx2rgb565, rgbx2rgb565, src_data + static_cast(r greenBits == 6 && CAROTENE_NS::isSupportedConfiguration() ? \ scn == 3 ? \ (swapBlue ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgb2bgr565_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgb2rgb565_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) ), \ CV_HAL_ERROR_OK : \ scn == 4 ? \ (swapBlue ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgbx2bgr565_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgbx2rgb565_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) ), \ CV_HAL_ERROR_OK : \ @@ -1646,19 +1646,19 @@ TegraCvtColor_Invoker(bgrx2gray, bgrx2gray, CAROTENE_NS::COLOR_SPACE_BT601, src_ depth == CV_8U && CAROTENE_NS::isSupportedConfiguration() ? \ scn == 3 ? \ (swapBlue ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgb2gray_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_bgr2gray_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) ), \ CV_HAL_ERROR_OK : \ scn == 4 ? \ (swapBlue ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgbx2gray_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_bgrx2gray_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) ), \ CV_HAL_ERROR_OK : \ @@ -1674,12 +1674,12 @@ TegraCvtColor_Invoker(gray2rgbx, gray2rgbx, src_data + static_cast(range ( \ depth == CV_8U && CAROTENE_NS::isSupportedConfiguration() ? \ dcn == 3 ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_gray2rgb_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ dcn == 4 ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_gray2rgbx_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)), \ CV_HAL_ERROR_OK : \ @@ -1700,19 +1700,19 @@ TegraCvtColor_Invoker(bgrx2ycrcb, bgrx2ycrcb, src_data + static_cast(ran isCbCr && depth == CV_8U && CAROTENE_NS::isSupportedConfiguration() ? \ scn == 3 ? \ (swapBlue ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgb2ycrcb_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_bgr2ycrcb_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) ), \ CV_HAL_ERROR_OK : \ scn == 4 ? \ (swapBlue ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgbx2ycrcb_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_bgrx2ycrcb_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) ), \ CV_HAL_ERROR_OK : \ @@ -1742,34 +1742,34 @@ TegraCvtColor_Invoker(bgrx2hsvf, bgrx2hsv, src_data + static_cast(range. scn == 3 ? \ (swapBlue ? \ isFullRange ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgb2hsvf_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgb2hsv_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ isFullRange ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_bgr2hsvf_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_bgr2hsv_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) ), \ CV_HAL_ERROR_OK : \ scn == 4 ? \ (swapBlue ? \ isFullRange ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgbx2hsvf_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_rgbx2hsv_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ isFullRange ? \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_bgrx2hsvf_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) : \ - parallel_for_(Range(0, height), \ + parallel_for_(cv::Range(0, height), \ TegraCvtColor_bgrx2hsv_Invoker(src_data, src_step, dst_data, dst_step, width, height), \ (width * height) / static_cast(1<<16)) ), \ CV_HAL_ERROR_OK : \ diff --git a/3rdparty/fastcv/fastcv.cmake b/3rdparty/fastcv/fastcv.cmake index b8172705ca..5c81c11300 100644 --- a/3rdparty/fastcv/fastcv.cmake +++ b/3rdparty/fastcv/fastcv.cmake @@ -1,7 +1,7 @@ function(download_fastcv root_dir) # Commit SHA in the opencv_3rdparty repo - set(FASTCV_COMMIT "dc5d58018f3af915a8d209386d2c58c0501c0f2c") + set(FASTCV_COMMIT "f4413cc2ab7233fdfc383a4cded402c072677fb0") # Define actual FastCV versions if(ANDROID) @@ -16,14 +16,15 @@ function(download_fastcv root_dir) endif() elseif(UNIX AND NOT APPLE AND NOT IOS AND NOT XROS) if(AARCH64) - set(FCV_PACKAGE_NAME "fastcv_linux_aarch64_2024_12_11.tgz") - set(FCV_PACKAGE_HASH "7b33ad833e6f15ab6d4ec64fa3c17acd") + set(FCV_PACKAGE_NAME "fastcv_linux_aarch64_2025_02_12.tgz") + set(FCV_PACKAGE_HASH "33ac2a59cf3e7d6402eee2e010de1202") else() message("FastCV: fastcv lib for 32-bit Linux is not supported for now!") endif() endif(ANDROID) # Download Package + set(OPENCV_FASTCV_URL "https://raw.githubusercontent.com/opencv/opencv_3rdparty/${FASTCV_COMMIT}/fastcv/") ocv_download( FILENAME ${FCV_PACKAGE_NAME} diff --git a/3rdparty/hal_rvv/hal_rvv.hpp b/3rdparty/hal_rvv/hal_rvv.hpp index 086f248a24..6f62d8471a 100644 --- a/3rdparty/hal_rvv/hal_rvv.hpp +++ b/3rdparty/hal_rvv/hal_rvv.hpp @@ -22,6 +22,12 @@ #if defined(__riscv_v) && __riscv_v == 1000000 #include "hal_rvv_1p0/merge.hpp" // core #include "hal_rvv_1p0/mean.hpp" // core +#include "hal_rvv_1p0/norm.hpp" // core +#include "hal_rvv_1p0/norm_diff.hpp" // core +#include "hal_rvv_1p0/convert_scale.hpp" // core +#include "hal_rvv_1p0/minmax.hpp" // core +#include "hal_rvv_1p0/atan.hpp" // core +#include "hal_rvv_1p0/split.hpp" // core #endif #endif diff --git a/3rdparty/hal_rvv/hal_rvv_1p0/atan.hpp b/3rdparty/hal_rvv/hal_rvv_1p0/atan.hpp new file mode 100644 index 0000000000..2134d98a6e --- /dev/null +++ b/3rdparty/hal_rvv/hal_rvv_1p0/atan.hpp @@ -0,0 +1,128 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level +// directory of this distribution and at http://opencv.org/license.html. +#pragma once + +#undef cv_hal_fastAtan32f +#define cv_hal_fastAtan32f cv::cv_hal_rvv::fast_atan_32 + +#undef cv_hal_fastAtan64f +#define cv_hal_fastAtan64f cv::cv_hal_rvv::fast_atan_64 + +#include + +#include + +namespace cv::cv_hal_rvv { + +namespace detail { +// ref: mathfuncs_core.simd.hpp +static constexpr float pi = CV_PI; +static constexpr float atan2_p1 = 0.9997878412794807F * (180 / pi); +static constexpr float atan2_p3 = -0.3258083974640975F * (180 / pi); +static constexpr float atan2_p5 = 0.1555786518463281F * (180 / pi); +static constexpr float atan2_p7 = -0.04432655554792128F * (180 / pi); + +__attribute__((always_inline)) inline vfloat32m4_t +rvv_atan_f32(vfloat32m4_t vy, vfloat32m4_t vx, size_t vl, float p7, + vfloat32m4_t vp5, vfloat32m4_t vp3, vfloat32m4_t vp1, + float angle_90_deg) { + const auto ax = __riscv_vfabs(vx, vl); + const auto ay = __riscv_vfabs(vy, vl); + const auto c = __riscv_vfdiv( + __riscv_vfmin(ax, ay, vl), + __riscv_vfadd(__riscv_vfmax(ax, ay, vl), FLT_EPSILON, vl), vl); + const auto c2 = __riscv_vfmul(c, c, vl); + + auto a = __riscv_vfmadd(c2, p7, vp5, vl); + a = __riscv_vfmadd(a, c2, vp3, vl); + a = __riscv_vfmadd(a, c2, vp1, vl); + a = __riscv_vfmul(a, c, vl); + + const auto mask = __riscv_vmflt(ax, ay, vl); + a = __riscv_vfrsub_mu(mask, a, a, angle_90_deg, vl); + + a = __riscv_vfrsub_mu(__riscv_vmflt(vx, 0.F, vl), a, a, angle_90_deg * 2, + vl); + a = __riscv_vfrsub_mu(__riscv_vmflt(vy, 0.F, vl), a, a, angle_90_deg * 4, + vl); + + return a; +} + +} // namespace detail + +inline int fast_atan_32(const float *y, const float *x, float *dst, size_t n, + bool angle_in_deg) { + const float scale = angle_in_deg ? 1.f : CV_PI / 180.f; + const float p1 = detail::atan2_p1 * scale; + const float p3 = detail::atan2_p3 * scale; + const float p5 = detail::atan2_p5 * scale; + const float p7 = detail::atan2_p7 * scale; + const float angle_90_deg = 90.F * scale; + + static size_t vlmax = __riscv_vsetvlmax_e32m4(); + auto vp1 = __riscv_vfmv_v_f_f32m4(p1, vlmax); + auto vp3 = __riscv_vfmv_v_f_f32m4(p3, vlmax); + auto vp5 = __riscv_vfmv_v_f_f32m4(p5, vlmax); + + for (size_t vl{}; n > 0; n -= vl) { + vl = __riscv_vsetvl_e32m4(n); + + auto vy = __riscv_vle32_v_f32m4(y, vl); + auto vx = __riscv_vle32_v_f32m4(x, vl); + + auto a = + detail::rvv_atan_f32(vy, vx, vl, p7, vp5, vp3, vp1, angle_90_deg); + + __riscv_vse32(dst, a, vl); + + x += vl; + y += vl; + dst += vl; + } + + return CV_HAL_ERROR_OK; +} + +inline int fast_atan_64(const double *y, const double *x, double *dst, size_t n, + bool angle_in_deg) { + // this also uses float32 version, ref: mathfuncs_core.simd.hpp + + const float scale = angle_in_deg ? 1.f : CV_PI / 180.f; + const float p1 = detail::atan2_p1 * scale; + const float p3 = detail::atan2_p3 * scale; + const float p5 = detail::atan2_p5 * scale; + const float p7 = detail::atan2_p7 * scale; + const float angle_90_deg = 90.F * scale; + + static size_t vlmax = __riscv_vsetvlmax_e32m4(); + auto vp1 = __riscv_vfmv_v_f_f32m4(p1, vlmax); + auto vp3 = __riscv_vfmv_v_f_f32m4(p3, vlmax); + auto vp5 = __riscv_vfmv_v_f_f32m4(p5, vlmax); + + for (size_t vl{}; n > 0; n -= vl) { + vl = __riscv_vsetvl_e64m8(n); + + auto wy = __riscv_vle64_v_f64m8(y, vl); + auto wx = __riscv_vle64_v_f64m8(x, vl); + + auto vy = __riscv_vfncvt_f_f_w_f32m4(wy, vl); + auto vx = __riscv_vfncvt_f_f_w_f32m4(wx, vl); + + auto a = + detail::rvv_atan_f32(vy, vx, vl, p7, vp5, vp3, vp1, angle_90_deg); + + auto wa = __riscv_vfwcvt_f_f_v_f64m8(a, vl); + + __riscv_vse64(dst, wa, vl); + + x += vl; + y += vl; + dst += vl; + } + + return CV_HAL_ERROR_OK; +} + +} // namespace cv::cv_hal_rvv diff --git a/3rdparty/hal_rvv/hal_rvv_1p0/convert_scale.hpp b/3rdparty/hal_rvv/hal_rvv_1p0/convert_scale.hpp new file mode 100644 index 0000000000..3a779f5cb3 --- /dev/null +++ b/3rdparty/hal_rvv/hal_rvv_1p0/convert_scale.hpp @@ -0,0 +1,120 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +#ifndef OPENCV_HAL_RVV_CONVERT_SCALE_HPP_INCLUDED +#define OPENCV_HAL_RVV_CONVERT_SCALE_HPP_INCLUDED + +#include + +namespace cv { namespace cv_hal_rvv { + +#undef cv_hal_convertScale +#define cv_hal_convertScale cv::cv_hal_rvv::convertScale + +inline int convertScale_8U8U(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, double alpha, double beta) +{ + int vlmax = __riscv_vsetvlmax_e32m8(); + auto vec_b = __riscv_vfmv_v_f_f32m8(beta, vlmax); + float a = alpha; + + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + uchar* dst_row = dst + i * dst_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_src_u16 = __riscv_vzext_vf2(vec_src, vl); + auto vec_src_f32 = __riscv_vfwcvt_f(vec_src_u16, vl); + auto vec_fma = __riscv_vfmadd(vec_src_f32, a, vec_b, vl); + auto vec_dst_u16 = __riscv_vfncvt_xu(vec_fma, vl); + auto vec_dst = __riscv_vnclipu(vec_dst_u16, 0, __RISCV_VXRM_RNU, vl); + __riscv_vse8_v_u8m2(dst_row + j, vec_dst, vl); + } + } + + return CV_HAL_ERROR_OK; +} + +inline int convertScale_8U32F(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, double alpha, double beta) +{ + int vlmax = __riscv_vsetvlmax_e32m8(); + auto vec_b = __riscv_vfmv_v_f_f32m8(beta, vlmax); + float a = alpha; + + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + float* dst_row = reinterpret_cast(dst + i * dst_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_src_u16 = __riscv_vzext_vf2(vec_src, vl); + auto vec_src_f32 = __riscv_vfwcvt_f(vec_src_u16, vl); + auto vec_fma = __riscv_vfmadd(vec_src_f32, a, vec_b, vl); + __riscv_vse32_v_f32m8(dst_row + j, vec_fma, vl); + } + } + + return CV_HAL_ERROR_OK; +} + +inline int convertScale_32F32F(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, double alpha, double beta) +{ + int vlmax = __riscv_vsetvlmax_e32m8(); + auto vec_b = __riscv_vfmv_v_f_f32m8(beta, vlmax); + float a = alpha; + + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + float* dst_row = reinterpret_cast(dst + i * dst_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m8(width - j); + auto vec_src = __riscv_vle32_v_f32m8(src_row + j, vl); + auto vec_fma = __riscv_vfmadd(vec_src, a, vec_b, vl); + __riscv_vse32_v_f32m8(dst_row + j, vec_fma, vl); + } + } + + return CV_HAL_ERROR_OK; +} + +inline int convertScale(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, + int sdepth, int ddepth, double alpha, double beta) +{ + if (!dst) + return CV_HAL_ERROR_OK; + + switch (sdepth) + { + case CV_8U: + switch (ddepth) + { + case CV_8U: + return convertScale_8U8U(src, src_step, dst, dst_step, width, height, alpha, beta); + case CV_32F: + return convertScale_8U32F(src, src_step, dst, dst_step, width, height, alpha, beta); + } + return CV_HAL_ERROR_NOT_IMPLEMENTED; + case CV_32F: + switch (ddepth) + { + case CV_32F: + return convertScale_32F32F(src, src_step, dst, dst_step, width, height, alpha, beta); + } + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + return CV_HAL_ERROR_NOT_IMPLEMENTED; +} + +}} + +#endif diff --git a/3rdparty/hal_rvv/hal_rvv_1p0/minmax.hpp b/3rdparty/hal_rvv/hal_rvv_1p0/minmax.hpp new file mode 100644 index 0000000000..dbaa4706db --- /dev/null +++ b/3rdparty/hal_rvv/hal_rvv_1p0/minmax.hpp @@ -0,0 +1,337 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +#ifndef OPENCV_HAL_RVV_MINMAXIDX_HPP_INCLUDED +#define OPENCV_HAL_RVV_MINMAXIDX_HPP_INCLUDED + +#include + +namespace cv { namespace cv_hal_rvv { + +#undef cv_hal_minMaxIdx +#define cv_hal_minMaxIdx cv::cv_hal_rvv::minMaxIdx + +// 1d support issue https://github.com/opencv/opencv/issues/26947 +//#undef cv_hal_minMaxIdxMaskStep +//#define cv_hal_minMaxIdxMaskStep cv::cv_hal_rvv::minMaxIdx + +namespace +{ + template struct rvv; + + #define HAL_RVV_GENERATOR(T, EEW, TYPE, IS_U, EMUL, M_EMUL, B_LEN) \ + template<> struct rvv \ + { \ + using vec_t = v##IS_U##int##EEW##EMUL##_t; \ + using bool_t = vbool##B_LEN##_t; \ + static inline size_t vsetvlmax() { return __riscv_vsetvlmax_e##EEW##EMUL(); } \ + static inline size_t vsetvl(size_t a) { return __riscv_vsetvl_e##EEW##EMUL(a); } \ + static inline vec_t vmv_v_x(T a, size_t b) { return __riscv_vmv_v_x_##TYPE##EMUL(a, b); } \ + static inline vec_t vle(const T* a, size_t b) { return __riscv_vle##EEW##_v_##TYPE##EMUL(a, b); } \ + static inline vuint8##M_EMUL##_t vle_mask(const uchar* a, size_t b) { return __riscv_vle8_v_u8##M_EMUL(a, b); } \ + static inline vec_t vmin_tu(vec_t a, vec_t b, vec_t c, size_t d) { return __riscv_vmin##IS_U##_tu(a, b, c, d); } \ + static inline vec_t vmax_tu(vec_t a, vec_t b, vec_t c, size_t d) { return __riscv_vmax##IS_U##_tu(a, b, c, d); } \ + static inline vec_t vmin_tumu(bool_t a, vec_t b, vec_t c, vec_t d, size_t e) { return __riscv_vmin##IS_U##_tumu(a, b, c, d, e); } \ + static inline vec_t vmax_tumu(bool_t a, vec_t b, vec_t c, vec_t d, size_t e) { return __riscv_vmax##IS_U##_tumu(a, b, c, d, e); } \ + static inline vec_t vredmin(vec_t a, vec_t b, size_t c) { return __riscv_vredmin##IS_U(a, b, c); } \ + static inline vec_t vredmax(vec_t a, vec_t b, size_t c) { return __riscv_vredmax##IS_U(a, b, c); } \ + }; + HAL_RVV_GENERATOR(uchar , 8 , u8 , u, m1, m1 , 8 ) + HAL_RVV_GENERATOR(schar , 8 , i8 , , m1, m1 , 8 ) + HAL_RVV_GENERATOR(ushort, 16, u16, u, m1, mf2, 16) + HAL_RVV_GENERATOR(short , 16, i16, , m1, mf2, 16) + #undef HAL_RVV_GENERATOR + + #define HAL_RVV_GENERATOR(T, NAME, EEW, TYPE, IS_F, F_OR_S, F_OR_X, EMUL, M_EMUL, P_EMUL, B_LEN) \ + template<> struct rvv \ + { \ + using vec_t = v##NAME##EEW##EMUL##_t; \ + using bool_t = vbool##B_LEN##_t; \ + static inline size_t vsetvlmax() { return __riscv_vsetvlmax_e##EEW##EMUL(); } \ + static inline size_t vsetvl(size_t a) { return __riscv_vsetvl_e##EEW##EMUL(a); } \ + static inline vec_t vmv_v_x(T a, size_t b) { return __riscv_v##IS_F##mv_v_##F_OR_X##_##TYPE##EMUL(a, b); } \ + static inline vuint32##P_EMUL##_t vid(size_t a) { return __riscv_vid_v_u32##P_EMUL(a); } \ + static inline vuint32##P_EMUL##_t vundefined() { return __riscv_vundefined_u32##P_EMUL(); } \ + static inline vec_t vle(const T* a, size_t b) { return __riscv_vle##EEW##_v_##TYPE##EMUL(a, b); } \ + static inline vuint8##M_EMUL##_t vle_mask(const uchar* a, size_t b) { return __riscv_vle8_v_u8##M_EMUL(a, b); } \ + static inline bool_t vmlt(vec_t a, vec_t b, size_t c) { return __riscv_vm##F_OR_S##lt(a, b, c); } \ + static inline bool_t vmgt(vec_t a, vec_t b, size_t c) { return __riscv_vm##F_OR_S##gt(a, b, c); } \ + static inline bool_t vmlt_mu(bool_t a, bool_t b, vec_t c, vec_t d, size_t e) { return __riscv_vm##F_OR_S##lt##_mu(a, b, c, d, e); } \ + static inline bool_t vmgt_mu(bool_t a, bool_t b, vec_t c, vec_t d, size_t e) { return __riscv_vm##F_OR_S##gt##_mu(a, b, c, d, e); } \ + static inline T vmv_x_s(vec_t a) { return __riscv_v##IS_F##mv_##F_OR_X(a); } \ + }; + HAL_RVV_GENERATOR(int , int , 32, i32, , s, x, m4, m1 , m4, 8 ) + HAL_RVV_GENERATOR(float , float, 32, f32, f, f, f, m4, m1 , m4, 8 ) + HAL_RVV_GENERATOR(double, float, 64, f64, f, f, f, m4, mf2, m2, 16) + #undef HAL_RVV_GENERATOR +} + +template +inline int minMaxIdxReadTwice(const uchar* src_data, size_t src_step, int width, int height, double* minVal, double* maxVal, + int* minIdx, int* maxIdx, uchar* mask, size_t mask_step) +{ + int vlmax = rvv::vsetvlmax(); + auto vec_min = rvv::vmv_v_x(std::numeric_limits::max(), vlmax); + auto vec_max = rvv::vmv_v_x(std::numeric_limits::lowest(), vlmax); + T val_min, val_max; + + if (mask) + { + for (int i = 0; i < height; i++) + { + const T* src_row = reinterpret_cast(src_data + i * src_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = rvv::vsetvl(width - j); + auto vec_src = rvv::vle(src_row + j, vl); + auto vec_mask = rvv::vle_mask(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + vec_min = rvv::vmin_tumu(bool_mask, vec_min, vec_min, vec_src, vl); + vec_max = rvv::vmax_tumu(bool_mask, vec_max, vec_max, vec_src, vl); + } + } + + auto sc_minval = rvv::vmv_v_x(std::numeric_limits::max(), vlmax); + auto sc_maxval = rvv::vmv_v_x(std::numeric_limits::lowest(), vlmax); + sc_minval = rvv::vredmin(vec_min, sc_minval, vlmax); + sc_maxval = rvv::vredmax(vec_max, sc_maxval, vlmax); + val_min = __riscv_vmv_x(sc_minval); + val_max = __riscv_vmv_x(sc_maxval); + + bool found_min = !minIdx, found_max = !maxIdx; + for (int i = 0; i < height && (!found_min || !found_max); i++) + { + const T* src_row = reinterpret_cast(src_data + i * src_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width && (!found_min || !found_max); j += vl) + { + vl = rvv::vsetvl(width - j); + auto vec_src = rvv::vle(src_row + j, vl); + auto vec_mask = rvv::vle_mask(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto bool_zero = __riscv_vmxor(bool_mask, bool_mask, vl); + if (!found_min) + { + auto bool_minpos = __riscv_vmseq_mu(bool_mask, bool_zero, vec_src, val_min, vl); + int index = __riscv_vfirst(bool_minpos, vl); + if (index != -1) + { + found_min = true; + minIdx[0] = i; + minIdx[1] = j + index; + } + } + if (!found_max) + { + auto bool_maxpos = __riscv_vmseq_mu(bool_mask, bool_zero, vec_src, val_max, vl); + int index = __riscv_vfirst(bool_maxpos, vl); + if (index != -1) + { + found_max = true; + maxIdx[0] = i; + maxIdx[1] = j + index; + } + } + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const T* src_row = reinterpret_cast(src_data + i * src_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = rvv::vsetvl(width - j); + auto vec_src = rvv::vle(src_row + j, vl); + vec_min = rvv::vmin_tu(vec_min, vec_min, vec_src, vl); + vec_max = rvv::vmax_tu(vec_max, vec_max, vec_src, vl); + } + } + + auto sc_minval = rvv::vmv_v_x(std::numeric_limits::max(), vlmax); + auto sc_maxval = rvv::vmv_v_x(std::numeric_limits::lowest(), vlmax); + sc_minval = rvv::vredmin(vec_min, sc_minval, vlmax); + sc_maxval = rvv::vredmax(vec_max, sc_maxval, vlmax); + val_min = __riscv_vmv_x(sc_minval); + val_max = __riscv_vmv_x(sc_maxval); + + bool found_min = !minIdx, found_max = !maxIdx; + for (int i = 0; i < height && (!found_min || !found_max); i++) + { + const T* src_row = reinterpret_cast(src_data + i * src_step); + int vl; + for (int j = 0; j < width && (!found_min || !found_max); j += vl) + { + vl = rvv::vsetvl(width - j); + auto vec_src = rvv::vle(src_row + j, vl); + if (!found_min) + { + auto bool_minpos = __riscv_vmseq(vec_src, val_min, vl); + int index = __riscv_vfirst(bool_minpos, vl); + if (index != -1) + { + found_min = true; + minIdx[0] = i; + minIdx[1] = j + index; + } + } + if (!found_max) + { + auto bool_maxpos = __riscv_vmseq(vec_src, val_max, vl); + int index = __riscv_vfirst(bool_maxpos, vl); + if (index != -1) + { + found_max = true; + maxIdx[0] = i; + maxIdx[1] = j + index; + } + } + } + } + } + if (minVal) + { + *minVal = val_min; + } + if (maxVal) + { + *maxVal = val_max; + } + + return CV_HAL_ERROR_OK; +} + +template +inline int minMaxIdxReadOnce(const uchar* src_data, size_t src_step, int width, int height, double* minVal, double* maxVal, + int* minIdx, int* maxIdx, uchar* mask, size_t mask_step) +{ + int vlmax = rvv::vsetvlmax(); + auto vec_min = rvv::vmv_v_x(std::numeric_limits::max(), vlmax); + auto vec_max = rvv::vmv_v_x(std::numeric_limits::lowest(), vlmax); + auto vec_pos = rvv::vid(vlmax); + auto vec_minpos = rvv::vundefined(), vec_maxpos = rvv::vundefined(); + T val_min, val_max; + + if (mask) + { + for (int i = 0; i < height; i++) + { + const T* src_row = reinterpret_cast(src_data + i * src_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = rvv::vsetvl(width - j); + auto vec_src = rvv::vle(src_row + j, vl); + auto vec_mask = rvv::vle_mask(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto bool_zero = __riscv_vmxor(bool_mask, bool_mask, vl); + + auto bool_minpos = rvv::vmlt_mu(bool_mask, bool_zero, vec_src, vec_min, vl); + auto bool_maxpos = rvv::vmgt_mu(bool_mask, bool_zero, vec_src, vec_max, vl); + vec_minpos = __riscv_vmerge_tu(vec_minpos, vec_minpos, vec_pos, bool_minpos, vl); + vec_maxpos = __riscv_vmerge_tu(vec_maxpos, vec_maxpos, vec_pos, bool_maxpos, vl); + + vec_min = __riscv_vmerge_tu(vec_min, vec_min, vec_src, bool_minpos, vl); + vec_max = __riscv_vmerge_tu(vec_max, vec_max, vec_src, bool_maxpos, vl); + vec_pos = __riscv_vadd(vec_pos, vl, vlmax); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const T* src_row = reinterpret_cast(src_data + i * src_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = rvv::vsetvl(width - j); + auto vec_src = rvv::vle(src_row + j, vl); + + auto bool_minpos = rvv::vmlt(vec_src, vec_min, vl); + auto bool_maxpos = rvv::vmgt(vec_src, vec_max, vl); + vec_minpos = __riscv_vmerge_tu(vec_minpos, vec_minpos, vec_pos, bool_minpos, vl); + vec_maxpos = __riscv_vmerge_tu(vec_maxpos, vec_maxpos, vec_pos, bool_maxpos, vl); + + vec_min = __riscv_vmerge_tu(vec_min, vec_min, vec_src, bool_minpos, vl); + vec_max = __riscv_vmerge_tu(vec_max, vec_max, vec_src, bool_maxpos, vl); + vec_pos = __riscv_vadd(vec_pos, vl, vlmax); + } + } + } + + val_min = std::numeric_limits::max(); + val_max = std::numeric_limits::lowest(); + for (int i = 0; i < vlmax; i++) + { + if (val_min > rvv::vmv_x_s(vec_min)) + { + val_min = rvv::vmv_x_s(vec_min); + if (minIdx) + { + minIdx[0] = __riscv_vmv_x(vec_minpos) / width; + minIdx[1] = __riscv_vmv_x(vec_minpos) % width; + } + } + if (val_max < rvv::vmv_x_s(vec_max)) + { + val_max = rvv::vmv_x_s(vec_max); + if (maxIdx) + { + maxIdx[0] = __riscv_vmv_x(vec_maxpos) / width; + maxIdx[1] = __riscv_vmv_x(vec_maxpos) % width; + } + } + vec_min = __riscv_vslidedown(vec_min, 1, vlmax); + vec_max = __riscv_vslidedown(vec_max, 1, vlmax); + vec_minpos = __riscv_vslidedown(vec_minpos, 1, vlmax); + vec_maxpos = __riscv_vslidedown(vec_maxpos, 1, vlmax); + } + if (minVal) + { + *minVal = val_min; + } + if (maxVal) + { + *maxVal = val_max; + } + + return CV_HAL_ERROR_OK; +} + +inline int minMaxIdx(const uchar* src_data, size_t src_step, int width, int height, int depth, double* minVal, double* maxVal, + int* minIdx, int* maxIdx, uchar* mask, size_t mask_step = 0) +{ + if (!mask_step) + mask_step = src_step; + + switch (depth) + { + case CV_8UC1: + return minMaxIdxReadTwice(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step); + case CV_8SC1: + return minMaxIdxReadTwice(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step); + case CV_16UC1: + return minMaxIdxReadTwice(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step); + case CV_16SC1: + return minMaxIdxReadTwice(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step); + case CV_32SC1: + return minMaxIdxReadOnce(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step); + case CV_32FC1: + return minMaxIdxReadOnce(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step); + case CV_64FC1: + return minMaxIdxReadOnce(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step); + } + + return CV_HAL_ERROR_NOT_IMPLEMENTED; +} + +}} + +#endif diff --git a/3rdparty/hal_rvv/hal_rvv_1p0/norm.hpp b/3rdparty/hal_rvv/hal_rvv_1p0/norm.hpp new file mode 100644 index 0000000000..e53b9d4391 --- /dev/null +++ b/3rdparty/hal_rvv/hal_rvv_1p0/norm.hpp @@ -0,0 +1,517 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +#ifndef OPENCV_HAL_RVV_NORM_HPP_INCLUDED +#define OPENCV_HAL_RVV_NORM_HPP_INCLUDED + +#include + +namespace cv { namespace cv_hal_rvv { + +#undef cv_hal_norm +#define cv_hal_norm cv::cv_hal_rvv::norm + +inline int normInf_8UC1(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m8(); + auto vec_max = __riscv_vmv_v_x_u8m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m8(width - j); + auto vec_src = __riscv_vle8_v_u8m8(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m8(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + vec_max = __riscv_vmaxu_tumu(bool_mask, vec_max, vec_max, vec_src, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m8(width - j); + auto vec_src = __riscv_vle8_v_u8m8(src_row + j, vl); + vec_max = __riscv_vmaxu_tu(vec_max, vec_max, vec_src, vl); + } + } + } + auto sc_max = __riscv_vmv_s_x_u8m1(0, vlmax); + sc_max = __riscv_vredmaxu(vec_max, sc_max, vlmax); + *result = __riscv_vmv_x(sc_max); + + return CV_HAL_ERROR_OK; +} + +inline int normL1_8UC1(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_zext = __riscv_vzext_vf4_u32m8_m(bool_mask, vec_src, vl); + vec_sum = __riscv_vadd_tumu(bool_mask, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_zext = __riscv_vzext_vf4(vec_src, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + auto sc_sum = __riscv_vmv_s_x_u32m1(0, vlmax); + sc_sum = __riscv_vredsum(vec_sum, sc_sum, vlmax); + *result = __riscv_vmv_x(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normL2Sqr_8UC1(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + int cnt = 0; + auto reduce = [&](int vl) { + if ((cnt += vl) < (1 << 16)) + return; + cnt = vl; + for (int i = 0; i < vlmax; i++) + { + *result += __riscv_vmv_x(vec_sum); + vec_sum = __riscv_vslidedown(vec_sum, 1, vlmax); + } + vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + }; + + *result = 0; + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + reduce(vl); + + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_mul = __riscv_vwmulu_vv_u16m4_m(bool_mask, vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2_u32m8_m(bool_mask, vec_mul, vl); + vec_sum = __riscv_vadd_tumu(bool_mask, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + reduce(vl); + + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_mul = __riscv_vwmulu(vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2(vec_mul, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + reduce(1 << 16); + + return CV_HAL_ERROR_OK; +} + +inline int normInf_8UC4(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m8(); + auto vec_max = __riscv_vmv_v_x_u8m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + const uchar* mask_row = mask + i * mask_step; + int vl, vlm; + for (int j = 0, jm = 0; j < width * 4; j += vl, jm += vlm) + { + vl = __riscv_vsetvl_e8m8(width * 4 - j); + vlm = __riscv_vsetvl_e8m2(width - jm); + auto vec_src = __riscv_vle8_v_u8m8(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + jm, vlm); + auto vec_mask_ext = __riscv_vmul(__riscv_vzext_vf4(__riscv_vminu(vec_mask, 1, vlm), vlm), 0x01010101, vlm); + auto bool_mask_ext = __riscv_vmsne(__riscv_vreinterpret_u8m8(vec_mask_ext), 0, vl); + vec_max = __riscv_vmaxu_tumu(bool_mask_ext, vec_max, vec_max, vec_src, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + int vl; + for (int j = 0; j < width * 4; j += vl) + { + vl = __riscv_vsetvl_e8m8(width * 4 - j); + auto vec_src = __riscv_vle8_v_u8m8(src_row + j, vl); + vec_max = __riscv_vmaxu_tu(vec_max, vec_max, vec_src, vl); + } + } + } + auto sc_max = __riscv_vmv_s_x_u8m1(0, vlmax); + sc_max = __riscv_vredmaxu(vec_max, sc_max, vlmax); + *result = __riscv_vmv_x(sc_max); + + return CV_HAL_ERROR_OK; +} + +inline int normL1_8UC4(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + const uchar* mask_row = mask + i * mask_step; + int vl, vlm; + for (int j = 0, jm = 0; j < width * 4; j += vl, jm += vlm) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + vlm = __riscv_vsetvl_e8mf2(width - jm); + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8mf2(mask_row + jm, vlm); + auto vec_mask_ext = __riscv_vmul(__riscv_vzext_vf4(__riscv_vminu(vec_mask, 1, vlm), vlm), 0x01010101, vlm); + auto bool_mask_ext = __riscv_vmsne(__riscv_vreinterpret_u8m2(vec_mask_ext), 0, vl); + auto vec_zext = __riscv_vzext_vf4_u32m8_m(bool_mask_ext, vec_src, vl); + vec_sum = __riscv_vadd_tumu(bool_mask_ext, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + int vl; + for (int j = 0; j < width * 4; j += vl) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_zext = __riscv_vzext_vf4(vec_src, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + auto sc_sum = __riscv_vmv_s_x_u32m1(0, vlmax); + sc_sum = __riscv_vredsum(vec_sum, sc_sum, vlmax); + *result = __riscv_vmv_x(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normL2Sqr_8UC4(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + int cnt = 0; + auto reduce = [&](int vl) { + if ((cnt += vl) < (1 << 16)) + return; + cnt = vl; + for (int i = 0; i < vlmax; i++) + { + *result += __riscv_vmv_x(vec_sum); + vec_sum = __riscv_vslidedown(vec_sum, 1, vlmax); + } + vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + }; + + *result = 0; + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + const uchar* mask_row = mask + i * mask_step; + int vl, vlm; + for (int j = 0, jm = 0; j < width * 4; j += vl, jm += vlm) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + vlm = __riscv_vsetvl_e8mf2(width - jm); + reduce(vl); + + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8mf2(mask_row + jm, vlm); + auto vec_mask_ext = __riscv_vmul(__riscv_vzext_vf4(__riscv_vminu(vec_mask, 1, vlm), vlm), 0x01010101, vlm); + auto bool_mask_ext = __riscv_vmsne(__riscv_vreinterpret_u8m2(vec_mask_ext), 0, vl); + auto vec_mul = __riscv_vwmulu_vv_u16m4_m(bool_mask_ext, vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2_u32m8_m(bool_mask_ext, vec_mul, vl); + vec_sum = __riscv_vadd_tumu(bool_mask_ext, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + int vl; + for (int j = 0; j < width * 4; j += vl) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + reduce(vl); + + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_mul = __riscv_vwmulu(vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2(vec_mul, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + reduce(1 << 16); + + return CV_HAL_ERROR_OK; +} + +inline int normInf_32FC1(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e32m8(); + auto vec_max = __riscv_vfmv_v_f_f32m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m8(width - j); + auto vec_src = __riscv_vle32_v_f32m8(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_abs = __riscv_vfabs_v_f32m8_m(bool_mask, vec_src, vl); + vec_max = __riscv_vfmax_tumu(bool_mask, vec_max, vec_max, vec_abs, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m8(width - j); + auto vec_src = __riscv_vle32_v_f32m8(src_row + j, vl); + auto vec_abs = __riscv_vfabs(vec_src, vl); + vec_max = __riscv_vfmax_tu(vec_max, vec_max, vec_abs, vl); + } + } + } + auto sc_max = __riscv_vfmv_s_f_f32m1(0, vlmax); + sc_max = __riscv_vfredmax(vec_max, sc_max, vlmax); + *result = __riscv_vfmv_f(sc_max); + + return CV_HAL_ERROR_OK; +} + +inline int normL1_32FC1(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e32m4(); + auto vec_sum = __riscv_vfmv_v_f_f64m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src = __riscv_vle32_v_f32m4(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m1(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_abs = __riscv_vfabs_v_f32m4_m(bool_mask, vec_src, vl); + auto vec_fext = __riscv_vfwcvt_f_f_v_f64m8_m(bool_mask, vec_abs, vl); + vec_sum = __riscv_vfadd_tumu(bool_mask, vec_sum, vec_sum, vec_fext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src = __riscv_vle32_v_f32m4(src_row + j, vl); + auto vec_abs = __riscv_vfabs(vec_src, vl); + auto vec_fext = __riscv_vfwcvt_f_f_v_f64m8(vec_abs, vl); + vec_sum = __riscv_vfadd_tu(vec_sum, vec_sum, vec_fext, vl); + } + } + } + auto sc_sum = __riscv_vfmv_s_f_f64m1(0, vlmax); + sc_sum = __riscv_vfredosum(vec_sum, sc_sum, vlmax); + *result = __riscv_vfmv_f(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normL2Sqr_32FC1(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e32m4(); + auto vec_sum = __riscv_vfmv_v_f_f64m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src = __riscv_vle32_v_f32m4(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m1(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_mul = __riscv_vfwmul_vv_f64m8_m(bool_mask, vec_src, vec_src, vl); + vec_sum = __riscv_vfadd_tumu(bool_mask, vec_sum, vec_sum, vec_mul, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src = __riscv_vle32_v_f32m4(src_row + j, vl); + auto vec_mul = __riscv_vfwmul(vec_src, vec_src, vl); + vec_sum = __riscv_vfadd_tu(vec_sum, vec_sum, vec_mul, vl); + } + } + } + auto sc_sum = __riscv_vfmv_s_f_f64m1(0, vlmax); + sc_sum = __riscv_vfredosum(vec_sum, sc_sum, vlmax); + *result = __riscv_vfmv_f(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int norm(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, + int height, int type, int norm_type, double* result) +{ + if (!result) + return CV_HAL_ERROR_OK; + + switch (type) + { + case CV_8UC1: + switch (norm_type) + { + case NORM_INF: + return normInf_8UC1(src, src_step, mask, mask_step, width, height, result); + case NORM_L1: + return normL1_8UC1(src, src_step, mask, mask_step, width, height, result); + case NORM_L2SQR: + return normL2Sqr_8UC1(src, src_step, mask, mask_step, width, height, result); + case NORM_L2: + int ret = normL2Sqr_8UC1(src, src_step, mask, mask_step, width, height, result); + *result = std::sqrt(*result); + return ret; + } + return CV_HAL_ERROR_NOT_IMPLEMENTED; + case CV_8UC4: + switch (norm_type) + { + case NORM_INF: + return normInf_8UC4(src, src_step, mask, mask_step, width, height, result); + case NORM_L1: + return normL1_8UC4(src, src_step, mask, mask_step, width, height, result); + case NORM_L2SQR: + return normL2Sqr_8UC4(src, src_step, mask, mask_step, width, height, result); + case NORM_L2: + int ret = normL2Sqr_8UC4(src, src_step, mask, mask_step, width, height, result); + *result = std::sqrt(*result); + return ret; + } + return CV_HAL_ERROR_NOT_IMPLEMENTED; + case CV_32FC1: + switch (norm_type) + { + case NORM_INF: + return normInf_32FC1(src, src_step, mask, mask_step, width, height, result); + case NORM_L1: + return normL1_32FC1(src, src_step, mask, mask_step, width, height, result); + case NORM_L2SQR: + return normL2Sqr_32FC1(src, src_step, mask, mask_step, width, height, result); + case NORM_L2: + int ret = normL2Sqr_32FC1(src, src_step, mask, mask_step, width, height, result); + *result = std::sqrt(*result); + return ret; + } + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + return CV_HAL_ERROR_NOT_IMPLEMENTED; +} + +}} + +#endif diff --git a/3rdparty/hal_rvv/hal_rvv_1p0/norm_diff.hpp b/3rdparty/hal_rvv/hal_rvv_1p0/norm_diff.hpp new file mode 100644 index 0000000000..6e4a9be65d --- /dev/null +++ b/3rdparty/hal_rvv/hal_rvv_1p0/norm_diff.hpp @@ -0,0 +1,605 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +#ifndef OPENCV_HAL_RVV_NORM_DIFF_HPP_INCLUDED +#define OPENCV_HAL_RVV_NORM_DIFF_HPP_INCLUDED + +#include + +namespace cv { namespace cv_hal_rvv { + +#undef cv_hal_normDiff +#define cv_hal_normDiff cv::cv_hal_rvv::normDiff + +inline int normDiffInf_8UC1(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m8(); + auto vec_max = __riscv_vmv_v_x_u8m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m8(width - j); + auto vec_src1 = __riscv_vle8_v_u8m8(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m8(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m8(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_src = __riscv_vsub_vv_u8m8_m(bool_mask, __riscv_vmaxu_vv_u8m8_m(bool_mask, vec_src1, vec_src2, vl), + __riscv_vminu_vv_u8m8_m(bool_mask, vec_src1, vec_src2, vl), vl); + vec_max = __riscv_vmaxu_tumu(bool_mask, vec_max, vec_max, vec_src, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m8(width - j); + auto vec_src1 = __riscv_vle8_v_u8m8(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m8(src2_row + j, vl); + auto vec_src = __riscv_vsub(__riscv_vmaxu(vec_src1, vec_src2, vl), __riscv_vminu(vec_src1, vec_src2, vl), vl); + vec_max = __riscv_vmaxu_tu(vec_max, vec_max, vec_src, vl); + } + } + } + auto sc_max = __riscv_vmv_s_x_u8m1(0, vlmax); + sc_max = __riscv_vredmaxu(vec_max, sc_max, vlmax); + *result = __riscv_vmv_x(sc_max); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffL1_8UC1(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_src = __riscv_vsub_vv_u8m2_m(bool_mask, __riscv_vmaxu_vv_u8m2_m(bool_mask, vec_src1, vec_src2, vl), + __riscv_vminu_vv_u8m2_m(bool_mask, vec_src1, vec_src2, vl), vl); + auto vec_zext = __riscv_vzext_vf4_u32m8_m(bool_mask, vec_src, vl); + vec_sum = __riscv_vadd_tumu(bool_mask, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_src = __riscv_vsub(__riscv_vmaxu(vec_src1, vec_src2, vl), __riscv_vminu(vec_src1, vec_src2, vl), vl); + auto vec_zext = __riscv_vzext_vf4(vec_src, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + auto sc_sum = __riscv_vmv_s_x_u32m1(0, vlmax); + sc_sum = __riscv_vredsum(vec_sum, sc_sum, vlmax); + *result = __riscv_vmv_x(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffL2Sqr_8UC1(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + int cnt = 0; + auto reduce = [&](int vl) { + if ((cnt += vl) < (1 << 16)) + return; + cnt = vl; + for (int i = 0; i < vlmax; i++) + { + *result += __riscv_vmv_x(vec_sum); + vec_sum = __riscv_vslidedown(vec_sum, 1, vlmax); + } + vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + }; + + *result = 0; + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + reduce(vl); + + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_src = __riscv_vsub_vv_u8m2_m(bool_mask, __riscv_vmaxu_vv_u8m2_m(bool_mask, vec_src1, vec_src2, vl), + __riscv_vminu_vv_u8m2_m(bool_mask, vec_src1, vec_src2, vl), vl); + auto vec_mul = __riscv_vwmulu_vv_u16m4_m(bool_mask, vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2_u32m8_m(bool_mask, vec_mul, vl); + vec_sum = __riscv_vadd_tumu(bool_mask, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + reduce(vl); + + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_src = __riscv_vsub(__riscv_vmaxu(vec_src1, vec_src2, vl), __riscv_vminu(vec_src1, vec_src2, vl), vl); + auto vec_mul = __riscv_vwmulu(vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2(vec_mul, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + reduce(1 << 16); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffInf_8UC4(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m8(); + auto vec_max = __riscv_vmv_v_x_u8m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + const uchar* mask_row = mask + i * mask_step; + int vl, vlm; + for (int j = 0, jm = 0; j < width * 4; j += vl, jm += vlm) + { + vl = __riscv_vsetvl_e8m8(width * 4 - j); + vlm = __riscv_vsetvl_e8m2(width - jm); + auto vec_src1 = __riscv_vle8_v_u8m8(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m8(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + jm, vlm); + auto vec_mask_ext = __riscv_vmul(__riscv_vzext_vf4(__riscv_vminu(vec_mask, 1, vlm), vlm), 0x01010101, vlm); + auto bool_mask_ext = __riscv_vmsne(__riscv_vreinterpret_u8m8(vec_mask_ext), 0, vl); + auto vec_src = __riscv_vsub_vv_u8m8_m(bool_mask_ext, __riscv_vmaxu_vv_u8m8_m(bool_mask_ext, vec_src1, vec_src2, vl), + __riscv_vminu_vv_u8m8_m(bool_mask_ext, vec_src1, vec_src2, vl), vl); + vec_max = __riscv_vmaxu_tumu(bool_mask_ext, vec_max, vec_max, vec_src, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + int vl; + for (int j = 0; j < width * 4; j += vl) + { + vl = __riscv_vsetvl_e8m8(width * 4 - j); + auto vec_src1 = __riscv_vle8_v_u8m8(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m8(src2_row + j, vl); + auto vec_src = __riscv_vsub(__riscv_vmaxu(vec_src1, vec_src2, vl), __riscv_vminu(vec_src1, vec_src2, vl), vl); + vec_max = __riscv_vmaxu_tu(vec_max, vec_max, vec_src, vl); + } + } + } + auto sc_max = __riscv_vmv_s_x_u8m1(0, vlmax); + sc_max = __riscv_vredmaxu(vec_max, sc_max, vlmax); + *result = __riscv_vmv_x(sc_max); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffL1_8UC4(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + const uchar* mask_row = mask + i * mask_step; + int vl, vlm; + for (int j = 0, jm = 0; j < width * 4; j += vl, jm += vlm) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + vlm = __riscv_vsetvl_e8mf2(width - jm); + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8mf2(mask_row + jm, vlm); + auto vec_mask_ext = __riscv_vmul(__riscv_vzext_vf4(__riscv_vminu(vec_mask, 1, vlm), vlm), 0x01010101, vlm); + auto bool_mask_ext = __riscv_vmsne(__riscv_vreinterpret_u8m2(vec_mask_ext), 0, vl); + auto vec_src = __riscv_vsub_vv_u8m2_m(bool_mask_ext, __riscv_vmaxu_vv_u8m2_m(bool_mask_ext, vec_src1, vec_src2, vl), + __riscv_vminu_vv_u8m2_m(bool_mask_ext, vec_src1, vec_src2, vl), vl); + auto vec_zext = __riscv_vzext_vf4_u32m8_m(bool_mask_ext, vec_src, vl); + vec_sum = __riscv_vadd_tumu(bool_mask_ext, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + int vl; + for (int j = 0; j < width * 4; j += vl) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_src = __riscv_vsub(__riscv_vmaxu(vec_src1, vec_src2, vl), __riscv_vminu(vec_src1, vec_src2, vl), vl); + auto vec_zext = __riscv_vzext_vf4(vec_src, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + auto sc_sum = __riscv_vmv_s_x_u32m1(0, vlmax); + sc_sum = __riscv_vredsum(vec_sum, sc_sum, vlmax); + *result = __riscv_vmv_x(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffL2Sqr_8UC4(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + int cnt = 0; + auto reduce = [&](int vl) { + if ((cnt += vl) < (1 << 16)) + return; + cnt = vl; + for (int i = 0; i < vlmax; i++) + { + *result += __riscv_vmv_x(vec_sum); + vec_sum = __riscv_vslidedown(vec_sum, 1, vlmax); + } + vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + }; + + *result = 0; + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + const uchar* mask_row = mask + i * mask_step; + int vl, vlm; + for (int j = 0, jm = 0; j < width * 4; j += vl, jm += vlm) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + vlm = __riscv_vsetvl_e8mf2(width - jm); + reduce(vl); + + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8mf2(mask_row + jm, vlm); + auto vec_mask_ext = __riscv_vmul(__riscv_vzext_vf4(__riscv_vminu(vec_mask, 1, vlm), vlm), 0x01010101, vlm); + auto bool_mask_ext = __riscv_vmsne(__riscv_vreinterpret_u8m2(vec_mask_ext), 0, vl); + auto vec_src = __riscv_vsub_vv_u8m2_m(bool_mask_ext, __riscv_vmaxu_vv_u8m2_m(bool_mask_ext, vec_src1, vec_src2, vl), + __riscv_vminu_vv_u8m2_m(bool_mask_ext, vec_src1, vec_src2, vl), vl); + auto vec_mul = __riscv_vwmulu_vv_u16m4_m(bool_mask_ext, vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2_u32m8_m(bool_mask_ext, vec_mul, vl); + vec_sum = __riscv_vadd_tumu(bool_mask_ext, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + int vl; + for (int j = 0; j < width * 4; j += vl) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + reduce(vl); + + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_src = __riscv_vsub(__riscv_vmaxu(vec_src1, vec_src2, vl), __riscv_vminu(vec_src1, vec_src2, vl), vl); + auto vec_mul = __riscv_vwmulu(vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2(vec_mul, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + reduce(1 << 16); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffInf_32FC1(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e32m8(); + auto vec_max = __riscv_vfmv_v_f_f32m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const float* src1_row = reinterpret_cast(src1 + i * src1_step); + const float* src2_row = reinterpret_cast(src2 + i * src2_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m8(width - j); + auto vec_src1 = __riscv_vle32_v_f32m8(src1_row + j, vl); + auto vec_src2 = __riscv_vle32_v_f32m8(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_src = __riscv_vfsub_vv_f32m8_m(bool_mask, vec_src1, vec_src2, vl); + auto vec_abs = __riscv_vfabs_v_f32m8_m(bool_mask, vec_src, vl); + vec_max = __riscv_vfmax_tumu(bool_mask, vec_max, vec_max, vec_abs, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const float* src1_row = reinterpret_cast(src1 + i * src1_step); + const float* src2_row = reinterpret_cast(src2 + i * src2_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m8(width - j); + auto vec_src1 = __riscv_vle32_v_f32m8(src1_row + j, vl); + auto vec_src2 = __riscv_vle32_v_f32m8(src2_row + j, vl); + auto vec_src = __riscv_vfsub(vec_src1, vec_src2, vl); + auto vec_abs = __riscv_vfabs(vec_src, vl); + vec_max = __riscv_vfmax_tu(vec_max, vec_max, vec_abs, vl); + } + } + } + auto sc_max = __riscv_vfmv_s_f_f32m1(0, vlmax); + sc_max = __riscv_vfredmax(vec_max, sc_max, vlmax); + *result = __riscv_vfmv_f(sc_max); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffL1_32FC1(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e32m4(); + auto vec_sum = __riscv_vfmv_v_f_f64m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const float* src1_row = reinterpret_cast(src1 + i * src1_step); + const float* src2_row = reinterpret_cast(src2 + i * src2_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src1 = __riscv_vle32_v_f32m4(src1_row + j, vl); + auto vec_src2 = __riscv_vle32_v_f32m4(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m1(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_src = __riscv_vfsub_vv_f32m4_m(bool_mask, vec_src1, vec_src2, vl); + auto vec_abs = __riscv_vfabs_v_f32m4_m(bool_mask, vec_src, vl); + auto vec_fext = __riscv_vfwcvt_f_f_v_f64m8_m(bool_mask, vec_abs, vl); + vec_sum = __riscv_vfadd_tumu(bool_mask, vec_sum, vec_sum, vec_fext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const float* src1_row = reinterpret_cast(src1 + i * src1_step); + const float* src2_row = reinterpret_cast(src2 + i * src2_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src1 = __riscv_vle32_v_f32m4(src1_row + j, vl); + auto vec_src2 = __riscv_vle32_v_f32m4(src2_row + j, vl); + auto vec_src = __riscv_vfsub(vec_src1, vec_src2, vl); + auto vec_abs = __riscv_vfabs(vec_src, vl); + auto vec_fext = __riscv_vfwcvt_f_f_v_f64m8(vec_abs, vl); + vec_sum = __riscv_vfadd_tu(vec_sum, vec_sum, vec_fext, vl); + } + } + } + auto sc_sum = __riscv_vfmv_s_f_f64m1(0, vlmax); + sc_sum = __riscv_vfredosum(vec_sum, sc_sum, vlmax); + *result = __riscv_vfmv_f(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffL2Sqr_32FC1(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e32m4(); + auto vec_sum = __riscv_vfmv_v_f_f64m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const float* src1_row = reinterpret_cast(src1 + i * src1_step); + const float* src2_row = reinterpret_cast(src2 + i * src2_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src1 = __riscv_vle32_v_f32m4(src1_row + j, vl); + auto vec_src2 = __riscv_vle32_v_f32m4(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m1(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_src = __riscv_vfsub_vv_f32m4_m(bool_mask, vec_src1, vec_src2, vl); + auto vec_mul = __riscv_vfwmul_vv_f64m8_m(bool_mask, vec_src, vec_src, vl); + vec_sum = __riscv_vfadd_tumu(bool_mask, vec_sum, vec_sum, vec_mul, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const float* src1_row = reinterpret_cast(src1 + i * src1_step); + const float* src2_row = reinterpret_cast(src2 + i * src2_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src1 = __riscv_vle32_v_f32m4(src1_row + j, vl); + auto vec_src2 = __riscv_vle32_v_f32m4(src2_row + j, vl); + auto vec_src = __riscv_vfsub(vec_src1, vec_src2, vl); + auto vec_mul = __riscv_vfwmul(vec_src, vec_src, vl); + vec_sum = __riscv_vfadd_tu(vec_sum, vec_sum, vec_mul, vl); + } + } + } + auto sc_sum = __riscv_vfmv_s_f_f64m1(0, vlmax); + sc_sum = __riscv_vfredosum(vec_sum, sc_sum, vlmax); + *result = __riscv_vfmv_f(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normDiff(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, + size_t mask_step, int width, int height, int type, int norm_type, double* result) +{ + if (!result) + return CV_HAL_ERROR_OK; + + int ret; + switch (type) + { + case CV_8UC1: + switch (norm_type & ~NORM_RELATIVE) + { + case NORM_INF: + ret = normDiffInf_8UC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L1: + ret = normDiffL1_8UC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L2SQR: + ret = normDiffL2Sqr_8UC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L2: + ret = normDiffL2Sqr_8UC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + *result = std::sqrt(*result); + break; + default: + ret = CV_HAL_ERROR_NOT_IMPLEMENTED; + } + break; + case CV_8UC4: + switch (norm_type & ~NORM_RELATIVE) + { + case NORM_INF: + ret = normDiffInf_8UC4(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L1: + ret = normDiffL1_8UC4(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L2SQR: + ret = normDiffL2Sqr_8UC4(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L2: + ret = normDiffL2Sqr_8UC4(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + *result = std::sqrt(*result); + break; + default: + ret = CV_HAL_ERROR_NOT_IMPLEMENTED; + } + break; + case CV_32FC1: + switch (norm_type & ~NORM_RELATIVE) + { + case NORM_INF: + ret = normDiffInf_32FC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L1: + ret = normDiffL1_32FC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L2SQR: + ret = normDiffL2Sqr_32FC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L2: + ret = normDiffL2Sqr_32FC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + *result = std::sqrt(*result); + break; + default: + ret = CV_HAL_ERROR_NOT_IMPLEMENTED; + } + break; + default: + ret = CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + if(ret == CV_HAL_ERROR_OK && (norm_type & NORM_RELATIVE)) + { + double result_; + ret = cv::cv_hal_rvv::norm(src2, src2_step, mask, mask_step, width, height, type, norm_type & ~NORM_RELATIVE, &result_); + if(ret == CV_HAL_ERROR_OK) + { + *result /= result_ + DBL_EPSILON; + } + } + + return ret; +} + +}} + +#endif diff --git a/3rdparty/hal_rvv/hal_rvv_1p0/split.hpp b/3rdparty/hal_rvv/hal_rvv_1p0/split.hpp new file mode 100644 index 0000000000..9646fd9f67 --- /dev/null +++ b/3rdparty/hal_rvv/hal_rvv_1p0/split.hpp @@ -0,0 +1,93 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +#ifndef OPENCV_HAL_RVV_SPLIT_HPP_INCLUDED +#define OPENCV_HAL_RVV_SPLIT_HPP_INCLUDED + +#include + +namespace cv { namespace cv_hal_rvv { + +#undef cv_hal_split8u +#define cv_hal_split8u cv::cv_hal_rvv::split8u + +inline int split8u(const uchar* src, uchar** dst, int len, int cn) +{ + int vl = 0; + if (cn == 1) + { + uchar* dst0 = dst[0]; + for (int i = 0; i < len; i += vl) + { + vl = __riscv_vsetvl_e8m8(len - i); + __riscv_vse8_v_u8m8(dst0 + i, __riscv_vle8_v_u8m8(src + i, vl), vl); + } + } + else if (cn == 2) + { + uchar *dst0 = dst[0], *dst1 = dst[1]; + for (int i = 0; i < len; i += vl) + { + vl = __riscv_vsetvl_e8m4(len - i); + vuint8m4x2_t seg = __riscv_vlseg2e8_v_u8m4x2(src + i * cn, vl); + __riscv_vse8_v_u8m4(dst0 + i, __riscv_vget_v_u8m4x2_u8m4(seg, 0), vl); + __riscv_vse8_v_u8m4(dst1 + i, __riscv_vget_v_u8m4x2_u8m4(seg, 1), vl); + } + } + else if (cn == 3) + { + uchar *dst0 = dst[0], *dst1 = dst[1], *dst2 = dst[2]; + for (int i = 0; i < len; i += vl) + { + vl = __riscv_vsetvl_e8m2(len - i); + vuint8m2x3_t seg = __riscv_vlseg3e8_v_u8m2x3(src + i * cn, vl); + __riscv_vse8_v_u8m2(dst0 + i, __riscv_vget_v_u8m2x3_u8m2(seg, 0), vl); + __riscv_vse8_v_u8m2(dst1 + i, __riscv_vget_v_u8m2x3_u8m2(seg, 1), vl); + __riscv_vse8_v_u8m2(dst2 + i, __riscv_vget_v_u8m2x3_u8m2(seg, 2), vl); + } + } + else if (cn == 4) + { + uchar *dst0 = dst[0], *dst1 = dst[1], *dst2 = dst[2], *dst3 = dst[3]; + for (int i = 0; i < len; i += vl) + { + vl = __riscv_vsetvl_e8m2(len - i); + vuint8m2x4_t seg = __riscv_vlseg4e8_v_u8m2x4(src + i * cn, vl); + __riscv_vse8_v_u8m2(dst0 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 0), vl); + __riscv_vse8_v_u8m2(dst1 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 1), vl); + __riscv_vse8_v_u8m2(dst2 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 2), vl); + __riscv_vse8_v_u8m2(dst3 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 3), vl); + } + } + else + { + int k = 0; + for (; k <= cn - 4; k += 4) + { + uchar *dst0 = dst[k], *dst1 = dst[k + 1], *dst2 = dst[k + 2], *dst3 = dst[k + 3]; + for (int i = 0; i < len; i += vl) + { + vl = __riscv_vsetvl_e8m2(len - i); + vuint8m2x4_t seg = __riscv_vlsseg4e8_v_u8m2x4(src + k + i * cn, cn, vl); + __riscv_vse8_v_u8m2(dst0 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 0), vl); + __riscv_vse8_v_u8m2(dst1 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 1), vl); + __riscv_vse8_v_u8m2(dst2 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 2), vl); + __riscv_vse8_v_u8m2(dst3 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 3), vl); + } + } + for (; k < cn; ++k) + { + uchar* dstK = dst[k]; + for (int i = 0; i < len; i += vl) + { + vl = __riscv_vsetvl_e8m2(len - i); + vuint8m2_t seg = __riscv_vlse8_v_u8m2(src + k + i * cn, cn, vl); + __riscv_vse8_v_u8m2(dstK + i, seg, vl); + } + } + } + return CV_HAL_ERROR_OK; +} + +}} +#endif diff --git a/3rdparty/ippicv/ippicv.cmake b/3rdparty/ippicv/ippicv.cmake index 7644bbba45..7bfcf66993 100644 --- a/3rdparty/ippicv/ippicv.cmake +++ b/3rdparty/ippicv/ippicv.cmake @@ -2,7 +2,7 @@ function(download_ippicv root_var) set(${root_var} "" PARENT_SCOPE) # Commit SHA in the opencv_3rdparty repo - set(IPPICV_COMMIT "7f55c0c26be418d494615afca15218566775c725") + set(IPPICV_COMMIT "d1cbea44d326eb0421fedcdd16de4630fd8c7ed0") # Define actual ICV versions if(APPLE) set(IPPICV_COMMIT "0cc4aa06bf2bef4b05d237c69a5a96b9cd0cb85a") @@ -14,9 +14,10 @@ function(download_ippicv root_var) set(OPENCV_ICV_PLATFORM "linux") set(OPENCV_ICV_PACKAGE_SUBDIR "ippicv_lnx") if(X86_64) - set(OPENCV_ICV_NAME "ippicv_2021.12.0_lnx_intel64_20240425_general.tgz") - set(OPENCV_ICV_HASH "d06e6d44ece88f7f17a6cd9216761186") + set(OPENCV_ICV_NAME "ippicv_2022.0.0_lnx_intel64_20240904_general.tgz") + set(OPENCV_ICV_HASH "63717ee0f918ad72fb5a737992a206d1") else() + set(IPPICV_COMMIT "7f55c0c26be418d494615afca15218566775c725") set(OPENCV_ICV_NAME "ippicv_2021.12.0_lnx_ia32_20240425_general.tgz") set(OPENCV_ICV_HASH "85ffa2b9ed7802b93c23fa27b0097d36") endif() @@ -24,9 +25,10 @@ function(download_ippicv root_var) set(OPENCV_ICV_PLATFORM "windows") set(OPENCV_ICV_PACKAGE_SUBDIR "ippicv_win") if(X86_64) - set(OPENCV_ICV_NAME "ippicv_2021.12.0_win_intel64_20240425_general.zip") - set(OPENCV_ICV_HASH "402ff8c6b4986738fed71c44e1ce665d") + set(OPENCV_ICV_NAME "ippicv_2022.0.0_win_intel64_20240904_general.zip") + set(OPENCV_ICV_HASH "3a6eca7cc3bce7159eb1443c6fca4e31") else() + set(IPPICV_COMMIT "7f55c0c26be418d494615afca15218566775c725") set(OPENCV_ICV_NAME "ippicv_2021.12.0_win_ia32_20240425_general.zip") set(OPENCV_ICV_HASH "8b1d2a23957d57624d0de8f2a5cae5f1") endif() diff --git a/3rdparty/ittnotify/CMakeLists.txt b/3rdparty/ittnotify/CMakeLists.txt index 0f39adcd4b..02f1057a68 100644 --- a/3rdparty/ittnotify/CMakeLists.txt +++ b/3rdparty/ittnotify/CMakeLists.txt @@ -24,7 +24,6 @@ set(ITT_PUBLIC_HDRS include/ittnotify.h include/jitprofiling.h include/libittnotify.h - include/llvm_jit_event_listener.hpp ) set(ITT_PRIVATE_HDRS src/ittnotify/disable_warnings.h @@ -39,6 +38,11 @@ set(ITT_SRCS add_library(${ITT_LIBRARY} STATIC ${OPENCV_3RDPARTY_EXCLUDE_FROM_ALL} ${ITT_SRCS} ${ITT_PUBLIC_HDRS} ${ITT_PRIVATE_HDRS}) +file(STRINGS "src/ittnotify/ittnotify_config.h" API_VERSION_NUM REGEX "#define\[ \t]+API_VERSION_NUM[ \t]+([0-9\.]+)") +if(API_VERSION_NUM MATCHES "#define\[ \t]+API_VERSION_NUM[ \t]+([0-9\.]*)") + set(ITTNOTIFY_VERSION "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE) +endif() + if(NOT WIN32) if(HAVE_DL_LIBRARY) target_link_libraries(${ITT_LIBRARY} dl) @@ -64,4 +68,4 @@ if(NOT BUILD_SHARED_LIBS) ocv_install_target(${ITT_LIBRARY} EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev OPTIONAL) endif() -ocv_install_3rdparty_licenses(ittnotify src/ittnotify/LICENSE.BSD src/ittnotify/LICENSE.GPL) +ocv_install_3rdparty_licenses(ittnotify src/ittnotify/BSD-3-Clause.txt src/ittnotify/GPL-2.0-only.txt) diff --git a/3rdparty/ittnotify/include/ittnotify.h b/3rdparty/ittnotify/include/ittnotify.h index 93e5ff7187..898f8bb61a 100644 --- a/3rdparty/ittnotify/include/ittnotify.h +++ b/3rdparty/ittnotify/include/ittnotify.h @@ -1,60 +1,8 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. +/* + Copyright (C) 2005-2019 Intel Corporation - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +*/ #ifndef _ITTNOTIFY_H_ #define _ITTNOTIFY_H_ @@ -63,7 +11,8 @@ @brief Public User API functions and types @mainpage -The ITT API is used to annotate a user's program with additional information +The Instrumentation and Tracing Technology API (ITT API) is used to +annotate a user's program with additional information that can be used by correctness and performance tools. The user inserts calls in their program. Those calls generate information that is collected at runtime, and used by Intel(R) Threading Tools. @@ -141,6 +90,10 @@ The same ID may not be reused for different instances, unless a previous # define ITT_OS_FREEBSD 4 #endif /* ITT_OS_FREEBSD */ +#ifndef ITT_OS_OPENBSD +# define ITT_OS_OPENBSD 5 +#endif /* ITT_OS_OPENBSD */ + #ifndef ITT_OS # if defined WIN32 || defined _WIN32 # define ITT_OS ITT_OS_WIN @@ -148,6 +101,8 @@ The same ID may not be reused for different instances, unless a previous # define ITT_OS ITT_OS_MAC # elif defined( __FreeBSD__ ) # define ITT_OS ITT_OS_FREEBSD +# elif defined( __OpenBSD__) +# define ITT_OS ITT_OS_OPENBSD # else # define ITT_OS ITT_OS_LINUX # endif @@ -169,6 +124,10 @@ The same ID may not be reused for different instances, unless a previous # define ITT_PLATFORM_FREEBSD 4 #endif /* ITT_PLATFORM_FREEBSD */ +#ifndef ITT_PLATFORM_OPENBSD +# define ITT_PLATFORM_OPENBSD 5 +#endif /* ITT_PLATFORM_OPENBSD */ + #ifndef ITT_PLATFORM # if ITT_OS==ITT_OS_WIN # define ITT_PLATFORM ITT_PLATFORM_WIN @@ -176,6 +135,8 @@ The same ID may not be reused for different instances, unless a previous # define ITT_PLATFORM ITT_PLATFORM_MAC # elif ITT_OS==ITT_OS_FREEBSD # define ITT_PLATFORM ITT_PLATFORM_FREEBSD +# elif ITT_OS==ITT_OS_OPENBSD +# define ITT_PLATFORM ITT_PLATFORM_OPENBSD # else # define ITT_PLATFORM ITT_PLATFORM_POSIX # endif @@ -228,7 +189,12 @@ The same ID may not be reused for different instances, unless a previous #if ITT_PLATFORM==ITT_PLATFORM_WIN /* use __forceinline (VC++ specific) */ -#define ITT_INLINE __forceinline +#if defined(__MINGW32__) && !defined(__cplusplus) +#define ITT_INLINE static __inline__ __attribute__((__always_inline__,__gnu_inline__)) +#else +#define ITT_INLINE static __forceinline +#endif /* __MINGW32__ */ + #define ITT_INLINE_ATTRIBUTE /* nothing */ #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ /* @@ -289,20 +255,20 @@ The same ID may not be reused for different instances, unless a previous #define ITTNOTIFY_VOID(n) (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n) #define ITTNOTIFY_DATA(n) (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n) -#define ITTNOTIFY_VOID_D0(n,d) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d) -#define ITTNOTIFY_VOID_D1(n,d,x) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x) -#define ITTNOTIFY_VOID_D2(n,d,x,y) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y) -#define ITTNOTIFY_VOID_D3(n,d,x,y,z) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z) -#define ITTNOTIFY_VOID_D4(n,d,x,y,z,a) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z,a) -#define ITTNOTIFY_VOID_D5(n,d,x,y,z,a,b) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b) -#define ITTNOTIFY_VOID_D6(n,d,x,y,z,a,b,c) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b,c) -#define ITTNOTIFY_DATA_D0(n,d) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d) -#define ITTNOTIFY_DATA_D1(n,d,x) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x) -#define ITTNOTIFY_DATA_D2(n,d,x,y) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y) -#define ITTNOTIFY_DATA_D3(n,d,x,y,z) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z) -#define ITTNOTIFY_DATA_D4(n,d,x,y,z,a) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z,a) -#define ITTNOTIFY_DATA_D5(n,d,x,y,z,a,b) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b) -#define ITTNOTIFY_DATA_D6(n,d,x,y,z,a,b,c) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b,c) +#define ITTNOTIFY_VOID_D0(n,d) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d) +#define ITTNOTIFY_VOID_D1(n,d,x) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x) +#define ITTNOTIFY_VOID_D2(n,d,x,y) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y) +#define ITTNOTIFY_VOID_D3(n,d,x,y,z) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z) +#define ITTNOTIFY_VOID_D4(n,d,x,y,z,a) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z,a) +#define ITTNOTIFY_VOID_D5(n,d,x,y,z,a,b) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b) +#define ITTNOTIFY_VOID_D6(n,d,x,y,z,a,b,c) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b,c) +#define ITTNOTIFY_DATA_D0(n,d) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d) +#define ITTNOTIFY_DATA_D1(n,d,x) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x) +#define ITTNOTIFY_DATA_D2(n,d,x,y) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y) +#define ITTNOTIFY_DATA_D3(n,d,x,y,z) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z) +#define ITTNOTIFY_DATA_D4(n,d,x,y,z,a) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z,a) +#define ITTNOTIFY_DATA_D5(n,d,x,y,z,a,b) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b) +#define ITTNOTIFY_DATA_D6(n,d,x,y,z,a,b,c) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b,c) #ifdef ITT_STUB #undef ITT_STUB @@ -340,7 +306,7 @@ extern "C" { * only pauses tracing and analyzing memory access. * It does not pause tracing or analyzing threading APIs. * . - * - Intel(R) Parallel Amplifier and Intel(R) VTune(TM) Amplifier XE: + * - Intel(R) VTune(TM) Profiler: * - Does continue to record when new threads are started. * . * - Other effects: @@ -355,35 +321,143 @@ void ITTAPI __itt_resume(void); /** @brief Detach collection */ void ITTAPI __itt_detach(void); +/** + * @enum __itt_collection_scope + * @brief Enumerator for collection scopes + */ +typedef enum { + __itt_collection_scope_host = 1 << 0, + __itt_collection_scope_offload = 1 << 1, + __itt_collection_scope_all = 0x7FFFFFFF +} __itt_collection_scope; + +/** @brief Pause scoped collection */ +void ITTAPI __itt_pause_scoped(__itt_collection_scope); +/** @brief Resume scoped collection */ +void ITTAPI __itt_resume_scoped(__itt_collection_scope); + /** @cond exclude_from_documentation */ #ifndef INTEL_NO_MACRO_BODY #ifndef INTEL_NO_ITTNOTIFY_API -ITT_STUBV(ITTAPI, void, pause, (void)) -ITT_STUBV(ITTAPI, void, resume, (void)) -ITT_STUBV(ITTAPI, void, detach, (void)) -#define __itt_pause ITTNOTIFY_VOID(pause) -#define __itt_pause_ptr ITTNOTIFY_NAME(pause) -#define __itt_resume ITTNOTIFY_VOID(resume) -#define __itt_resume_ptr ITTNOTIFY_NAME(resume) -#define __itt_detach ITTNOTIFY_VOID(detach) -#define __itt_detach_ptr ITTNOTIFY_NAME(detach) +ITT_STUBV(ITTAPI, void, pause, (void)) +ITT_STUBV(ITTAPI, void, pause_scoped, (__itt_collection_scope)) +ITT_STUBV(ITTAPI, void, resume, (void)) +ITT_STUBV(ITTAPI, void, resume_scoped, (__itt_collection_scope)) +ITT_STUBV(ITTAPI, void, detach, (void)) +#define __itt_pause ITTNOTIFY_VOID(pause) +#define __itt_pause_ptr ITTNOTIFY_NAME(pause) +#define __itt_pause_scoped ITTNOTIFY_VOID(pause_scoped) +#define __itt_pause_scoped_ptr ITTNOTIFY_NAME(pause_scoped) +#define __itt_resume ITTNOTIFY_VOID(resume) +#define __itt_resume_ptr ITTNOTIFY_NAME(resume) +#define __itt_resume_scoped ITTNOTIFY_VOID(resume_scoped) +#define __itt_resume_scoped_ptr ITTNOTIFY_NAME(resume_scoped) +#define __itt_detach ITTNOTIFY_VOID(detach) +#define __itt_detach_ptr ITTNOTIFY_NAME(detach) #else /* INTEL_NO_ITTNOTIFY_API */ #define __itt_pause() -#define __itt_pause_ptr 0 +#define __itt_pause_ptr 0 +#define __itt_pause_scoped(scope) +#define __itt_pause_scoped_ptr 0 #define __itt_resume() -#define __itt_resume_ptr 0 +#define __itt_resume_ptr 0 +#define __itt_resume_scoped(scope) +#define __itt_resume_scoped_ptr 0 #define __itt_detach() -#define __itt_detach_ptr 0 +#define __itt_detach_ptr 0 #endif /* INTEL_NO_ITTNOTIFY_API */ #else /* INTEL_NO_MACRO_BODY */ -#define __itt_pause_ptr 0 -#define __itt_resume_ptr 0 -#define __itt_detach_ptr 0 +#define __itt_pause_ptr 0 +#define __itt_pause_scoped_ptr 0 +#define __itt_resume_ptr 0 +#define __itt_resume_scoped_ptr 0 +#define __itt_detach_ptr 0 #endif /* INTEL_NO_MACRO_BODY */ /** @endcond */ /** @} control group */ /** @endcond */ +/** + * @defgroup Intel Processor Trace control + * API from this group provides control over collection and analysis of Intel Processor Trace (Intel PT) data + * Information about Intel Processor Trace technology can be found here (Volume 3 chapter 35): + * https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf + * Use this API to mark particular code regions for loading detailed performance statistics. + * This mode makes your analysis faster and more accurate. + * @{ +*/ +typedef unsigned char __itt_pt_region; + +/** + * @brief function saves a region name marked with Intel PT API and returns a region id. + * Only 7 names can be registered. Attempts to register more names will be ignored and a region id with auto names will be returned. + * For automatic naming of regions pass NULL as function parameter +*/ +#if ITT_PLATFORM==ITT_PLATFORM_WIN +__itt_pt_region ITTAPI __itt_pt_region_createA(const char *name); +__itt_pt_region ITTAPI __itt_pt_region_createW(const wchar_t *name); +#if defined(UNICODE) || defined(_UNICODE) +# define __itt_pt_region_create __itt_pt_region_createW +#else /* UNICODE */ +# define __itt_pt_region_create __itt_pt_region_createA +#endif /* UNICODE */ +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +__itt_pt_region ITTAPI __itt_pt_region_create(const char *name); +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ + +/** @cond exclude_from_documentation */ +#ifndef INTEL_NO_MACRO_BODY +#ifndef INTEL_NO_ITTNOTIFY_API +#if ITT_PLATFORM==ITT_PLATFORM_WIN +ITT_STUB(ITTAPI, __itt_pt_region, pt_region_createA, (const char *name)) +ITT_STUB(ITTAPI, __itt_pt_region, pt_region_createW, (const wchar_t *name)) +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +ITT_STUB(ITTAPI, __itt_pt_region, pt_region_create, (const char *name)) +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#if ITT_PLATFORM==ITT_PLATFORM_WIN +#define __itt_pt_region_createA ITTNOTIFY_DATA(pt_region_createA) +#define __itt_pt_region_createA_ptr ITTNOTIFY_NAME(pt_region_createA) +#define __itt_pt_region_createW ITTNOTIFY_DATA(pt_region_createW) +#define __itt_pt_region_createW_ptr ITTNOTIFY_NAME(pt_region_createW) +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#define __itt_pt_region_create ITTNOTIFY_DATA(pt_region_create) +#define __itt_pt_region_create_ptr ITTNOTIFY_NAME(pt_region_create) +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#else /* INTEL_NO_ITTNOTIFY_API */ +#if ITT_PLATFORM==ITT_PLATFORM_WIN +#define __itt_pt_region_createA(name) (__itt_pt_region)0 +#define __itt_pt_region_createA_ptr 0 +#define __itt_pt_region_createW(name) (__itt_pt_region)0 +#define __itt_pt_region_createW_ptr 0 +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#define __itt_pt_region_create(name) (__itt_pt_region)0 +#define __itt_pt_region_create_ptr 0 +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#endif /* INTEL_NO_ITTNOTIFY_API */ +#else /* INTEL_NO_MACRO_BODY */ +#if ITT_PLATFORM==ITT_PLATFORM_WIN +#define __itt_pt_region_createA_ptr 0 +#define __itt_pt_region_createW_ptr 0 +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#define __itt_pt_region_create_ptr 0 +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#endif /* INTEL_NO_MACRO_BODY */ +/** @endcond */ + +/** + * @brief function contains a special code pattern identified on the post-processing stage and + * marks the beginning of a code region targeted for Intel PT analysis + * @param[in] region - region id, 0 <= region < 8 +*/ +void __itt_mark_pt_region_begin(__itt_pt_region region); +/** + * @brief function contains a special code pattern identified on the post-processing stage and + * marks the end of a code region targeted for Intel PT analysis + * @param[in] region - region id, 0 <= region < 8 +*/ +void __itt_mark_pt_region_end(__itt_pt_region region); +/** @} Intel PT control group*/ + /** * @defgroup threads Threads * @ingroup public @@ -541,14 +615,26 @@ ITT_STUBV(ITTAPI, void, suppress_pop, (void)) /** @endcond */ /** - * @enum __itt_model_disable - * @brief Enumerator for the disable methods + * @enum __itt_suppress_mode + * @brief Enumerator for the suppressing modes */ typedef enum __itt_suppress_mode { __itt_unsuppress_range, __itt_suppress_range } __itt_suppress_mode_t; +/** + * @enum __itt_collection_state + * @brief Enumerator for collection state. + */ +typedef enum { + __itt_collection_uninitialized = 0, /* uninitialized */ + __itt_collection_init_fail = 1, /* failed to init */ + __itt_collection_collector_absent = 2, /* non work state collector is absent */ + __itt_collection_collector_exists = 3, /* work state collector exists */ + __itt_collection_init_successful = 4 /* success to init */ +} __itt_collection_state; + /** * @brief Mark a range of memory for error suppression or unsuppression for error types included in mask */ @@ -1496,7 +1582,7 @@ ITT_STUBV(ITTAPI, void, heap_allocate_end, (__itt_heap_function h, void** addr, /** @endcond */ /** - * @brief Record an free begin occurrence. + * @brief Record a free begin occurrence. */ void ITTAPI __itt_heap_free_begin(__itt_heap_function h, void* addr); @@ -1516,7 +1602,7 @@ ITT_STUBV(ITTAPI, void, heap_free_begin, (__itt_heap_function h, void* addr)) /** @endcond */ /** - * @brief Record an free end occurrence. + * @brief Record a free end occurrence. */ void ITTAPI __itt_heap_free_end(__itt_heap_function h, void* addr); @@ -1536,7 +1622,7 @@ ITT_STUBV(ITTAPI, void, heap_free_end, (__itt_heap_function h, void* addr)) /** @endcond */ /** - * @brief Record an reallocation begin occurrence. + * @brief Record a reallocation begin occurrence. */ void ITTAPI __itt_heap_reallocate_begin(__itt_heap_function h, void* addr, size_t new_size, int initialized); @@ -1556,7 +1642,7 @@ ITT_STUBV(ITTAPI, void, heap_reallocate_begin, (__itt_heap_function h, void* add /** @endcond */ /** - * @brief Record an reallocation end occurrence. + * @brief Record a reallocation end occurrence. */ void ITTAPI __itt_heap_reallocate_end(__itt_heap_function h, void* addr, void** new_addr, size_t new_size, int initialized); @@ -2692,7 +2778,7 @@ ITT_STUB(ITTAPI, __itt_clock_domain*, clock_domain_create, (__itt_get_clock_info /** * @ingroup clockdomains - * @brief Recalculate clock domains frequences and clock base timestamps. + * @brief Recalculate clock domains frequencies and clock base timestamps. */ void ITTAPI __itt_clock_domain_reset(void); @@ -3597,11 +3683,12 @@ ITT_STUBV(ITTAPI, void, enable_attach, (void)) /** @endcond */ /** - * @brief Module load info - * This API is used to report necessary information in case of module relocation - * @param[in] start_addr - relocated module start address - * @param[in] end_addr - relocated module end address - * @param[in] path - file system path to the module + * @brief Module load notification + * This API is used to report necessary information in case of bypassing default system loader. + * Notification should be done immidiatelly after this module is loaded to process memory. + * @param[in] start_addr - module start address + * @param[in] end_addr - module end address + * @param[in] path - file system full path to the module */ #if ITT_PLATFORM==ITT_PLATFORM_WIN void ITTAPI __itt_module_loadA(void *start_addr, void *end_addr, const char *path); @@ -3656,7 +3743,462 @@ ITT_STUB(ITTAPI, void, module_load, (void *start_addr, void *end_addr, const ch #endif /* INTEL_NO_MACRO_BODY */ /** @endcond */ +/** + * @brief Report module unload + * This API is used to report necessary information in case of bypassing default system loader. + * Notification should be done just before the module is unloaded from process memory. + * @param[in] addr - base address of loaded module + */ +void ITTAPI __itt_module_unload(void *addr); +/** @cond exclude_from_documentation */ +#ifndef INTEL_NO_MACRO_BODY +#ifndef INTEL_NO_ITTNOTIFY_API +ITT_STUBV(ITTAPI, void, module_unload, (void *addr)) +#define __itt_module_unload ITTNOTIFY_VOID(module_unload) +#define __itt_module_unload_ptr ITTNOTIFY_NAME(module_unload) +#else /* INTEL_NO_ITTNOTIFY_API */ +#define __itt_module_unload(addr) +#define __itt_module_unload_ptr 0 +#endif /* INTEL_NO_ITTNOTIFY_API */ +#else /* INTEL_NO_MACRO_BODY */ +#define __itt_module_unload_ptr 0 +#endif /* INTEL_NO_MACRO_BODY */ +/** @endcond */ + +/** @cond exclude_from_documentation */ +typedef enum +{ + __itt_module_type_unknown = 0, + __itt_module_type_elf, + __itt_module_type_coff +} __itt_module_type; +/** @endcond */ + +/** @cond exclude_from_documentation */ +typedef enum +{ + itt_section_type_unknown, + itt_section_type_bss, /* notifies that the section contains uninitialized data. These are the relevant section types and the modules that contain them: + * ELF module: SHT_NOBITS section type + * COFF module: IMAGE_SCN_CNT_UNINITIALIZED_DATA section type + */ + itt_section_type_data, /* notifies that section contains initialized data. These are the relevant section types and the modules that contain them: + * ELF module: SHT_PROGBITS section type + * COFF module: IMAGE_SCN_CNT_INITIALIZED_DATA section type + */ + itt_section_type_text /* notifies that the section contains executable code. These are the relevant section types and the modules that contain them: + * ELF module: SHT_PROGBITS section type + * COFF module: IMAGE_SCN_CNT_CODE section type + */ +} __itt_section_type; +/** @endcond */ + +/** + * @hideinitializer + * @brief bit-mask, detects a section attribute that indicates whether a section can be executed as code: + * These are the relevant section attributes and the modules that contain them: + * ELF module: PF_X section attribute + * COFF module: IMAGE_SCN_MEM_EXECUTE attribute + */ +#define __itt_section_exec 0x20000000 + +/** + * @hideinitializer + * @brief bit-mask, detects a section attribute that indicates whether a section can be read. + * These are the relevant section attributes and the modules that contain them: + * ELF module: PF_R attribute + * COFF module: IMAGE_SCN_MEM_READ attribute + */ +#define __itt_section_read 0x40000000 + +/** + * @hideinitializer + * @brief bit-mask, detects a section attribute that indicates whether a section can be written to. + * These are the relevant section attributes and the modules that contain them: + * ELF module: PF_W attribute + * COFF module: IMAGE_SCN_MEM_WRITE attribute + */ +#define __itt_section_write 0x80000000 + +/** @cond exclude_from_documentation */ +#pragma pack(push, 8) + +typedef struct ___itt_section_info +{ + const char* name; /*!< Section name in UTF8 */ + __itt_section_type type; /*!< Section content and semantics description */ + size_t flags; /*!< Section bit flags that describe attributes using bit mask + * Zero if disabled, non-zero if enabled + */ + void* start_addr; /*!< Section load(relocated) start address */ + size_t size; /*!< Section file offset */ + size_t file_offset; /*!< Section size */ +} __itt_section_info; + +#pragma pack(pop) +/** @endcond */ + +/** @cond exclude_from_documentation */ +#pragma pack(push, 8) + +typedef struct ___itt_module_object +{ + unsigned int version; /*!< API version*/ + __itt_id module_id; /*!< Unique identifier. This is unchanged for sections that belong to the same module */ + __itt_module_type module_type; /*!< Binary module format */ + const char* module_name; /*!< Unique module name or path to module in UTF8 + * Contains module name when module_bufer and module_size exist + * Contains module path when module_bufer and module_size absent + * module_name remains the same for the certain module_id + */ + void* module_buffer; /*!< Module buffer content */ + size_t module_size; /*!< Module buffer size */ + /*!< If module_buffer and module_size exist, the binary module is dumped onto the system. + * If module_buffer and module_size do not exist, + * the binary module exists on the system already. + * The module_name parameter contains the path to the module. + */ + __itt_section_info* section_array; /*!< Reference to section information */ + size_t section_number; +} __itt_module_object; + +#pragma pack(pop) +/** @endcond */ + +/** + * @brief Load module content and its loaded(relocated) sections. + * This API is useful to save a module, or specify its location on the system and report information about loaded sections. + * The target module is saved on the system if module buffer content and size are available. + * If module buffer content and size are unavailable, the module name contains the path to the existing binary module. + * @param[in] module_obj - provides module and section information, along with unique module identifiers (name,module ID) + * which bind the binary module to particular sections. + */ +void ITTAPI __itt_module_load_with_sections(__itt_module_object* module_obj); + +/** @cond exclude_from_documentation */ +#ifndef INTEL_NO_MACRO_BODY +#ifndef INTEL_NO_ITTNOTIFY_API +ITT_STUBV(ITTAPI, void, module_load_with_sections, (__itt_module_object* module_obj)) +#define __itt_module_load_with_sections ITTNOTIFY_VOID(module_load_with_sections) +#define __itt_module_load_with_sections_ptr ITTNOTIFY_NAME(module_load_with_sections) +#else /* INTEL_NO_ITTNOTIFY_API */ +#define __itt_module_load_with_sections(module_obj) +#define __itt_module_load_with_sections_ptr 0 +#endif /* INTEL_NO_ITTNOTIFY_API */ +#else /* INTEL_NO_MACRO_BODY */ +#define __itt_module_load_with_sections_ptr 0 +#endif /* INTEL_NO_MACRO_BODY */ +/** @endcond */ + +/** + * @brief Unload a module and its loaded(relocated) sections. + * This API notifies that the module and its sections were unloaded. + * @param[in] module_obj - provides module and sections information, along with unique module identifiers (name,module ID) + * which bind the binary module to particular sections. + */ +void ITTAPI __itt_module_unload_with_sections(__itt_module_object* module_obj); + +/** @cond exclude_from_documentation */ +#ifndef INTEL_NO_MACRO_BODY +#ifndef INTEL_NO_ITTNOTIFY_API +ITT_STUBV(ITTAPI, void, module_unload_with_sections, (__itt_module_object* module_obj)) +#define __itt_module_unload_with_sections ITTNOTIFY_VOID(module_unload_with_sections) +#define __itt_module_unload_with_sections_ptr ITTNOTIFY_NAME(module_unload_with_sections) +#else /* INTEL_NO_ITTNOTIFY_API */ +#define __itt_module_unload_with_sections(module_obj) +#define __itt_module_unload_with_sections_ptr 0 +#endif /* INTEL_NO_ITTNOTIFY_API */ +#else /* INTEL_NO_MACRO_BODY */ +#define __itt_module_unload_with_sections_ptr 0 +#endif /* INTEL_NO_MACRO_BODY */ +/** @endcond */ + +/** @cond exclude_from_documentation */ +#pragma pack(push, 8) + +typedef struct ___itt_histogram +{ + const __itt_domain* domain; /*!< Domain of the histogram*/ + const char* nameA; /*!< Name of the histogram */ +#if defined(UNICODE) || defined(_UNICODE) + const wchar_t* nameW; +#else /* UNICODE || _UNICODE */ + void* nameW; +#endif /* UNICODE || _UNICODE */ + __itt_metadata_type x_type; /*!< Type of the histogram X axis */ + __itt_metadata_type y_type; /*!< Type of the histogram Y axis */ + int extra1; /*!< Reserved to the runtime */ + void* extra2; /*!< Reserved to the runtime */ + struct ___itt_histogram* next; +} __itt_histogram; + +#pragma pack(pop) +/** @endcond */ + +/** + * @brief Create a typed histogram instance with given name/domain. + * @param[in] domain The domain controlling the call. + * @param[in] name The name of the histogram. + * @param[in] x_type The type of the X axis in histogram (may be 0 to calculate batch statistics). + * @param[in] y_type The type of the Y axis in histogram. +*/ +#if ITT_PLATFORM==ITT_PLATFORM_WIN +__itt_histogram* ITTAPI __itt_histogram_createA(const __itt_domain* domain, const char* name, __itt_metadata_type x_type, __itt_metadata_type y_type); +__itt_histogram* ITTAPI __itt_histogram_createW(const __itt_domain* domain, const wchar_t* name, __itt_metadata_type x_type, __itt_metadata_type y_type); +#if defined(UNICODE) || defined(_UNICODE) +# define __itt_histogram_create __itt_histogram_createW +# define __itt_histogram_create_ptr __itt_histogram_createW_ptr +#else /* UNICODE */ +# define __itt_histogram_create __itt_histogram_createA +# define __itt_histogram_create_ptr __itt_histogram_createA_ptr +#endif /* UNICODE */ +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +__itt_histogram* ITTAPI __itt_histogram_create(const __itt_domain* domain, const char* name, __itt_metadata_type x_type, __itt_metadata_type y_type); +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ + +/** @cond exclude_from_documentation */ +#ifndef INTEL_NO_MACRO_BODY +#ifndef INTEL_NO_ITTNOTIFY_API +#if ITT_PLATFORM==ITT_PLATFORM_WIN +ITT_STUB(ITTAPI, __itt_histogram*, histogram_createA, (const __itt_domain* domain, const char* name, __itt_metadata_type x_type, __itt_metadata_type y_type)) +ITT_STUB(ITTAPI, __itt_histogram*, histogram_createW, (const __itt_domain* domain, const wchar_t* name, __itt_metadata_type x_type, __itt_metadata_type y_type)) +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +ITT_STUB(ITTAPI, __itt_histogram*, histogram_create, (const __itt_domain* domain, const char* name, __itt_metadata_type x_type, __itt_metadata_type y_type)) +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#if ITT_PLATFORM==ITT_PLATFORM_WIN +#define __itt_histogram_createA ITTNOTIFY_DATA(histogram_createA) +#define __itt_histogram_createA_ptr ITTNOTIFY_NAME(histogram_createA) +#define __itt_histogram_createW ITTNOTIFY_DATA(histogram_createW) +#define __itt_histogram_createW_ptr ITTNOTIFY_NAME(histogram_createW) +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#define __itt_histogram_create ITTNOTIFY_DATA(histogram_create) +#define __itt_histogram_create_ptr ITTNOTIFY_NAME(histogram_create) +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#else /* INTEL_NO_ITTNOTIFY_API */ +#if ITT_PLATFORM==ITT_PLATFORM_WIN +#define __itt_histogram_createA(domain, name, x_type, y_type) (__itt_histogram*)0 +#define __itt_histogram_createA_ptr 0 +#define __itt_histogram_createW(domain, name, x_type, y_type) (__itt_histogram*)0 +#define __itt_histogram_createW_ptr 0 +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#define __itt_histogram_create(domain, name, x_type, y_type) (__itt_histogram*)0 +#define __itt_histogram_create_ptr 0 +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#endif /* INTEL_NO_ITTNOTIFY_API */ +#else /* INTEL_NO_MACRO_BODY */ +#if ITT_PLATFORM==ITT_PLATFORM_WIN +#define __itt_histogram_createA_ptr 0 +#define __itt_histogram_createW_ptr 0 +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#define __itt_histogram_create_ptr 0 +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#endif /* INTEL_NO_MACRO_BODY */ +/** @endcond */ + +/** + * @brief Submit statistics for a histogram instance. + * @param[in] hist Pointer to the histogram instance to which the histogram statistic is to be dumped. + * @param[in] length The number of elements in dumped axis data array. + * @param[in] x_data The X axis dumped data itself (may be NULL to calculate batch statistics). + * @param[in] y_data The Y axis dumped data itself. +*/ +void ITTAPI __itt_histogram_submit(__itt_histogram* hist, size_t length, void* x_data, void* y_data); + +/** @cond exclude_from_documentation */ +#ifndef INTEL_NO_MACRO_BODY +#ifndef INTEL_NO_ITTNOTIFY_API +ITT_STUBV(ITTAPI, void, histogram_submit, (__itt_histogram* hist, size_t length, void* x_data, void* y_data)) +#define __itt_histogram_submit ITTNOTIFY_VOID(histogram_submit) +#define __itt_histogram_submit_ptr ITTNOTIFY_NAME(histogram_submit) +#else /* INTEL_NO_ITTNOTIFY_API */ +#define __itt_histogram_submit(hist, length, x_data, y_data) +#define __itt_histogram_submit_ptr 0 +#endif /* INTEL_NO_ITTNOTIFY_API */ +#else /* INTEL_NO_MACRO_BODY */ +#define __itt_histogram_submit_ptr 0 +#endif /* INTEL_NO_MACRO_BODY */ + +/** +* @brief function allows to obtain the current collection state at the moment +* @return collection state as a enum __itt_collection_state +*/ +__itt_collection_state __itt_get_collection_state(void); + +/** +* @brief function releases resources allocated by ITT API static part +* this API should be called from the library destructor +* @return void +*/ +void __itt_release_resources(void); +/** @endcond */ + +/** + * @brief Create a typed counter with given domain pointer, string name and counter type +*/ +#if ITT_PLATFORM==ITT_PLATFORM_WIN +__itt_counter ITTAPI __itt_counter_createA_v3(const __itt_domain* domain, const char* name, __itt_metadata_type type); +__itt_counter ITTAPI __itt_counter_createW_v3(const __itt_domain* domain, const wchar_t* name, __itt_metadata_type type); +#if defined(UNICODE) || defined(_UNICODE) +# define __itt_counter_create_v3 __itt_counter_createW_v3 +# define __itt_counter_create_v3_ptr __itt_counter_createW_v3_ptr +#else /* UNICODE */ +# define __itt_counter_create_v3 __itt_counter_createA_v3 +# define __itt_counter_create_v3_ptr __itt_counter_createA_v3_ptr +#endif /* UNICODE */ +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +__itt_counter ITTAPI __itt_counter_create_v3(const __itt_domain* domain, const char* name, __itt_metadata_type type); +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ + +#ifndef INTEL_NO_MACRO_BODY +#ifndef INTEL_NO_ITTNOTIFY_API +#if ITT_PLATFORM==ITT_PLATFORM_WIN +ITT_STUB(ITTAPI, __itt_counter, counter_createA_v3, (const __itt_domain* domain, const char* name, __itt_metadata_type type)) +ITT_STUB(ITTAPI, __itt_counter, counter_createW_v3, (const __itt_domain* domain, const wchar_t* name, __itt_metadata_type type)) +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +ITT_STUB(ITTAPI, __itt_counter, counter_create_v3, (const __itt_domain* domain, const char* name, __itt_metadata_type type)) +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#if ITT_PLATFORM==ITT_PLATFORM_WIN +#define __itt_counter_createA_v3 ITTNOTIFY_DATA(counter_createA_v3) +#define __itt_counter_createA_v3_ptr ITTNOTIFY_NAME(counter_createA_v3) +#define __itt_counter_createW_v3 ITTNOTIFY_DATA(counter_createW_v3) +#define __itt_counter_createW_v3_ptr ITTNOTIFY_NAME(counter_createW_v3) +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#define __itt_counter_create_v3 ITTNOTIFY_DATA(counter_create_v3) +#define __itt_counter_create_v3_ptr ITTNOTIFY_NAME(counter_create_v3) +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#else /* INTEL_NO_ITTNOTIFY_API */ +#if ITT_PLATFORM==ITT_PLATFORM_WIN +#define __itt_counter_createA_v3(domain, name, type) (__itt_counter)0 +#define __itt_counter_createA_v3_ptr 0 +#define __itt_counter_createW_v3(domain, name, type) (__itt_counter)0 +#define __itt_counter_create_typedW_ptr 0 +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#define __itt_counter_create_v3(domain, name, type) (__itt_counter)0 +#define __itt_counter_create_v3_ptr 0 +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#endif /* INTEL_NO_ITTNOTIFY_API */ +#else /* INTEL_NO_MACRO_BODY */ +#if ITT_PLATFORM==ITT_PLATFORM_WIN +#define __itt_counter_createA_v3_ptr 0 +#define __itt_counter_createW_v3_ptr 0 +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#define __itt_counter_create_v3_ptr 0 +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +#endif /* INTEL_NO_MACRO_BODY */ +/** @endcond */ + +/** + * @brief Set the counter value api + */ +void ITTAPI __itt_counter_set_value_v3(__itt_counter counter, void *value_ptr); + +#ifndef INTEL_NO_MACRO_BODY +#ifndef INTEL_NO_ITTNOTIFY_API +ITT_STUBV(ITTAPI, void, counter_set_value_v3, (__itt_counter counter, void *value_ptr)) +#define __itt_counter_set_value_v3 ITTNOTIFY_VOID(counter_set_value_v3) +#define __itt_counter_set_value_v3_ptr ITTNOTIFY_NAME(counter_set_value_v3) +#else /* INTEL_NO_ITTNOTIFY_API */ +#define __itt_counter_set_value_v3(counter, value_ptr) +#define __itt_counter_set_value_v3_ptr 0 +#endif /* INTEL_NO_ITTNOTIFY_API */ +#else /* INTEL_NO_MACRO_BODY */ +#define __itt_counter_set_value_v3_ptr 0 +#endif /* INTEL_NO_MACRO_BODY */ +/** @endcond */ + +/** + * @brief describes the type of context metadata +*/ +typedef enum { + __itt_context_unknown = 0, /*!< Undefined type */ + __itt_context_nameA, /*!< ASCII string char* type */ + __itt_context_nameW, /*!< Unicode string wchar_t* type */ + __itt_context_deviceA, /*!< ASCII string char* type */ + __itt_context_deviceW, /*!< Unicode string wchar_t* type */ + __itt_context_unitsA, /*!< ASCII string char* type */ + __itt_context_unitsW, /*!< Unicode string wchar_t* type */ + __itt_context_pci_addrA, /*!< ASCII string char* type */ + __itt_context_pci_addrW, /*!< Unicode string wchar_t* type */ + __itt_context_tid, /*!< Unsigned 64-bit integer type */ + __itt_context_max_val, /*!< Unsigned 64-bit integer type */ + __itt_context_bandwidth_flag, /*!< Unsigned 64-bit integer type */ + __itt_context_latency_flag, /*!< Unsigned 64-bit integer type */ + __itt_context_occupancy_flag, /*!< Unsigned 64-bit integer type */ + __itt_context_on_thread_flag, /*!< Unsigned 64-bit integer type */ + __itt_context_is_abs_val_flag, /*!< Unsigned 64-bit integer type */ + __itt_context_cpu_instructions_flag, /*!< Unsigned 64-bit integer type */ + __itt_context_cpu_cycles_flag /*!< Unsigned 64-bit integer type */ +} __itt_context_type; + +#if defined(UNICODE) || defined(_UNICODE) +# define __itt_context_name __itt_context_nameW +# define __itt_context_device __itt_context_deviceW +# define __itt_context_units __itt_context_unitsW +# define __itt_context_pci_addr __itt_context_pci_addrW +#else /* UNICODE || _UNICODE */ +# define __itt_context_name __itt_context_nameA +# define __itt_context_device __itt_context_deviceA +# define __itt_context_units __itt_context_unitsA +# define __itt_context_pci_addr __itt_context_pci_addrA +#endif /* UNICODE || _UNICODE */ + +/** @cond exclude_from_documentation */ +#pragma pack(push, 8) + +typedef struct ___itt_context_metadata +{ + __itt_context_type type; /*!< Type of the context metadata value */ + void* value; /*!< Pointer to context metadata value itself */ +} __itt_context_metadata; + +#pragma pack(pop) +/** @endcond */ + +/** @cond exclude_from_documentation */ +#pragma pack(push, 8) + +typedef struct ___itt_counter_metadata +{ + __itt_counter counter; /*!< Associated context metadata counter */ + __itt_context_type type; /*!< Type of the context metadata value */ + const char* str_valueA; /*!< String context metadata value */ +#if defined(UNICODE) || defined(_UNICODE) + const wchar_t* str_valueW; +#else /* UNICODE || _UNICODE */ + void* str_valueW; +#endif /* UNICODE || _UNICODE */ + unsigned long long value; /*!< Numeric context metadata value */ + int extra1; /*!< Reserved to the runtime */ + void* extra2; /*!< Reserved to the runtime */ + struct ___itt_counter_metadata* next; +} __itt_counter_metadata; + +#pragma pack(pop) +/** @endcond */ + +/** + * @brief Bind context metadata to counter instance + * @param[in] counter Pointer to the counter instance to which the context metadata is to be associated. + * @param[in] length The number of elements in context metadata array. + * @param[in] metadata The context metadata itself. +*/ +void ITTAPI __itt_bind_context_metadata_to_counter(__itt_counter counter, size_t length, __itt_context_metadata* metadata); + +/** @cond exclude_from_documentation */ +#ifndef INTEL_NO_MACRO_BODY +#ifndef INTEL_NO_ITTNOTIFY_API +ITT_STUBV(ITTAPI, void, bind_context_metadata_to_counter, (__itt_counter counter, size_t length, __itt_context_metadata* metadata)) +#define __itt_bind_context_metadata_to_counter ITTNOTIFY_VOID(bind_context_metadata_to_counter) +#define __itt_bind_context_metadata_to_counter_ptr ITTNOTIFY_NAME(bind_context_metadata_to_counter) +#else /* INTEL_NO_ITTNOTIFY_API */ +#define __itt_bind_context_metadata_to_counter(counter, length, metadata) +#define __itt_bind_context_metadata_to_counter_ptr 0 +#endif /* INTEL_NO_ITTNOTIFY_API */ +#else /* INTEL_NO_MACRO_BODY */ +#define __itt_bind_context_metadata_to_counter_ptr 0 +#endif /* INTEL_NO_MACRO_BODY */ +/** @endcond */ #ifdef __cplusplus } @@ -4005,7 +4547,7 @@ ITT_STUB(ITTAPI, __itt_caller, stack_caller_create, (void)) /** @endcond */ /** - * @brief Destroy the inforamtion about stitch point identified by the pointer previously returned by __itt_stack_caller_create() + * @brief Destroy the information about stitch point identified by the pointer previously returned by __itt_stack_caller_create() */ void ITTAPI __itt_stack_caller_destroy(__itt_caller id); diff --git a/3rdparty/ittnotify/include/jitprofiling.h b/3rdparty/ittnotify/include/jitprofiling.h index 3e166c04d4..5a88359485 100644 --- a/3rdparty/ittnotify/include/jitprofiling.h +++ b/3rdparty/ittnotify/include/jitprofiling.h @@ -1,60 +1,8 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. +/* + Copyright (C) 2005-2019 Intel Corporation - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +*/ #ifndef __JITPROFILING_H__ #define __JITPROFILING_H__ @@ -66,7 +14,7 @@ * generated code that can be used by performance tools. The user inserts * calls in the code generator to report information before JIT-compiled * code goes to execution. This information is collected at runtime and used - * by tools like Intel(R) VTune(TM) Amplifier to display performance metrics + * by tools like Intel(R) VTune(TM) Profiler to display performance metrics * associated with JIT-compiled code. * * These APIs can be used to\n @@ -97,16 +45,16 @@ * * Expected behavior: * * If any iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event overwrites an * already reported method, then such a method becomes invalid and its - * memory region is treated as unloaded. VTune Amplifier displays the metrics + * memory region is treated as unloaded. VTune Profiler displays the metrics * collected by the method until it is overwritten. * * If supplied line number information contains multiple source lines for - * the same assembly instruction (code location), then VTune Amplifier picks up + * the same assembly instruction (code location), then VTune Profiler picks up * the first line number. * * Dynamically generated code can be associated with a module name. * Use the iJIT_Method_Load_V2 structure.\n * Clarification of some cases: * * If you register a function with the same method ID multiple times, - * specifying different module names, then the VTune Amplifier picks up + * specifying different module names, then the VTune Profiler picks up * the module name registered first. If you want to distinguish the same * function between different JIT engines, supply different method IDs for * each function. Other symbolic information (for example, source file) @@ -143,18 +91,18 @@ * belonging to the same method. Symbolic information (method name, * source file name) will be taken from the first notification, and all * subsequent notifications with the same method ID will be processed - * only for line number table information. So, the VTune Amplifier will map + * only for line number table information. So, the VTune Profiler will map * samples to a source line using the line number table from the current * notification while taking the source file name from the very first one.\n * Clarification of some cases:\n * * If you register a second code region with a different source file * name and the same method ID, then this information will be saved and * will not be considered as an extension of the first code region, but - * VTune Amplifier will use the source file of the first code region and map + * VTune Profiler will use the source file of the first code region and map * performance metrics incorrectly. * * If you register a second code region with the same source file as * for the first region and the same method ID, then the source file will be - * discarded but VTune Amplifier will map metrics to the source file correctly. + * discarded but VTune Profiler will map metrics to the source file correctly. * * If you register a second code region with a null source file and * the same method ID, then provided line number info will be associated * with the source file of the first code region. @@ -293,7 +241,7 @@ typedef enum _iJIT_IsProfilingActiveFlags * @brief Description of a single entry in the line number information of a code region. * @details A table of line number entries gives information about how the reported code region * is mapped to source file. - * Intel(R) VTune(TM) Amplifier uses line number information to attribute + * Intel(R) VTune(TM) Profiler uses line number information to attribute * the samples (virtual address) to a line number. \n * It is acceptable to report different code addresses for the same source line: * @code @@ -304,7 +252,7 @@ typedef enum _iJIT_IsProfilingActiveFlags * 18 1 * 21 30 * - * VTune Amplifier constructs the following table using the client data + * VTune Profiler constructs the following table using the client data * * Code subrange Line number * 0-1 2 @@ -428,7 +376,7 @@ typedef struct _iJIT_Method_Load_V2 char* module_name; /**<\brief Module name. Can be NULL. The module name can be useful for distinguishing among - different JIT engines. VTune Amplifier will display + different JIT engines. VTune Profiler will display reported methods grouped by specific module. */ } *piJIT_Method_Load_V2, iJIT_Method_Load_V2; @@ -480,7 +428,7 @@ typedef struct _iJIT_Method_Load_V3 char* module_name; /**<\brief Module name. Can be NULL. * The module name can be useful for distinguishing among - * different JIT engines. VTune Amplifier will display + * different JIT engines. VTune Profiler will display * reported methods grouped by specific module. */ iJIT_CodeArchitecture module_arch; /**<\brief Architecture of the method's code region. @@ -490,9 +438,9 @@ typedef struct _iJIT_Method_Load_V3 * engine generates 64-bit code. * * If JIT engine reports both 32-bit and 64-bit types - * of methods then VTune Amplifier splits the methods + * of methods then VTune Profiler splits the methods * with the same module name but with different - * architectures in two different modules. VTune Amplifier + * architectures in two different modules. VTune Profiler * modifies the original name provided with a 64-bit method * version by ending it with '(64)' */ @@ -561,9 +509,9 @@ typedef enum _iJIT_SegmentType iJIT_CT_CODE, /**<\brief Executable code. */ iJIT_CT_DATA, /**<\brief Data (not executable code). - * VTune Amplifier uses the format string + * VTune Profiler uses the format string * (see iJIT_Method_Update) to represent - * this data in the VTune Amplifier GUI */ + * this data in the VTune Profiler GUI */ iJIT_CT_KEEP, /**<\brief Use the previous markup for the trace. * Can be used for the following @@ -580,11 +528,11 @@ typedef enum _iJIT_SegmentType * structure to describe the update of the content within a JIT-compiled method, * use iJVM_EVENT_TYPE_METHOD_UPDATE_V2 as an event type to report it. * - * On the first Update event, VTune Amplifier copies the original code range reported by + * On the first Update event, VTune Profiler copies the original code range reported by * the iJVM_EVENT_TYPE_METHOD_LOAD event, then modifies it with the supplied bytes and - * adds the modified range to the original method. For next update events, VTune Amplifier + * adds the modified range to the original method. For next update events, VTune Profiler * does the same but it uses the latest modified version of a code region for update. - * Eventually, VTune Amplifier GUI displays multiple code ranges for the method reported by + * Eventually, VTune Profiler GUI displays multiple code ranges for the method reported by * the iJVM_EVENT_TYPE_METHOD_LOAD event. * Notes: * - Multiple update events with different types for the same trace are allowed @@ -673,7 +621,7 @@ iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive(void); * @brief Reports infomation about JIT-compiled code to the agent. * * The reported information is used to attribute samples obtained from any - * Intel(R) VTune(TM) Amplifier collector. This API needs to be called + * Intel(R) VTune(TM) Profiler collector. This API needs to be called * after JIT compilation and before the first entry into the JIT-compiled * code. * diff --git a/3rdparty/ittnotify/include/legacy/ittnotify.h b/3rdparty/ittnotify/include/legacy/ittnotify.h index 36a77f1dfc..cb014f3eed 100644 --- a/3rdparty/ittnotify/include/legacy/ittnotify.h +++ b/3rdparty/ittnotify/include/legacy/ittnotify.h @@ -1,60 +1,8 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. +/* + Copyright (C) 2005-2019 Intel Corporation - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +*/ #ifndef _LEGACY_ITTNOTIFY_H_ #define _LEGACY_ITTNOTIFY_H_ @@ -80,6 +28,10 @@ # define ITT_OS_FREEBSD 4 #endif /* ITT_OS_FREEBSD */ +#ifndef ITT_OS_OPENBSD +# define ITT_OS_OPENBSD 5 +#endif /* ITT_OS_OPENBSD */ + #ifndef ITT_OS # if defined WIN32 || defined _WIN32 # define ITT_OS ITT_OS_WIN @@ -87,6 +39,8 @@ # define ITT_OS ITT_OS_MAC # elif defined( __FreeBSD__ ) # define ITT_OS ITT_OS_FREEBSD +# elif defined( __OpenBSD__ ) +# define ITT_OS ITT_OS_OPENBSD # else # define ITT_OS ITT_OS_LINUX # endif @@ -108,6 +62,10 @@ # define ITT_PLATFORM_FREEBSD 4 #endif /* ITT_PLATFORM_FREEBSD */ +#ifndef ITT_PLATFORM_OPENBSD +# define ITT_PLATFORM_OPENBSD 5 +#endif /* ITT_PLATFORM_OPENBSD */ + #ifndef ITT_PLATFORM # if ITT_OS==ITT_OS_WIN # define ITT_PLATFORM ITT_PLATFORM_WIN @@ -115,6 +73,8 @@ # define ITT_PLATFORM ITT_PLATFORM_MAC # elif ITT_OS==ITT_OS_FREEBSD # define ITT_PLATFORM ITT_PLATFORM_FREEBSD +# elif ITT_OS==ITT_OS_OPENBSD +# define ITT_PLATFORM ITT_PLATFORM_OPENBSD # else # define ITT_PLATFORM ITT_PLATFORM_POSIX # endif @@ -167,7 +127,12 @@ #if ITT_PLATFORM==ITT_PLATFORM_WIN /* use __forceinline (VC++ specific) */ -#define ITT_INLINE __forceinline +#if defined(__MINGW32__) && !defined(__cplusplus) +#define ITT_INLINE static __inline__ __attribute__((__always_inline__,__gnu_inline__)) +#else +#define ITT_INLINE static __forceinline +#endif /* __MINGW32__ */ + #define ITT_INLINE_ATTRIBUTE /* nothing */ #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ /* @@ -219,20 +184,20 @@ #define ITTNOTIFY_VOID(n) (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n) #define ITTNOTIFY_DATA(n) (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n) -#define ITTNOTIFY_VOID_D0(n,d) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d) -#define ITTNOTIFY_VOID_D1(n,d,x) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x) -#define ITTNOTIFY_VOID_D2(n,d,x,y) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y) -#define ITTNOTIFY_VOID_D3(n,d,x,y,z) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z) -#define ITTNOTIFY_VOID_D4(n,d,x,y,z,a) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z,a) -#define ITTNOTIFY_VOID_D5(n,d,x,y,z,a,b) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b) -#define ITTNOTIFY_VOID_D6(n,d,x,y,z,a,b,c) (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b,c) -#define ITTNOTIFY_DATA_D0(n,d) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d) -#define ITTNOTIFY_DATA_D1(n,d,x) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x) -#define ITTNOTIFY_DATA_D2(n,d,x,y) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y) -#define ITTNOTIFY_DATA_D3(n,d,x,y,z) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z) -#define ITTNOTIFY_DATA_D4(n,d,x,y,z,a) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z,a) -#define ITTNOTIFY_DATA_D5(n,d,x,y,z,a,b) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b) -#define ITTNOTIFY_DATA_D6(n,d,x,y,z,a,b,c) (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b,c) +#define ITTNOTIFY_VOID_D0(n,d) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d) +#define ITTNOTIFY_VOID_D1(n,d,x) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x) +#define ITTNOTIFY_VOID_D2(n,d,x,y) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y) +#define ITTNOTIFY_VOID_D3(n,d,x,y,z) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z) +#define ITTNOTIFY_VOID_D4(n,d,x,y,z,a) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z,a) +#define ITTNOTIFY_VOID_D5(n,d,x,y,z,a,b) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b) +#define ITTNOTIFY_VOID_D6(n,d,x,y,z,a,b,c) (d == NULL) ? (void)0 : (!(d)->flags) ? (void)0 : (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b,c) +#define ITTNOTIFY_DATA_D0(n,d) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d) +#define ITTNOTIFY_DATA_D1(n,d,x) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x) +#define ITTNOTIFY_DATA_D2(n,d,x,y) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y) +#define ITTNOTIFY_DATA_D3(n,d,x,y,z) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z) +#define ITTNOTIFY_DATA_D4(n,d,x,y,z,a) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z,a) +#define ITTNOTIFY_DATA_D5(n,d,x,y,z,a,b) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b) +#define ITTNOTIFY_DATA_D6(n,d,x,y,z,a,b,c) (d == NULL) ? 0 : (!(d)->flags) ? 0 : (!ITTNOTIFY_NAME(n)) ? 0 : ITTNOTIFY_NAME(n)(d,x,y,z,a,b,c) #ifdef ITT_STUB #undef ITT_STUB @@ -269,7 +234,7 @@ extern "C" { * only pauses tracing and analyzing memory access. * It does not pause tracing or analyzing threading APIs. * . - * - Intel(R) Parallel Amplifier and Intel(R) VTune(TM) Amplifier XE: + * - Intel(R) VTune(TM) Profiler: * - Does continue to record when new threads are started. * . * - Other effects: @@ -1005,9 +970,9 @@ ITT_STUB(ITTAPI, __itt_frame, frame_create, (const char *domain)) #endif /* INTEL_NO_MACRO_BODY */ /** @endcond */ -/** @brief Record an frame begin occurrence. */ +/** @brief Record a frame begin occurrence. */ void ITTAPI __itt_frame_begin(__itt_frame frame); -/** @brief Record an frame end occurrence. */ +/** @brief Record a frame end occurrence. */ void ITTAPI __itt_frame_end (__itt_frame frame); /** @cond exclude_from_documentation */ diff --git a/3rdparty/ittnotify/include/libittnotify.h b/3rdparty/ittnotify/include/libittnotify.h index 2ac37d8c34..107949aa76 100644 --- a/3rdparty/ittnotify/include/libittnotify.h +++ b/3rdparty/ittnotify/include/libittnotify.h @@ -1,60 +1,8 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. +/* + Copyright (C) 2005-2019 Intel Corporation - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +*/ #ifndef _LIBITTNOTIFY_H_ #define _LIBITTNOTIFY_H_ diff --git a/3rdparty/ittnotify/include/llvm_jit_event_listener.hpp b/3rdparty/ittnotify/include/llvm_jit_event_listener.hpp deleted file mode 100644 index 2d1ca7fc43..0000000000 --- a/3rdparty/ittnotify/include/llvm_jit_event_listener.hpp +++ /dev/null @@ -1,241 +0,0 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. - - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This file implements an interface bridge from Low-Level Virtual Machine - * llvm::JITEventListener to Intel JIT Profiling API. It passes the function - * and line information to the appropriate functions in the JIT profiling - * interface so that any LLVM-based JIT engine can emit the JIT code - * notifications that the profiler will receive. - * - * Usage model: - * - * 1. Register the listener implementation instance with the execution engine: - * - * #include - * ... - * ExecutionEngine *TheExecutionEngine; - * ... - * TheExecutionEngine = EngineBuilder(TheModule).create(); - * ... - * __itt_llvm_jit_event_listener jitListener; - * TheExecutionEngine->RegisterJITEventListener(&jitListener); - * ... - * - * 2. When compiling make sure to add the ITT API include directory to the - * compiler include directories, ITT API library directory to the linker - * library directories and link with jitprofling static library. - */ - -#ifndef __ITT_LLVM_JIT_EVENT_LISTENER_HPP__ -#define __ITT_LLVM_JIT_EVENT_LISTENER_HPP__ - -#include "jitprofiling.h" - -#include -#include -#include -#include - -#include -#include - -// Uncomment the line below to turn on logging to stderr -#define JITPROFILING_DEBUG_ENABLE - -// Some elementary logging support -#ifdef JITPROFILING_DEBUG_ENABLE -#include -#include -static void _jit_debug(const char* format, ...) -{ - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); -} -// Use the macro as JITDEBUG(("foo: %d", foo_val)); -#define JITDEBUG(x) \ - do { \ - _jit_debug("jit-listener: "); \ - _jit_debug x; \ - } \ - while (0) -#else -#define JITDEBUG(x) -#endif - -// LLVM JIT event listener, translates the notifications to the JIT profiling -// API information. -class __itt_llvm_jit_event_listener : public llvm::JITEventListener -{ -public: - __itt_llvm_jit_event_listener() {} - -public: - virtual void NotifyFunctionEmitted(const llvm::Function &F, - void *Code, size_t Size, const EmittedFunctionDetails &Details) - { - std::string name = F.getName().str(); - JITDEBUG(("function jitted:\n")); - JITDEBUG((" addr=0x%08x\n", (int)Code)); - JITDEBUG((" name=`%s'\n", name.c_str())); - JITDEBUG((" code-size=%d\n", (int)Size)); - JITDEBUG((" line-infos-count=%d\n", Details.LineStarts.size())); - - // The method must not be in the map - the entry must have been cleared - // from the map in NotifyFreeingMachineCode in case of rejitting. - assert(m_addr2MethodId.find(Code) == m_addr2MethodId.end()); - - int mid = iJIT_GetNewMethodID(); - m_addr2MethodId[Code] = mid; - - iJIT_Method_Load mload; - memset(&mload, 0, sizeof mload); - mload.method_id = mid; - - // Populate the method size and name information - // TODO: The JIT profiling API should have members as const char pointers. - mload.method_name = (char*)name.c_str(); - mload.method_load_address = Code; - mload.method_size = (unsigned int)Size; - - // Populate line information now. - // From the JIT API documentation it is not quite clear whether the - // line information can be given in ranges, so we'll populate it for - // every byte of the function, hmm. - std::string srcFilePath; - std::vector lineInfos; - char *addr = (char*)Code; - char *lineAddr = addr; // Exclusive end point at which current - // line info changes. - const llvm::DebugLoc* loc = 0; // Current line info - int lineIndex = -1; // Current index into the line info table - for (int i = 0; i < Size; ++i, ++addr) { - while (addr >= lineAddr) { - if (lineIndex >= 0 && lineIndex < Details.LineStarts.size()) { - loc = &Details.LineStarts[lineIndex].Loc; - std::string p = getSrcFilePath(F.getContext(), *loc); - assert(srcFilePath.empty() || p == srcFilePath); - srcFilePath = p; - } else { - loc = NULL; - } - lineIndex++; - if (lineIndex >= 0 && lineIndex < Details.LineStarts.size()) { - lineAddr = (char*)Details.LineStarts[lineIndex].Address; - } else { - lineAddr = addr + Size; - } - } - if (loc) { - int line = loc->getLine(); - LineNumberInfo info = { i, line }; - lineInfos.push_back(info); - JITDEBUG((" addr 0x%08x -> line %d\n", addr, line)); - } - } - if (!lineInfos.empty()) { - mload.line_number_size = lineInfos.size(); - JITDEBUG((" translated to %d line infos to JIT", (int)lineInfos.size())); - mload.line_number_table = &lineInfos[0]; - mload.source_file_name = (char*)srcFilePath.c_str(); - } - - iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &mload); - } - - virtual void NotifyFreeingMachineCode(void *OldPtr) - { - JITDEBUG(("function unjitted\n")); - JITDEBUG((" addr=0x%08x\n", (int)OldPtr)); - Addr2MethodId::iterator it = m_addr2MethodId.find(OldPtr); - assert(it != m_addr2MethodId.end()); - iJIT_Method_Id mid = { it->second }; - iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, &mid); - m_addr2MethodId.erase(it); - } - -private: - std::string getSrcFilePath(const llvm::LLVMContext& ctx, const llvm::DebugLoc& loc) - { - llvm::MDNode* node = loc.getAsMDNode(ctx); - llvm::DILocation srcLoc(node); - return srcLoc.getDirectory().str() + "/" + srcLoc.getFilename().str(); - } - -private: - /// Don't copy - __itt_llvm_jit_event_listener(const __itt_llvm_jit_event_listener&); - __itt_llvm_jit_event_listener& operator=(const __itt_llvm_jit_event_listener&); - -private: - typedef std::vector LineInfoList; - - // The method unload notification in VTune JIT profiling API takes the - // method ID, not method address so have to maintain the mapping. Is - // there a more efficient and simple way to do this like attaching the - // method ID information somehow to the LLVM function instance? - // - // TODO: It would be more convenient for the JIT API to take the method - // address, not method ID. - typedef std::map Addr2MethodId; - Addr2MethodId m_addr2MethodId; -}; - -#endif // Header guard diff --git a/3rdparty/ittnotify/src/ittnotify/LICENSE.BSD b/3rdparty/ittnotify/src/ittnotify/BSD-3-Clause.txt similarity index 69% rename from 3rdparty/ittnotify/src/ittnotify/LICENSE.BSD rename to 3rdparty/ittnotify/src/ittnotify/BSD-3-Clause.txt index 7beafe5ce9..37478a55f3 100644 --- a/3rdparty/ittnotify/src/ittnotify/LICENSE.BSD +++ b/3rdparty/ittnotify/src/ittnotify/BSD-3-Clause.txt @@ -1,7 +1,8 @@ -Copyright (c) 2011, Intel Corporation -All rights reserved. +Copyright (c) 2019 Intel Corporation. All rights reserved. + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -• Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -• Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -• Neither the name of the Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/3rdparty/ittnotify/src/ittnotify/LICENSE.GPL b/3rdparty/ittnotify/src/ittnotify/GPL-2.0-only.txt similarity index 96% rename from 3rdparty/ittnotify/src/ittnotify/LICENSE.GPL rename to 3rdparty/ittnotify/src/ittnotify/GPL-2.0-only.txt index efe910f4f0..be1e815450 100644 --- a/3rdparty/ittnotify/src/ittnotify/LICENSE.GPL +++ b/3rdparty/ittnotify/src/ittnotify/GPL-2.0-only.txt @@ -1,65 +1,103 @@ -The GNU General Public License (GPL) +GNU GENERAL PUBLIC LICENSE Version 2, June 1991 + Copyright (C) 1989, 1991 Free Software Foundation, Inc. -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + Preamble -The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. + +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. + When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. + To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. + For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. + We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. + Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. + Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. + The precise terms and conditions for copying, distribution and modification follow. + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. + 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. + Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. + In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. + If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. + It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. + 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS + How to Apply These Terms to Your New Programs + If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. + To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. -One line to give the program's name and a brief idea of what it does. -Copyright (C) + + +Copyright (C) < yyyy> + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + Also add information on how to contact you by electronic and paper mail. + If the program is interactive, make it output a short notice like this when it starts in an interactive mode: + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. + The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. + You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: + Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. -signature of Ty Coon, 1 April 1989 -Ty Coon, President of Vice -This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. + +, 1 April 1989 Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. diff --git a/3rdparty/ittnotify/src/ittnotify/disable_warnings.h b/3rdparty/ittnotify/src/ittnotify/disable_warnings.h index 6dfe159c16..c4f4da79a3 100644 --- a/3rdparty/ittnotify/src/ittnotify/disable_warnings.h +++ b/3rdparty/ittnotify/src/ittnotify/disable_warnings.h @@ -1,71 +1,23 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. +/* + Copyright (C) 2005-2019 Intel Corporation - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +*/ #include "ittnotify_config.h" #if ITT_PLATFORM==ITT_PLATFORM_WIN +#if defined _MSC_VER + #pragma warning (disable: 593) /* parameter "XXXX" was set but never used */ #pragma warning (disable: 344) /* typedef name has already been declared (with same type) */ #pragma warning (disable: 174) /* expression has no effect */ #pragma warning (disable: 4127) /* conditional expression is constant */ #pragma warning (disable: 4306) /* conversion from '?' to '?' of greater size */ +#endif + #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ #if defined __INTEL_COMPILER diff --git a/3rdparty/ittnotify/src/ittnotify/ittnotify_config.h b/3rdparty/ittnotify/src/ittnotify/ittnotify_config.h index d68d0e152e..64c91ef57e 100644 --- a/3rdparty/ittnotify/src/ittnotify/ittnotify_config.h +++ b/3rdparty/ittnotify/src/ittnotify/ittnotify_config.h @@ -1,60 +1,8 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. +/* + Copyright (C) 2005-2019 Intel Corporation - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +*/ #ifndef _ITTNOTIFY_CONFIG_H_ #define _ITTNOTIFY_CONFIG_H_ @@ -75,6 +23,10 @@ # define ITT_OS_FREEBSD 4 #endif /* ITT_OS_FREEBSD */ +#ifndef ITT_OS_OPENBSD +# define ITT_OS_OPENBSD 5 +#endif /* ITT_OS_OPENBSD */ + #ifndef ITT_OS # if defined WIN32 || defined _WIN32 # define ITT_OS ITT_OS_WIN @@ -82,6 +34,8 @@ # define ITT_OS ITT_OS_MAC # elif defined( __FreeBSD__ ) # define ITT_OS ITT_OS_FREEBSD +# elif defined( __OpenBSD__ ) +# define ITT_OS ITT_OS_OPENBSD # else # define ITT_OS ITT_OS_LINUX # endif @@ -103,6 +57,10 @@ # define ITT_PLATFORM_FREEBSD 4 #endif /* ITT_PLATFORM_FREEBSD */ +#ifndef ITT_PLATFORM_OPENBSD +# define ITT_PLATFORM_OPENBSD 5 +#endif /* ITT_PLATFORM_OPENBSD */ + #ifndef ITT_PLATFORM # if ITT_OS==ITT_OS_WIN # define ITT_PLATFORM ITT_PLATFORM_WIN @@ -110,6 +68,8 @@ # define ITT_PLATFORM ITT_PLATFORM_MAC # elif ITT_OS==ITT_OS_FREEBSD # define ITT_PLATFORM ITT_PLATFORM_FREEBSD +# elif ITT_OS==ITT_OS_OPENBSD +# define ITT_PLATFORM ITT_PLATFORM_OPENBSD # else # define ITT_PLATFORM ITT_PLATFORM_POSIX # endif @@ -162,7 +122,12 @@ #if ITT_PLATFORM==ITT_PLATFORM_WIN /* use __forceinline (VC++ specific) */ -#define ITT_INLINE __forceinline +#if defined(__MINGW32__) && !defined(__cplusplus) +#define ITT_INLINE static __inline__ __attribute__((__always_inline__,__gnu_inline__)) +#else +#define ITT_INLINE static __forceinline +#endif /* __MINGW32__ */ + #define ITT_INLINE_ATTRIBUTE /* nothing */ #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ /* @@ -188,6 +153,10 @@ # define ITT_ARCH_IA32E 2 #endif /* ITT_ARCH_IA32E */ +#ifndef ITT_ARCH_IA64 +# define ITT_ARCH_IA64 3 +#endif /* ITT_ARCH_IA64 */ + #ifndef ITT_ARCH_ARM # define ITT_ARCH_ARM 4 #endif /* ITT_ARCH_ARM */ @@ -196,9 +165,9 @@ # define ITT_ARCH_PPC64 5 #endif /* ITT_ARCH_PPC64 */ -#ifndef ITT_ARCH_AARCH64 /* 64-bit ARM */ -# define ITT_ARCH_AARCH64 6 -#endif /* ITT_ARCH_AARCH64 */ +#ifndef ITT_ARCH_ARM64 +# define ITT_ARCH_ARM64 6 +#endif /* ITT_ARCH_ARM64 */ #ifndef ITT_ARCH # if defined _M_IX86 || defined __i386__ @@ -210,7 +179,7 @@ # elif defined _M_ARM || defined __arm__ # define ITT_ARCH ITT_ARCH_ARM # elif defined __aarch64__ -# define ITT_ARCH ITT_ARCH_AARCH64 +# define ITT_ARCH ITT_ARCH_ARM64 # elif defined __powerpc64__ # define ITT_ARCH ITT_ARCH_PPC64 # endif @@ -239,10 +208,10 @@ #define ITT_MAGIC { 0xED, 0xAB, 0xAB, 0xEC, 0x0D, 0xEE, 0xDA, 0x30 } /* Replace with snapshot date YYYYMMDD for promotion build. */ -#define API_VERSION_BUILD 20151119 +#define API_VERSION_BUILD 20250113 #ifndef API_VERSION_NUM -#define API_VERSION_NUM 0.0.0 +#define API_VERSION_NUM 3.25.4 #endif /* API_VERSION_NUM */ #define API_VERSION "ITT-API-Version " ITT_TO_STR(API_VERSION_NUM) \ @@ -254,7 +223,11 @@ typedef HMODULE lib_t; typedef DWORD TIDT; typedef CRITICAL_SECTION mutex_t; +#ifdef __cplusplus +#define MUTEX_INITIALIZER {} +#else #define MUTEX_INITIALIZER { 0 } +#endif #define strong_alias(name, aliasname) /* empty for Windows */ #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ #include @@ -282,13 +255,13 @@ typedef pthread_mutex_t mutex_t; #define __itt_mutex_init(mutex) InitializeCriticalSection(mutex) #define __itt_mutex_lock(mutex) EnterCriticalSection(mutex) #define __itt_mutex_unlock(mutex) LeaveCriticalSection(mutex) +#define __itt_mutex_destroy(mutex) DeleteCriticalSection(mutex) #define __itt_load_lib(name) LoadLibraryA(name) #define __itt_unload_lib(handle) FreeLibrary(handle) #define __itt_system_error() (int)GetLastError() #define __itt_fstrcmp(s1, s2) lstrcmpA(s1, s2) #define __itt_fstrnlen(s, l) strnlen_s(s, l) #define __itt_fstrcpyn(s1, b, s2, l) strncpy_s(s1, b, s2, l) -#define __itt_fstrdup(s) _strdup(s) #define __itt_thread_id() GetCurrentThreadId() #define __itt_thread_yield() SwitchToThread() #ifndef ITT_SIMPLE_INIT @@ -298,6 +271,13 @@ ITT_INLINE long __itt_interlocked_increment(volatile long* ptr) { return InterlockedIncrement(ptr); } +ITT_INLINE long +__itt_interlocked_compare_exchange(volatile long* ptr, long exchange, long comperand) ITT_INLINE_ATTRIBUTE; +ITT_INLINE long +__itt_interlocked_compare_exchange(volatile long* ptr, long exchange, long comperand) +{ + return InterlockedCompareExchange(ptr, exchange, comperand); +} #endif /* ITT_SIMPLE_INIT */ #define DL_SYMBOLS (1) @@ -327,6 +307,7 @@ ITT_INLINE long __itt_interlocked_increment(volatile long* ptr) } #define __itt_mutex_lock(mutex) pthread_mutex_lock(mutex) #define __itt_mutex_unlock(mutex) pthread_mutex_unlock(mutex) +#define __itt_mutex_destroy(mutex) pthread_mutex_destroy(mutex) #define __itt_load_lib(name) dlopen(name, RTLD_LAZY) #define __itt_unload_lib(handle) dlclose(handle) #define __itt_system_error() errno @@ -341,10 +322,18 @@ ITT_INLINE long __itt_interlocked_increment(volatile long* ptr) #ifdef SDL_STRNCPY_S #define __itt_fstrcpyn(s1, b, s2, l) SDL_STRNCPY_S(s1, b, s2, l) #else -#define __itt_fstrcpyn(s1, b, s2, l) strncpy(s1, s2, b) +#define __itt_fstrcpyn(s1, b, s2, l) { \ + if (b > 0) { \ + /* 'volatile' is used to suppress the warning that a destination */ \ + /* bound depends on the length of the source. */ \ + volatile size_t num_to_copy = (size_t)(b - 1) < (size_t)(l) ? \ + (size_t)(b - 1) : (size_t)(l); \ + strncpy(s1, s2, num_to_copy); \ + s1[num_to_copy] = 0; \ + } \ +} #endif /* SDL_STRNCPY_S */ -#define __itt_fstrdup(s) strdup(s) #define __itt_thread_id() pthread_self() #define __itt_thread_yield() sched_yield() #if ITT_ARCH==ITT_ARCH_IA64 @@ -360,12 +349,12 @@ ITT_INLINE long __TBB_machine_fetchadd4(volatile void* ptr, long addend) { long result; __asm__ __volatile__("lock\nxadd %0,%1" - : "=r"(result),"=m"(*(int*)ptr) - : "0"(addend), "m"(*(int*)ptr) + : "=r"(result),"=m"(*(volatile int*)ptr) + : "0"(addend), "m"(*(volatile int*)ptr) : "memory"); return result; } -#elif ITT_ARCH==ITT_ARCH_ARM || ITT_ARCH==ITT_ARCH_AARCH64 || ITT_ARCH==ITT_ARCH_PPC64 +#else #define __TBB_machine_fetchadd4(addr, val) __sync_fetch_and_add(addr, val) #endif /* ITT_ARCH==ITT_ARCH_IA64 */ #ifndef ITT_SIMPLE_INIT @@ -375,6 +364,13 @@ ITT_INLINE long __itt_interlocked_increment(volatile long* ptr) { return __TBB_machine_fetchadd4(ptr, 1) + 1L; } +ITT_INLINE long +__itt_interlocked_compare_exchange(volatile long* ptr, long exchange, long comperand) ITT_INLINE_ATTRIBUTE; +ITT_INLINE long +__itt_interlocked_compare_exchange(volatile long* ptr, long exchange, long comperand) +{ + return __sync_val_compare_and_swap(ptr, exchange, comperand); +} #endif /* ITT_SIMPLE_INIT */ void* dlopen(const char*, int) __attribute__((weak)); @@ -394,10 +390,20 @@ pthread_t pthread_self(void) __attribute__((weak)); #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -typedef enum { - __itt_collection_normal = 0, - __itt_collection_paused = 1 -} __itt_collection_state; +/* strdup() is not included into C99 which results in a compiler warning about + * implicitly declared symbol. To avoid the issue strdup is implemented + * manually. + */ +#define ITT_STRDUP_MAX_STRING_SIZE 4096 +#define __itt_fstrdup(s, new_s) do { \ + if (s != NULL) { \ + size_t s_len = __itt_fstrnlen(s, ITT_STRDUP_MAX_STRING_SIZE); \ + new_s = (char *)malloc(s_len + 1); \ + if (new_s != NULL) { \ + __itt_fstrcpyn(new_s, s_len + 1, s, s_len); \ + } \ + } \ +} while(0) typedef enum { __itt_thread_normal = 0, @@ -463,6 +469,10 @@ typedef struct __itt_counter_info struct ___itt_domain; struct ___itt_string_handle; +struct ___itt_histogram; +struct ___itt_counter_metadata; + +#include "ittnotify.h" typedef struct ___itt_global { @@ -484,7 +494,10 @@ typedef struct ___itt_global struct ___itt_domain* domain_list; struct ___itt_string_handle* string_list; __itt_collection_state state; - __itt_counter_info_t* counter_list; + __itt_counter_info_t* counter_list; + unsigned int ipt_collect_events; + struct ___itt_histogram* histogram_list; + struct ___itt_counter_metadata* counter_metadata_list; } __itt_global; #pragma pack(pop) @@ -510,7 +523,9 @@ typedef struct ___itt_global h = (__itt_thread_info*)malloc(sizeof(__itt_thread_info)); \ if (h != NULL) { \ h->tid = t; \ - h->nameA = n ? __itt_fstrdup(n) : NULL; \ + char *n_copy = NULL; \ + __itt_fstrdup(n, n_copy); \ + h->nameA = n_copy; \ h->nameW = NULL; \ h->state = s; \ h->extra1 = 0; /* reserved */ \ @@ -543,7 +558,9 @@ typedef struct ___itt_global h = (__itt_domain*)malloc(sizeof(__itt_domain)); \ if (h != NULL) { \ h->flags = 1; /* domain is enabled by default */ \ - h->nameA = name ? __itt_fstrdup(name) : NULL; \ + char *name_copy = NULL; \ + __itt_fstrdup(name, name_copy); \ + h->nameA = name_copy; \ h->nameW = NULL; \ h->extra1 = 0; /* reserved */ \ h->extra2 = NULL; /* reserved */ \ @@ -573,7 +590,9 @@ typedef struct ___itt_global #define NEW_STRING_HANDLE_A(gptr,h,h_tail,name) { \ h = (__itt_string_handle*)malloc(sizeof(__itt_string_handle)); \ if (h != NULL) { \ - h->strA = name ? __itt_fstrdup(name) : NULL; \ + char *name_copy = NULL; \ + __itt_fstrdup(name, name_copy); \ + h->strA = name_copy; \ h->strW = NULL; \ h->extra1 = 0; /* reserved */ \ h->extra2 = NULL; /* reserved */ \ @@ -591,7 +610,7 @@ typedef struct ___itt_global h->nameA = NULL; \ h->nameW = name ? _wcsdup(name) : NULL; \ h->domainA = NULL; \ - h->domainW = name ? _wcsdup(domain) : NULL; \ + h->domainW = domain ? _wcsdup(domain) : NULL; \ h->type = type; \ h->index = 0; \ h->next = NULL; \ @@ -605,9 +624,13 @@ typedef struct ___itt_global #define NEW_COUNTER_A(gptr,h,h_tail,name,domain,type) { \ h = (__itt_counter_info_t*)malloc(sizeof(__itt_counter_info_t)); \ if (h != NULL) { \ - h->nameA = name ? __itt_fstrdup(name) : NULL; \ + char *name_copy = NULL; \ + __itt_fstrdup(name, name_copy); \ + h->nameA = name_copy; \ h->nameW = NULL; \ - h->domainA = domain ? __itt_fstrdup(domain) : NULL; \ + char *domain_copy = NULL; \ + __itt_fstrdup(domain, domain_copy); \ + h->domainA = domain_copy; \ h->domainW = NULL; \ h->type = type; \ h->index = 0; \ @@ -619,4 +642,98 @@ typedef struct ___itt_global } \ } +#define NEW_HISTOGRAM_W(gptr,h,h_tail,domain,name,x_type,y_type) { \ + h = (__itt_histogram*)malloc(sizeof(__itt_histogram)); \ + if (h != NULL) { \ + h->domain = domain; \ + h->nameA = NULL; \ + h->nameW = name ? _wcsdup(name) : NULL; \ + h->x_type = x_type; \ + h->y_type = y_type; \ + h->extra1 = 0; \ + h->extra2 = NULL; \ + h->next = NULL; \ + if (h_tail == NULL) \ + (gptr)->histogram_list = h; \ + else \ + h_tail->next = h; \ + } \ +} + +#define NEW_HISTOGRAM_A(gptr,h,h_tail,domain,name,x_type,y_type) { \ + h = (__itt_histogram*)malloc(sizeof(__itt_histogram)); \ + if (h != NULL) { \ + h->domain = domain; \ + char *name_copy = NULL; \ + __itt_fstrdup(name, name_copy); \ + h->nameA = name_copy; \ + h->nameW = NULL; \ + h->x_type = x_type; \ + h->y_type = y_type; \ + h->extra1 = 0; \ + h->extra2 = NULL; \ + h->next = NULL; \ + if (h_tail == NULL) \ + (gptr)->histogram_list = h; \ + else \ + h_tail->next = h; \ + } \ +} + +#define NEW_COUNTER_METADATA_NUM(gptr,h,h_tail,counter,type,value) { \ + h = (__itt_counter_metadata*)malloc(sizeof(__itt_counter_metadata)); \ + if (h != NULL) { \ + h->counter = counter; \ + h->type = type; \ + h->str_valueA = NULL; \ + h->str_valueW = NULL; \ + h->value = value; \ + h->extra1 = 0; \ + h->extra2 = NULL; \ + h->next = NULL; \ + if (h_tail == NULL) \ + (gptr)->counter_metadata_list = h; \ + else \ + h_tail->next = h; \ + } \ +} + +#define NEW_COUNTER_METADATA_STR_A(gptr,h,h_tail,counter,type,str_valueA) { \ + h = (__itt_counter_metadata*)malloc(sizeof(__itt_counter_metadata)); \ + if (h != NULL) { \ + h->counter = counter; \ + h->type = type; \ + char *str_value_copy = NULL; \ + __itt_fstrdup(str_valueA, str_value_copy); \ + h->str_valueA = str_value_copy; \ + h->str_valueW = NULL; \ + h->value = 0; \ + h->extra1 = 0; \ + h->extra2 = NULL; \ + h->next = NULL; \ + if (h_tail == NULL) \ + (gptr)->counter_metadata_list = h; \ + else \ + h_tail->next = h; \ + } \ +} + +#define NEW_COUNTER_METADATA_STR_W(gptr,h,h_tail,counter,type,str_valueW) { \ + h = (__itt_counter_metadata*)malloc(sizeof(__itt_counter_metadata)); \ + if (h != NULL) { \ + h->counter = counter; \ + h->type = type; \ + h->str_valueA = NULL; \ + h->str_valueW = str_valueW ? _wcsdup(str_valueW) : NULL; \ + h->value = 0; \ + h->extra1 = 0; \ + h->extra2 = NULL; \ + h->next = NULL; \ + if (h_tail == NULL) \ + (gptr)->counter_metadata_list = h; \ + else \ + h_tail->next = h; \ + } \ +} + #endif /* _ITTNOTIFY_CONFIG_H_ */ diff --git a/3rdparty/ittnotify/src/ittnotify/ittnotify_static.c b/3rdparty/ittnotify/src/ittnotify/ittnotify_static.c index 2a3349cff6..1913839dd8 100644 --- a/3rdparty/ittnotify/src/ittnotify/ittnotify_static.c +++ b/3rdparty/ittnotify/src/ittnotify/ittnotify_static.c @@ -1,65 +1,17 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. +/* + Copyright (C) 2005-2019 Intel Corporation - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +*/ +#define INTEL_NO_MACRO_BODY +#define INTEL_ITTNOTIFY_API_PRIVATE #include "ittnotify_config.h" #if ITT_PLATFORM==ITT_PLATFORM_WIN +#if !defined(PATH_MAX) #define PATH_MAX 512 +#endif #else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */ #include #include @@ -70,20 +22,56 @@ #include #include -#define INTEL_NO_MACRO_BODY -#define INTEL_ITTNOTIFY_API_PRIVATE #include "ittnotify.h" #include "legacy/ittnotify.h" #include "disable_warnings.h" -static const char api_version[] = API_VERSION "\0\n@(#) $Revision: 481659 $\n"; +static const char api_version[] = API_VERSION "\0\n@(#) $Revision$\n"; #define _N_(n) ITT_JOIN(INTEL_ITTNOTIFY_PREFIX,n) +#ifndef HAS_CPP_ATTR +#if defined(__cplusplus) && defined(__has_cpp_attribute) +#define HAS_CPP_ATTR(X) __has_cpp_attribute(X) +#else +#define HAS_CPP_ATTR(X) 0 +#endif +#endif + +#ifndef HAS_C_ATTR +#if defined(__STDC__) && defined(__has_c_attribute) +#define HAS_C_ATTR(X) __has_c_attribute(X) +#else +#define HAS_C_ATTR(X) 0 +#endif +#endif + +#ifndef HAS_GNU_ATTR +#if defined(__has_attribute) +#define HAS_GNU_ATTR(X) __has_attribute(X) +#else +#define HAS_GNU_ATTR(X) 0 +#endif +#endif + +#ifndef ITT_ATTRIBUTE_FALLTHROUGH +#if (HAS_CPP_ATTR(fallthrough) || HAS_C_ATTR(fallthrough)) && (__cplusplus >= 201703L || _MSVC_LANG >= 201703L) +#define ITT_ATTRIBUTE_FALLTHROUGH [[fallthrough]] +#elif HAS_CPP_ATTR(gnu::fallthrough) +#define ITT_ATTRIBUTE_FALLTHROUGH [[gnu::fallthrough]] +#elif HAS_CPP_ATTR(clang::fallthrough) +#define ITT_ATTRIBUTE_FALLTHROUGH [[clang::fallthrough]] +#elif HAS_GNU_ATTR(fallthrough) && !__INTEL_COMPILER +#define ITT_ATTRIBUTE_FALLTHROUGH __attribute__((fallthrough)) +#else +#define ITT_ATTRIBUTE_FALLTHROUGH +#endif +#endif + #if ITT_OS==ITT_OS_WIN static const char* ittnotify_lib_name = "libittnotify.dll"; -#elif ITT_OS==ITT_OS_LINUX || ITT_OS==ITT_OS_FREEBSD +#elif ITT_OS==ITT_OS_LINUX || ITT_OS==ITT_OS_FREEBSD || ITT_OS==ITT_OS_OPENBSD static const char* ittnotify_lib_name = "libittnotify.so"; #elif ITT_OS==ITT_OS_MAC static const char* ittnotify_lib_name = "libittnotify.dylib"; @@ -139,7 +127,7 @@ static const char* ittnotify_lib_name = "libittnotify.dylib"; { \ if (!p.mutex_initialized) \ { \ - if (__itt_interlocked_increment(&p.atomic_counter) == 1) \ + if (__itt_interlocked_compare_exchange(&p.atomic_counter, 1, 0) == 0) \ { \ __itt_mutex_init(&p.mutex); \ p.mutex_initialized = 1; \ @@ -152,7 +140,21 @@ static const char* ittnotify_lib_name = "libittnotify.dylib"; } \ } -const int _N_(err) = 0; +#define ITT_MUTEX_DESTROY(p) { \ + if (PTHREAD_SYMBOLS) \ + { \ + if (p.mutex_initialized) \ + { \ + if (__itt_interlocked_compare_exchange(&p.atomic_counter, 0, 1) == 1) \ + { \ + __itt_mutex_destroy(&p.mutex); \ + p.mutex_initialized = 0; \ + } \ + } \ + } \ +} + +#define ITT_MODULE_OBJECT_VERSION 1 typedef int (__itt_init_ittlib_t)(const char*, __itt_group_id); @@ -172,6 +174,8 @@ static __itt_fini_ittlib_t* __itt_fini_ittlib_ptr = _N_(fini_ittlib); #define __itt_fini_ittlib_name __itt_fini_ittlib_ptr #endif /* __itt_fini_ittlib_name */ +extern __itt_global _N_(_ittapi_global); + /* building pointers to imported funcs */ #undef ITT_STUBV #undef ITT_STUB @@ -181,7 +185,8 @@ typedef type api ITT_JOIN(_N_(name),_t) args; \ ITT_EXTERN_C_BEGIN ITT_JOIN(_N_(name),_t)* ITTNOTIFY_NAME(name) = ITT_VERSIONIZE(ITT_JOIN(_N_(name),_init)); ITT_EXTERN_C_END \ static type api ITT_VERSIONIZE(ITT_JOIN(_N_(name),_init)) args \ { \ - __itt_init_ittlib_name(NULL, __itt_group_all); \ + if (!_N_(_ittapi_global).api_initialized && _N_(_ittapi_global).thread_list == NULL) \ + __itt_init_ittlib_name(NULL, __itt_group_all); \ if (ITTNOTIFY_NAME(name) && ITTNOTIFY_NAME(name) != ITT_VERSIONIZE(ITT_JOIN(_N_(name),_init))) \ return ITTNOTIFY_NAME(name) params; \ else \ @@ -194,7 +199,8 @@ typedef type api ITT_JOIN(_N_(name),_t) args; \ ITT_EXTERN_C_BEGIN ITT_JOIN(_N_(name),_t)* ITTNOTIFY_NAME(name) = ITT_VERSIONIZE(ITT_JOIN(_N_(name),_init)); ITT_EXTERN_C_END \ static type api ITT_VERSIONIZE(ITT_JOIN(_N_(name),_init)) args \ { \ - __itt_init_ittlib_name(NULL, __itt_group_all); \ + if (!_N_(_ittapi_global).api_initialized && _N_(_ittapi_global).thread_list == NULL) \ + __itt_init_ittlib_name(NULL, __itt_group_all); \ if (ITTNOTIFY_NAME(name) && ITTNOTIFY_NAME(name) != ITT_VERSIONIZE(ITT_JOIN(_N_(name),_init))) \ ITTNOTIFY_NAME(name) params; \ else \ @@ -240,8 +246,10 @@ static __itt_group_alias group_alias[] = { #pragma pack(pop) #if ITT_PLATFORM==ITT_PLATFORM_WIN +#if _MSC_VER #pragma warning(push) #pragma warning(disable: 4054) /* warning C4054: 'type cast' : from function pointer 'XXX' to data pointer 'void *' */ +#endif #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ static __itt_api_info api_list[] = { @@ -263,11 +271,11 @@ static __itt_api_info api_list[] = { }; #if ITT_PLATFORM==ITT_PLATFORM_WIN +#if _MSC_VER #pragma warning(pop) +#endif #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -static const char dll_path[PATH_MAX] = { 0 }; - /* static part descriptor which handles. all notification api attributes. */ __itt_global _N_(_ittapi_global) = { ITT_MAGIC, /* identification info */ @@ -278,19 +286,23 @@ __itt_global _N_(_ittapi_global) = { MUTEX_INITIALIZER, /* mutex */ NULL, /* dynamic library handle */ NULL, /* error_handler */ - (const char**)&dll_path, /* dll_path_ptr */ + NULL, /* dll_path_ptr */ (__itt_api_info*)&api_list, /* api_list_ptr */ NULL, /* next __itt_global */ NULL, /* thread_list */ NULL, /* domain_list */ NULL, /* string_list */ - __itt_collection_normal, /* collection state */ - NULL /* counter_list */ + __itt_collection_uninitialized, /* collection state */ + NULL, /* counter_list */ + 0, /* ipt_collect_events */ + NULL, /* histogram_list */ + NULL /* counter_metadata_list */ }; typedef void (__itt_api_init_t)(__itt_global*, __itt_group_id); typedef void (__itt_api_fini_t)(__itt_global*); +static __itt_domain dummy_domain; /* ========================================================================= */ #ifdef ITT_NOTIFY_EXT_REPORT @@ -298,27 +310,33 @@ ITT_EXTERN_C void _N_(error_handler)(__itt_error_code, va_list args); #endif /* ITT_NOTIFY_EXT_REPORT */ #if ITT_PLATFORM==ITT_PLATFORM_WIN +#if _MSC_VER #pragma warning(push) #pragma warning(disable: 4055) /* warning C4055: 'type cast' : from data pointer 'void *' to function pointer 'XXX' */ +#endif #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -static void __itt_report_error(__itt_error_code code, ...) +static void __itt_report_error(int code, ...) { va_list args; va_start(args, code); if (_N_(_ittapi_global).error_handler != NULL) { __itt_error_handler_t* handler = (__itt_error_handler_t*)(size_t)_N_(_ittapi_global).error_handler; - handler(code, args); + handler((__itt_error_code)code, args); } #ifdef ITT_NOTIFY_EXT_REPORT - _N_(error_handler)(code, args); + _N_(error_handler)((__itt_error_code)code, args); #endif /* ITT_NOTIFY_EXT_REPORT */ va_end(args); } +static int __itt_is_collector_available(void); + #if ITT_PLATFORM==ITT_PLATFORM_WIN +#if _MSC_VER #pragma warning(pop) +#endif #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ #if ITT_PLATFORM==ITT_PLATFORM_WIN @@ -339,14 +357,22 @@ static __itt_domain* ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(domain_createW),_init))( __itt_mutex_unlock(&_N_(_ittapi_global).mutex); return ITTNOTIFY_NAME(domain_createW)(name); } + else + { + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return &dummy_domain; + } } - for (h_tail = NULL, h = _N_(_ittapi_global).domain_list; h != NULL; h_tail = h, h = h->next) + if (__itt_is_collector_available()) { - if (h->nameW != NULL && !wcscmp(h->nameW, name)) break; - } - if (h == NULL) - { - NEW_DOMAIN_W(&_N_(_ittapi_global),h,h_tail,name); + for (h_tail = NULL, h = _N_(_ittapi_global).domain_list; h != NULL; h_tail = h, h = h->next) + { + if (h->nameW != NULL && !wcscmp(h->nameW, name)) break; + } + if (h == NULL) + { + NEW_DOMAIN_W(&_N_(_ittapi_global), h, h_tail, name); + } } if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); return h; @@ -380,19 +406,63 @@ static __itt_domain* ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(domain_create),_init))(c return ITTNOTIFY_NAME(domain_create)(name); } #endif + else + { +#if ITT_PLATFORM==ITT_PLATFORM_WIN + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#else + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#endif + return &dummy_domain; + } } - for (h_tail = NULL, h = _N_(_ittapi_global).domain_list; h != NULL; h_tail = h, h = h->next) + if (__itt_is_collector_available()) { - if (h->nameA != NULL && !__itt_fstrcmp(h->nameA, name)) break; - } - if (h == NULL) - { - NEW_DOMAIN_A(&_N_(_ittapi_global),h,h_tail,name); + for (h_tail = NULL, h = _N_(_ittapi_global).domain_list; h != NULL; h_tail = h, h = h->next) + { + if (h->nameA != NULL && !__itt_fstrcmp(h->nameA, name)) break; + } + if (h == NULL) + { + NEW_DOMAIN_A(&_N_(_ittapi_global), h, h_tail, name); + } } if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); return h; } +static void ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(module_load_with_sections),_init))(__itt_module_object* module_obj) +{ + if (!_N_(_ittapi_global).api_initialized && _N_(_ittapi_global).thread_list == NULL) + { + __itt_init_ittlib_name(NULL, __itt_group_all); + } + if (ITTNOTIFY_NAME(module_load_with_sections) && ITTNOTIFY_NAME(module_load_with_sections) != ITT_VERSIONIZE(ITT_JOIN(_N_(module_load_with_sections),_init))) + { + if(module_obj != NULL) + { + module_obj->version = ITT_MODULE_OBJECT_VERSION; + ITTNOTIFY_NAME(module_load_with_sections)(module_obj); + } + } +} + +static void ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(module_unload_with_sections),_init))(__itt_module_object* module_obj) +{ + if (!_N_(_ittapi_global).api_initialized && _N_(_ittapi_global).thread_list == NULL) + { + __itt_init_ittlib_name(NULL, __itt_group_all); + } + if (ITTNOTIFY_NAME(module_unload_with_sections) && ITTNOTIFY_NAME(module_unload_with_sections) != ITT_VERSIONIZE(ITT_JOIN(_N_(module_unload_with_sections),_init))) + { + if(module_obj != NULL) + { + module_obj->version = ITT_MODULE_OBJECT_VERSION; + ITTNOTIFY_NAME(module_unload_with_sections)(module_obj); + } + } +} + #if ITT_PLATFORM==ITT_PLATFORM_WIN static __itt_string_handle* ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(string_handle_createW),_init))(const wchar_t* name) { @@ -411,14 +481,22 @@ static __itt_string_handle* ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(string_handle_cre __itt_mutex_unlock(&_N_(_ittapi_global).mutex); return ITTNOTIFY_NAME(string_handle_createW)(name); } + else + { + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return NULL; + } } - for (h_tail = NULL, h = _N_(_ittapi_global).string_list; h != NULL; h_tail = h, h = h->next) + if (__itt_is_collector_available()) { - if (h->strW != NULL && !wcscmp(h->strW, name)) break; - } - if (h == NULL) - { - NEW_STRING_HANDLE_W(&_N_(_ittapi_global),h,h_tail,name); + for (h_tail = NULL, h = _N_(_ittapi_global).string_list; h != NULL; h_tail = h, h = h->next) + { + if (h->strW != NULL && !wcscmp(h->strW, name)) break; + } + if (h == NULL) + { + NEW_STRING_HANDLE_W(&_N_(_ittapi_global), h, h_tail, name); + } } __itt_mutex_unlock(&_N_(_ittapi_global).mutex); return h; @@ -452,14 +530,26 @@ static __itt_string_handle* ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(string_handle_cre return ITTNOTIFY_NAME(string_handle_create)(name); } #endif + else + { +#if ITT_PLATFORM==ITT_PLATFORM_WIN + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#else + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#endif + return NULL; + } } - for (h_tail = NULL, h = _N_(_ittapi_global).string_list; h != NULL; h_tail = h, h = h->next) + if (__itt_is_collector_available()) { - if (h->strA != NULL && !__itt_fstrcmp(h->strA, name)) break; - } - if (h == NULL) - { - NEW_STRING_HANDLE_A(&_N_(_ittapi_global),h,h_tail,name); + for (h_tail = NULL, h = _N_(_ittapi_global).string_list; h != NULL; h_tail = h, h = h->next) + { + if (h->strA != NULL && !__itt_fstrcmp(h->strA, name)) break; + } + if (h == NULL) + { + NEW_STRING_HANDLE_A(&_N_(_ittapi_global), h, h_tail, name); + } } if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); return h; @@ -484,16 +574,24 @@ static __itt_counter ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(counter_createW),_init)) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); return ITTNOTIFY_NAME(counter_createW)(name, domain); } + else + { + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return NULL; + } } - for (h_tail = NULL, h = _N_(_ittapi_global).counter_list; h != NULL; h_tail = h, h = h->next) + if (__itt_is_collector_available()) { - if (h->nameW != NULL && h->type == type && !wcscmp(h->nameW, name) && ((h->domainW == NULL && domain == NULL) || - (h->domainW != NULL && domain != NULL && !wcscmp(h->domainW, domain)))) break; + for (h_tail = NULL, h = _N_(_ittapi_global).counter_list; h != NULL; h_tail = h, h = h->next) + { + if (h->nameW != NULL && h->type == (int)type && !wcscmp(h->nameW, name) && ((h->domainW == NULL && domain == NULL) || + (h->domainW != NULL && domain != NULL && !wcscmp(h->domainW, domain)))) break; - } - if (h == NULL) - { - NEW_COUNTER_W(&_N_(_ittapi_global),h,h_tail,name,domain,type); + } + if (h == NULL) + { + NEW_COUNTER_W(&_N_(_ittapi_global), h, h_tail, name, domain, type); + } } __itt_mutex_unlock(&_N_(_ittapi_global).mutex); return (__itt_counter)h; @@ -528,15 +626,27 @@ static __itt_counter ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(counter_create),_init))( return ITTNOTIFY_NAME(counter_create)(name, domain); } #endif + else + { +#if ITT_PLATFORM==ITT_PLATFORM_WIN + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#else + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#endif + return NULL; + } } - for (h_tail = NULL, h = _N_(_ittapi_global).counter_list; h != NULL; h_tail = h, h = h->next) + if (__itt_is_collector_available()) { - if (h->nameA != NULL && h->type == type && !__itt_fstrcmp(h->nameA, name) && ((h->domainA == NULL && domain == NULL) || - (h->domainA != NULL && domain != NULL && !__itt_fstrcmp(h->domainA, domain)))) break; - } - if (h == NULL) - { - NEW_COUNTER_A(&_N_(_ittapi_global),h,h_tail,name,domain,type); + for (h_tail = NULL, h = _N_(_ittapi_global).counter_list; h != NULL; h_tail = h, h = h->next) + { + if (h->nameA != NULL && h->type == (int)type && !__itt_fstrcmp(h->nameA, name) && ((h->domainA == NULL && domain == NULL) || + (h->domainA != NULL && domain != NULL && !__itt_fstrcmp(h->domainA, domain)))) break; + } + if (h == NULL) + { + NEW_COUNTER_A(&_N_(_ittapi_global), h, h_tail, name, domain, type); + } } if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); return (__itt_counter)h; @@ -560,16 +670,24 @@ static __itt_counter ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(counter_create_typedW),_ __itt_mutex_unlock(&_N_(_ittapi_global).mutex); return ITTNOTIFY_NAME(counter_create_typedW)(name, domain, type); } + else + { + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return NULL; + } } - for (h_tail = NULL, h = _N_(_ittapi_global).counter_list; h != NULL; h_tail = h, h = h->next) + if (__itt_is_collector_available()) { - if (h->nameW != NULL && h->type == type && !wcscmp(h->nameW, name) && ((h->domainW == NULL && domain == NULL) || - (h->domainW != NULL && domain != NULL && !wcscmp(h->domainW, domain)))) break; + for (h_tail = NULL, h = _N_(_ittapi_global).counter_list; h != NULL; h_tail = h, h = h->next) + { + if (h->nameW != NULL && h->type == (int)type && !wcscmp(h->nameW, name) && ((h->domainW == NULL && domain == NULL) || + (h->domainW != NULL && domain != NULL && !wcscmp(h->domainW, domain)))) break; - } - if (h == NULL) - { - NEW_COUNTER_W(&_N_(_ittapi_global),h,h_tail,name,domain,type); + } + if (h == NULL) + { + NEW_COUNTER_W(&_N_(_ittapi_global), h, h_tail, name, domain, type); + } } __itt_mutex_unlock(&_N_(_ittapi_global).mutex); return (__itt_counter)h; @@ -603,20 +721,290 @@ static __itt_counter ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(counter_create_typed),_i return ITTNOTIFY_NAME(counter_create_typed)(name, domain, type); } #endif + else + { +#if ITT_PLATFORM==ITT_PLATFORM_WIN + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#else + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#endif + return NULL; + } } - for (h_tail = NULL, h = _N_(_ittapi_global).counter_list; h != NULL; h_tail = h, h = h->next) + if (__itt_is_collector_available()) { - if (h->nameA != NULL && h->type == type && !__itt_fstrcmp(h->nameA, name) && ((h->domainA == NULL && domain == NULL) || - (h->domainA != NULL && domain != NULL && !__itt_fstrcmp(h->domainA, domain)))) break; - } - if (h == NULL) - { - NEW_COUNTER_A(&_N_(_ittapi_global),h,h_tail,name,domain,type); + for (h_tail = NULL, h = _N_(_ittapi_global).counter_list; h != NULL; h_tail = h, h = h->next) + { + if (h->nameA != NULL && h->type == (int)type && !__itt_fstrcmp(h->nameA, name) && ((h->domainA == NULL && domain == NULL) || + (h->domainA != NULL && domain != NULL && !__itt_fstrcmp(h->domainA, domain)))) break; + } + if (h == NULL) + { + NEW_COUNTER_A(&_N_(_ittapi_global), h, h_tail, name, domain, type); + } } if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); return (__itt_counter)h; } +#if ITT_PLATFORM==ITT_PLATFORM_WIN +static __itt_histogram* ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(histogram_createW),_init))(const __itt_domain* domain, const wchar_t* name, __itt_metadata_type x_type, __itt_metadata_type y_type) +{ + __itt_histogram *h_tail = NULL, *h = NULL; + + if (domain == NULL || name == NULL) + { + return NULL; + } + + ITT_MUTEX_INIT_AND_LOCK(_N_(_ittapi_global)); + if (_N_(_ittapi_global).api_initialized) + { + if (ITTNOTIFY_NAME(histogram_createW) && ITTNOTIFY_NAME(histogram_createW) != ITT_VERSIONIZE(ITT_JOIN(_N_(histogram_createW),_init))) + { + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return ITTNOTIFY_NAME(histogram_createW)(domain, name, x_type, y_type); + } + else + { + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return NULL; + } + } + if (__itt_is_collector_available()) + { + for (h_tail = NULL, h = _N_(_ittapi_global).histogram_list; h != NULL; h_tail = h, h = h->next) + { + if (h->domain == NULL) continue; + else if (h->domain == domain && h->nameW != NULL && !wcscmp(h->nameW, name)) break; + } + if (h == NULL) + { + NEW_HISTOGRAM_W(&_N_(_ittapi_global), h, h_tail, domain, name, x_type, y_type); + } + } + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return (__itt_histogram*)h; +} + +static __itt_histogram* ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(histogram_createA),_init))(const __itt_domain* domain, const char* name, __itt_metadata_type x_type, __itt_metadata_type y_type) +#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */ +static __itt_histogram* ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(histogram_create),_init))(const __itt_domain* domain, const char* name, __itt_metadata_type x_type, __itt_metadata_type y_type) +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +{ + __itt_histogram *h_tail = NULL, *h = NULL; + + if (domain == NULL || name == NULL) + { + return NULL; + } + + ITT_MUTEX_INIT_AND_LOCK(_N_(_ittapi_global)); + if (_N_(_ittapi_global).api_initialized) + { +#if ITT_PLATFORM==ITT_PLATFORM_WIN + if (ITTNOTIFY_NAME(histogram_createA) && ITTNOTIFY_NAME(histogram_createA) != ITT_VERSIONIZE(ITT_JOIN(_N_(histogram_createA),_init))) + { + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return ITTNOTIFY_NAME(histogram_createA)(domain, name, x_type, y_type); + } +#else + if (ITTNOTIFY_NAME(histogram_create) && ITTNOTIFY_NAME(histogram_create) != ITT_VERSIONIZE(ITT_JOIN(_N_(histogram_create),_init))) + { + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return ITTNOTIFY_NAME(histogram_create)(domain, name, x_type, y_type); + } +#endif + else + { +#if ITT_PLATFORM==ITT_PLATFORM_WIN + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#else + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#endif + return NULL; + } + } + if (__itt_is_collector_available()) + { + for (h_tail = NULL, h = _N_(_ittapi_global).histogram_list; h != NULL; h_tail = h, h = h->next) + { + if (h->domain == NULL) continue; + else if (h->domain == domain && h->nameA != NULL && !__itt_fstrcmp(h->nameA, name)) break; + } + if (h == NULL) + { + NEW_HISTOGRAM_A(&_N_(_ittapi_global), h, h_tail, domain, name, x_type, y_type); + } + } + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return (__itt_histogram*)h; +} + +#if ITT_PLATFORM==ITT_PLATFORM_WIN +static __itt_counter ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(counter_createW_v3),_init))(const __itt_domain* domain, const wchar_t* name, __itt_metadata_type type) +{ + __itt_counter_info_t *h_tail = NULL, *h = NULL; + + if (name == NULL || domain == NULL) + { + return NULL; + } + + ITT_MUTEX_INIT_AND_LOCK(_N_(_ittapi_global)); + if (_N_(_ittapi_global).api_initialized) + { + if (ITTNOTIFY_NAME(counter_createW_v3) && ITTNOTIFY_NAME(counter_createW_v3) != ITT_VERSIONIZE(ITT_JOIN(_N_(counter_createW_v3),_init))) + { + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return ITTNOTIFY_NAME(counter_createW_v3)(domain, name, type); + } + else + { + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return NULL; + } + } + if (__itt_is_collector_available()) + { + for (h_tail = NULL, h = _N_(_ittapi_global).counter_list; h != NULL; h_tail = h, h = h->next) + { + if (h->nameW != NULL && h->type == (int)type && !wcscmp(h->nameW, name) && ((h->domainW == NULL && domain->nameW == NULL) || + (h->domainW != NULL && domain->nameW != NULL && !wcscmp(h->domainW, domain->nameW)))) break; + + } + if (h == NULL) + { + NEW_COUNTER_W(&_N_(_ittapi_global),h,h_tail,name,domain->nameW,type); + } + } + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return (__itt_counter)h; +} + +static __itt_counter ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(counter_createA_v3),_init))(const __itt_domain* domain, const char* name, __itt_metadata_type type) +#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */ +static __itt_counter ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(counter_create_v3),_init))(const __itt_domain* domain, const char* name, __itt_metadata_type type) +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +{ + __itt_counter_info_t *h_tail = NULL, *h = NULL; + + if (name == NULL || domain == NULL) + { + return NULL; + } + + ITT_MUTEX_INIT_AND_LOCK(_N_(_ittapi_global)); + if (_N_(_ittapi_global).api_initialized) + { +#if ITT_PLATFORM==ITT_PLATFORM_WIN + if (ITTNOTIFY_NAME(counter_createA_v3) && ITTNOTIFY_NAME(counter_createA_v3) != ITT_VERSIONIZE(ITT_JOIN(_N_(counter_createA_v3),_init))) + { + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return ITTNOTIFY_NAME(counter_createA_v3)(domain, name, type); + } +#else + if (ITTNOTIFY_NAME(counter_create_v3) && ITTNOTIFY_NAME(counter_create_v3) != ITT_VERSIONIZE(ITT_JOIN(_N_(counter_create_v3),_init))) + { + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return ITTNOTIFY_NAME(counter_create_v3)(domain, name, type); + } +#endif + else + { +#if ITT_PLATFORM==ITT_PLATFORM_WIN + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#else + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#endif + return NULL; + } + } + if (__itt_is_collector_available()) + { + for (h_tail = NULL, h = _N_(_ittapi_global).counter_list; h != NULL; h_tail = h, h = h->next) + { + if (h->nameA != NULL && h->type == (int)type && !__itt_fstrcmp(h->nameA, name) && ((h->domainA == NULL && domain->nameA == NULL) || + (h->domainA != NULL && domain->nameA != NULL && !__itt_fstrcmp(h->domainA, domain->nameA)))) break; + } + if (h == NULL) + { + NEW_COUNTER_A(&_N_(_ittapi_global),h,h_tail,name,domain->nameA,type); + } + } + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return (__itt_counter)h; +} + +static void ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(bind_context_metadata_to_counter),_init))(__itt_counter counter, size_t length, __itt_context_metadata* metadata) +{ + __itt_counter_metadata *h_tail = NULL, *h = NULL; + + if (counter == NULL || length == 0 || metadata == NULL) + { + return; + } + + ITT_MUTEX_INIT_AND_LOCK(_N_(_ittapi_global)); + if (_N_(_ittapi_global).api_initialized) + { + if (ITTNOTIFY_NAME(bind_context_metadata_to_counter) && ITTNOTIFY_NAME(bind_context_metadata_to_counter) != ITT_VERSIONIZE(ITT_JOIN(_N_(bind_context_metadata_to_counter),_init))) + { + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + ITTNOTIFY_NAME(bind_context_metadata_to_counter)(counter, length, metadata); + } + else + { +#if ITT_PLATFORM==ITT_PLATFORM_WIN + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#else + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +#endif + return; + } + } + if (__itt_is_collector_available()) + { + size_t item; + char* str_valueA = NULL; +#if ITT_PLATFORM==ITT_PLATFORM_WIN + wchar_t* str_valueW = NULL; +#endif + unsigned long long value = 0; + __itt_context_type type = __itt_context_unknown; + + for (item = 0; item < length; item++) + { + type = metadata[item].type; + for (h_tail = NULL, h = _N_(_ittapi_global).counter_metadata_list; h != NULL; h_tail = h, h = h->next) + { + if (h->counter != NULL && h->counter == counter && h->type == type) break; + } + if (h == NULL && counter != NULL && type != __itt_context_unknown) + { + if (type == __itt_context_nameA || type == __itt_context_deviceA || type == __itt_context_unitsA || type == __itt_context_pci_addrA) + { + str_valueA = (char*)(metadata[item].value); + NEW_COUNTER_METADATA_STR_A(&_N_(_ittapi_global),h,h_tail,counter,type,str_valueA); + } +#if ITT_PLATFORM==ITT_PLATFORM_WIN + else if (type == __itt_context_nameW || type == __itt_context_deviceW || type == __itt_context_unitsW || type == __itt_context_pci_addrW) + { + str_valueW = (wchar_t*)(metadata[item].value); + NEW_COUNTER_METADATA_STR_W(&_N_(_ittapi_global),h,h_tail,counter,type,str_valueW); + } +#endif + else if (type >= __itt_context_tid && type <= __itt_context_cpu_cycles_flag) + { + value = *(unsigned long long*)(metadata[item].value); + NEW_COUNTER_METADATA_NUM(&_N_(_ittapi_global),h,h_tail,counter,type,value); + } + } + } + } + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); +} + /* -------------------------------------------------------------------------- */ static void ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(pause),_init))(void) @@ -629,10 +1017,6 @@ static void ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(pause),_init))(void) { ITTNOTIFY_NAME(pause)(); } - else - { - _N_(_ittapi_global).state = __itt_collection_paused; - } } static void ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(resume),_init))(void) @@ -645,9 +1029,29 @@ static void ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(resume),_init))(void) { ITTNOTIFY_NAME(resume)(); } - else +} + +static void ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(pause_scoped),_init))(__itt_collection_scope scope) +{ + if (!_N_(_ittapi_global).api_initialized && _N_(_ittapi_global).thread_list == NULL) { - _N_(_ittapi_global).state = __itt_collection_normal; + __itt_init_ittlib_name(NULL, __itt_group_all); + } + if (ITTNOTIFY_NAME(pause_scoped) && ITTNOTIFY_NAME(pause_scoped) != ITT_VERSIONIZE(ITT_JOIN(_N_(pause_scoped),_init))) + { + ITTNOTIFY_NAME(pause_scoped)(scope); + } +} + +static void ITTAPI ITT_VERSIONIZE(ITT_JOIN(_N_(resume_scoped),_init))(__itt_collection_scope scope) +{ + if (!_N_(_ittapi_global).api_initialized && _N_(_ittapi_global).thread_list == NULL) + { + __itt_init_ittlib_name(NULL, __itt_group_all); + } + if (ITTNOTIFY_NAME(resume_scoped) && ITTNOTIFY_NAME(resume_scoped) != ITT_VERSIONIZE(ITT_JOIN(_N_(resume_scoped),_init))) + { + ITTNOTIFY_NAME(resume_scoped)(scope); } } @@ -797,7 +1201,7 @@ static const char* __itt_fsplit(const char* s, const char* sep, const char** out /* This function return value of env variable that placed into static buffer. * !!! The same static buffer is used for subsequent calls. !!! - * This was done to aviod dynamic allocation for few calls. + * This was done to avoid dynamic allocation for few calls. * Actually we need this function only four times. */ static const char* __itt_get_env_var(const char* name) @@ -821,7 +1225,7 @@ static const char* __itt_get_env_var(const char* name) } else { - /* If environment variable is empty, GetEnvirornmentVariables() + /* If environment variable is empty, GetEnvironmentVariables() * returns zero (number of characters (not including terminating null), * and GetLastError() returns ERROR_SUCCESS. */ DWORD err = GetLastError(); @@ -854,129 +1258,15 @@ static const char* __itt_get_env_var(const char* name) static const char* __itt_get_lib_name(void) { const char* lib_name = __itt_get_env_var(ITT_TO_STR(LIB_VAR_NAME)); - -#ifdef __ANDROID__ - if (lib_name == NULL) - { - -#if ITT_ARCH==ITT_ARCH_IA32 || ITT_ARCH==ITT_ARCH_ARM - const char* const marker_filename = "com.intel.itt.collector_lib_32"; -#else - const char* const marker_filename = "com.intel.itt.collector_lib_64"; -#endif - - char system_wide_marker_filename[PATH_MAX] = {0}; - int itt_marker_file_fd = -1; - ssize_t res = 0; - - res = snprintf(system_wide_marker_filename, PATH_MAX - 1, "%s%s", "/data/local/tmp/", marker_filename); - if (res < 0) - { - ITT_ANDROID_LOGE("Unable to concatenate marker file string."); - return lib_name; - } - itt_marker_file_fd = open(system_wide_marker_filename, O_RDONLY); - - if (itt_marker_file_fd == -1) - { - const pid_t my_pid = getpid(); - char cmdline_path[PATH_MAX] = {0}; - char package_name[PATH_MAX] = {0}; - char app_sandbox_file[PATH_MAX] = {0}; - int cmdline_fd = 0; - - ITT_ANDROID_LOGI("Unable to open system-wide marker file."); - res = snprintf(cmdline_path, PATH_MAX - 1, "/proc/%d/cmdline", my_pid); - if (res < 0) - { - ITT_ANDROID_LOGE("Unable to get cmdline path string."); - return lib_name; - } - - ITT_ANDROID_LOGI("CMD file: %s\n", cmdline_path); - cmdline_fd = open(cmdline_path, O_RDONLY); - if (cmdline_fd == -1) - { - ITT_ANDROID_LOGE("Unable to open %s file!", cmdline_path); - return lib_name; - } - res = read(cmdline_fd, package_name, PATH_MAX - 1); - if (res == -1) - { - ITT_ANDROID_LOGE("Unable to read %s file!", cmdline_path); - res = close(cmdline_fd); - if (res == -1) - { - ITT_ANDROID_LOGE("Unable to close %s file!", cmdline_path); - } - return lib_name; - } - res = close(cmdline_fd); - if (res == -1) - { - ITT_ANDROID_LOGE("Unable to close %s file!", cmdline_path); - return lib_name; - } - ITT_ANDROID_LOGI("Package name: %s\n", package_name); - res = snprintf(app_sandbox_file, PATH_MAX - 1, "/data/data/%s/%s", package_name, marker_filename); - if (res < 0) - { - ITT_ANDROID_LOGE("Unable to concatenate marker file string."); - return lib_name; - } - - ITT_ANDROID_LOGI("Lib marker file name: %s\n", app_sandbox_file); - itt_marker_file_fd = open(app_sandbox_file, O_RDONLY); - if (itt_marker_file_fd == -1) - { - ITT_ANDROID_LOGE("Unable to open app marker file!"); - return lib_name; - } - } - - { - char itt_lib_name[PATH_MAX] = {0}; - - res = read(itt_marker_file_fd, itt_lib_name, PATH_MAX - 1); - if (res == -1) - { - ITT_ANDROID_LOGE("Unable to read %s file!", itt_marker_file_fd); - res = close(itt_marker_file_fd); - if (res == -1) - { - ITT_ANDROID_LOGE("Unable to close %s file!", itt_marker_file_fd); - } - return lib_name; - } - ITT_ANDROID_LOGI("ITT Lib path: %s", itt_lib_name); - res = close(itt_marker_file_fd); - if (res == -1) - { - ITT_ANDROID_LOGE("Unable to close %s file!", itt_marker_file_fd); - return lib_name; - } - ITT_ANDROID_LOGI("Set env %s to %s", ITT_TO_STR(LIB_VAR_NAME), itt_lib_name); - res = setenv(ITT_TO_STR(LIB_VAR_NAME), itt_lib_name, 0); - if (res == -1) - { - ITT_ANDROID_LOGE("Unable to set env var!"); - return lib_name; - } - lib_name = __itt_get_env_var(ITT_TO_STR(LIB_VAR_NAME)); - ITT_ANDROID_LOGI("ITT Lib path from env: %s", lib_name); - } - } -#endif - return lib_name; } -/* Avoid clashes with std::min, reported by tbb team */ -#define __itt_min(a,b) (a) < (b) ? (a) : (b) +/* Avoid clashes with std::min */ +#define __itt_min(a,b) ((a) < (b) ? (a) : (b)) static __itt_group_id __itt_get_groups(void) { - register int i; + int i; __itt_group_id res = __itt_group_none; const char* var_name = "INTEL_ITTNOTIFY_GROUPS"; const char* group_str = __itt_get_env_var(var_name); @@ -1046,16 +1336,33 @@ static void __itt_reinit_all_pointers(void) static void __itt_nullify_all_pointers(void) { - register int i; + int i; /* Nulify all pointers except domain_create, string_handle_create and counter_create */ for (i = 0; _N_(_ittapi_global).api_list_ptr[i].name != NULL; i++) *_N_(_ittapi_global).api_list_ptr[i].func_ptr = _N_(_ittapi_global).api_list_ptr[i].null_func; } +static int __itt_is_collector_available(void) +{ + int is_available; + + ITT_MUTEX_INIT_AND_LOCK(_N_(_ittapi_global)); + if (_N_(_ittapi_global).state == __itt_collection_uninitialized) + { + _N_(_ittapi_global).state = (NULL == __itt_get_lib_name()) ? __itt_collection_collector_absent : __itt_collection_collector_exists; + } + is_available = (_N_(_ittapi_global).state == __itt_collection_collector_exists || + _N_(_ittapi_global).state == __itt_collection_init_successful); + __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + return is_available; +} + #if ITT_PLATFORM==ITT_PLATFORM_WIN +#if _MSC_VER #pragma warning(push) #pragma warning(disable: 4054) /* warning C4054: 'type cast' : from function pointer 'XXX' to data pointer 'void *' */ #pragma warning(disable: 4055) /* warning C4055: 'type cast' : from data pointer 'void *' to function pointer 'XXX' */ +#endif #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ ITT_EXTERN_C void _N_(fini_ittlib)(void) @@ -1095,9 +1402,80 @@ ITT_EXTERN_C void _N_(fini_ittlib)(void) } } +/* !!! this function should be called under mutex lock !!! */ +static void __itt_free_allocated_resources(void) +{ + __itt_string_handle* current_string = _N_(_ittapi_global).string_list; + while (current_string != NULL) + { + __itt_string_handle* tmp = current_string->next; + free((char*)current_string->strA); +#if ITT_PLATFORM==ITT_PLATFORM_WIN + free((wchar_t*)current_string->strW); +#endif + free(current_string); + current_string = tmp; + } + _N_(_ittapi_global).string_list = NULL; + + __itt_domain* current_domain = _N_(_ittapi_global).domain_list; + while (current_domain != NULL) + { + __itt_domain* tmp = current_domain->next; + free((char*)current_domain->nameA); +#if ITT_PLATFORM==ITT_PLATFORM_WIN + free((wchar_t*)current_domain->nameW); +#endif + free(current_domain); + current_domain = tmp; + } + _N_(_ittapi_global).domain_list = NULL; + + __itt_counter_info_t* current_couter = _N_(_ittapi_global).counter_list; + while (current_couter != NULL) + { + __itt_counter_info_t* tmp = current_couter->next; + free((char*)current_couter->nameA); + free((char*)current_couter->domainA); +#if ITT_PLATFORM==ITT_PLATFORM_WIN + free((wchar_t*)current_couter->nameW); + free((wchar_t*)current_couter->domainW); +#endif + free(current_couter); + current_couter = tmp; + } + _N_(_ittapi_global).counter_list = NULL; + + __itt_histogram* current_histogram = _N_(_ittapi_global).histogram_list; + while (current_histogram != NULL) + { + __itt_histogram* tmp = current_histogram->next; + free((char*)current_histogram->nameA); +#if ITT_PLATFORM==ITT_PLATFORM_WIN + free((wchar_t*)current_histogram->nameW); +#endif + free(current_histogram); + current_histogram = tmp; + } + _N_(_ittapi_global).histogram_list = NULL; + + __itt_counter_metadata* current_counter_metadata = _N_(_ittapi_global).counter_metadata_list; + while (current_counter_metadata != NULL) + { + __itt_counter_metadata* tmp = current_counter_metadata->next; + free((char*)current_counter_metadata->str_valueA); +#if ITT_PLATFORM==ITT_PLATFORM_WIN + free((wchar_t*)current_counter_metadata->str_valueW); +#endif + free(current_counter_metadata); + current_counter_metadata = tmp; + } + _N_(_ittapi_global).counter_metadata_list = NULL; +} + ITT_EXTERN_C int _N_(init_ittlib)(const char* lib_name, __itt_group_id init_groups) { - register int i; + int i; __itt_group_id groups; #ifdef ITT_COMPLETE_GROUP __itt_group_id zero_group = __itt_group_none; @@ -1126,12 +1504,15 @@ ITT_EXTERN_C int _N_(init_ittlib)(const char* lib_name, __itt_group_id init_grou if (_N_(_ittapi_global).lib != NULL) { + _N_(_ittapi_global).state = __itt_collection_init_successful; __itt_api_init_t* __itt_api_init_ptr; int lib_version = __itt_lib_version(_N_(_ittapi_global).lib); - switch (lib_version) { + switch (lib_version) + { case 0: groups = __itt_group_legacy; + ITT_ATTRIBUTE_FALLTHROUGH; case 1: /* Fill all pointers from dynamic library */ for (i = 0; _N_(_ittapi_global).api_list_ptr[i].name != NULL; i++) @@ -1184,6 +1565,8 @@ ITT_EXTERN_C int _N_(init_ittlib)(const char* lib_name, __itt_group_id init_grou } else { + _N_(_ittapi_global).state = __itt_collection_init_fail; + __itt_free_allocated_resources(); __itt_nullify_all_pointers(); __itt_report_error(__itt_error_no_module, lib_name, @@ -1197,6 +1580,7 @@ ITT_EXTERN_C int _N_(init_ittlib)(const char* lib_name, __itt_group_id init_grou } else { + _N_(_ittapi_global).state = __itt_collection_collector_absent; __itt_nullify_all_pointers(); } _N_(_ittapi_global).api_initialized = 1; @@ -1231,6 +1615,69 @@ ITT_EXTERN_C __itt_error_handler_t* _N_(set_error_handler)(__itt_error_handler_t } #if ITT_PLATFORM==ITT_PLATFORM_WIN +#if _MSC_VER #pragma warning(pop) +#endif #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +/** __itt_mark_pt_region functions marks region of interest + * region parameter defines different regions. + * 0 <= region < 8 */ + +#if defined(ITT_API_IPT_SUPPORT) && (ITT_PLATFORM==ITT_PLATFORM_WIN || ITT_PLATFORM==ITT_PLATFORM_POSIX) && !defined(__ANDROID__) +void __itt_pt_mark(__itt_pt_region region); +void __itt_pt_mark_event(__itt_pt_region region); +#endif + +ITT_EXTERN_C void _N_(mark_pt_region_begin)(__itt_pt_region region) +{ +#if defined(ITT_API_IPT_SUPPORT) && (ITT_PLATFORM==ITT_PLATFORM_WIN || ITT_PLATFORM==ITT_PLATFORM_POSIX) && !defined(__ANDROID__) + if (_N_(_ittapi_global).ipt_collect_events == 1) + { + __itt_pt_mark_event(2*region); + } + else + { + __itt_pt_mark(2*region); + } +#else + (void)region; +#endif +} + +ITT_EXTERN_C void _N_(mark_pt_region_end)(__itt_pt_region region) +{ +#if defined(ITT_API_IPT_SUPPORT) && (ITT_PLATFORM==ITT_PLATFORM_WIN || ITT_PLATFORM==ITT_PLATFORM_POSIX) && !defined(__ANDROID__) + if (_N_(_ittapi_global).ipt_collect_events == 1) + { + __itt_pt_mark_event(2*region + 1); + } + else + { + __itt_pt_mark(2*region + 1); + } +#else + (void)region; +#endif +} + +ITT_EXTERN_C __itt_collection_state (_N_(get_collection_state))(void) +{ + if (!_N_(_ittapi_global).api_initialized && _N_(_ittapi_global).thread_list == NULL) + { + __itt_init_ittlib_name(NULL, __itt_group_all); + } + return _N_(_ittapi_global).state; +} + +/* !!! should be called from the library destructor !!! + * this function destroys the mutex and frees resources + * allocated by ITT API static part + */ +ITT_EXTERN_C void (_N_(release_resources))(void) +{ + ITT_MUTEX_INIT_AND_LOCK(_N_(_ittapi_global)); + __itt_free_allocated_resources(); + if (PTHREAD_SYMBOLS) __itt_mutex_unlock(&_N_(_ittapi_global).mutex); + ITT_MUTEX_DESTROY(_N_(_ittapi_global)); +} diff --git a/3rdparty/ittnotify/src/ittnotify/ittnotify_static.h b/3rdparty/ittnotify/src/ittnotify/ittnotify_static.h index dd2e2e50e2..6072687239 100644 --- a/3rdparty/ittnotify/src/ittnotify/ittnotify_static.h +++ b/3rdparty/ittnotify/src/ittnotify/ittnotify_static.h @@ -1,60 +1,8 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. +/* + Copyright (C) 2005-2019 Intel Corporation - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +*/ #include "ittnotify_config.h" @@ -81,6 +29,9 @@ ITT_STUB(ITTAPI, __itt_domain*, domain_createW, (const wchar_t *name), (ITT_FORM ITT_STUB(ITTAPI, __itt_domain*, domain_create, (const char *name), (ITT_FORMAT name), domain_create, __itt_group_structure, "\"%s\"") #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +ITT_STUBV(ITTAPI, void, module_load_with_sections, (__itt_module_object* module_obj), (ITT_FORMAT module_obj), module_load_with_sections, __itt_group_module, "%p") +ITT_STUBV(ITTAPI, void, module_unload_with_sections, (__itt_module_object* module_obj), (ITT_FORMAT module_obj), module_unload_with_sections, __itt_group_module, "%p") + #if ITT_PLATFORM==ITT_PLATFORM_WIN ITT_STUB(ITTAPI, __itt_string_handle*, string_handle_createA, (const char *name), (ITT_FORMAT name), string_handle_createA, __itt_group_structure, "\"%s\"") ITT_STUB(ITTAPI, __itt_string_handle*, string_handle_createW, (const wchar_t *name), (ITT_FORMAT name), string_handle_createW, __itt_group_structure, "\"%S\"") @@ -105,6 +56,8 @@ ITT_STUB(ITTAPI, __itt_counter, counter_create_typed, (const char *name, con ITT_STUBV(ITTAPI, void, pause, (void), (ITT_NO_PARAMS), pause, __itt_group_control | __itt_group_legacy, "no args") ITT_STUBV(ITTAPI, void, resume, (void), (ITT_NO_PARAMS), resume, __itt_group_control | __itt_group_legacy, "no args") +ITT_STUBV(ITTAPI, void, pause_scoped, (__itt_collection_scope scope), (ITT_FORMAT scope), pause_scoped, __itt_group_control, "%d") +ITT_STUBV(ITTAPI, void, resume_scoped, (__itt_collection_scope scope), (ITT_FORMAT scope), resume_scoped, __itt_group_control, "%d") #if ITT_PLATFORM==ITT_PLATFORM_WIN ITT_STUBV(ITTAPI, void, thread_set_nameA, (const char *name), (ITT_FORMAT name), thread_set_nameA, __itt_group_thread, "\"%s\"") @@ -121,6 +74,23 @@ ITT_STUB(LIBITTAPI, int, thr_name_setW, (const wchar_t *name, int namelen), (IT ITT_STUB(LIBITTAPI, int, thr_name_set, (const char *name, int namelen), (ITT_FORMAT name, namelen), thr_name_set, __itt_group_thread | __itt_group_legacy, "\"%s\", %d") #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ ITT_STUBV(LIBITTAPI, void, thr_ignore, (void), (ITT_NO_PARAMS), thr_ignore, __itt_group_thread | __itt_group_legacy, "no args") + +#if ITT_PLATFORM==ITT_PLATFORM_WIN +ITT_STUB(ITTAPI, __itt_histogram*, histogram_createA, (const __itt_domain* domain, const char* name, __itt_metadata_type x_type, __itt_metadata_type y_type), (ITT_FORMAT domain, name, x_type, y_type), histogram_createA, __itt_group_structure, "%p, \"%s\", %d, %d") +ITT_STUB(ITTAPI, __itt_histogram*, histogram_createW, (const __itt_domain* domain, const wchar_t* name, __itt_metadata_type x_type, __itt_metadata_type y_type), (ITT_FORMAT domain, name, x_type, y_type), histogram_createW, __itt_group_structure, "%p, \"%s\", %d, %d") +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +ITT_STUB(ITTAPI, __itt_histogram*, histogram_create, (const __itt_domain* domain, const char* name, __itt_metadata_type x_type, __itt_metadata_type y_type), (ITT_FORMAT domain, name, x_type, y_type), histogram_create, __itt_group_structure, "%p, \"%s\", %d, %d") +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ + +#if ITT_PLATFORM==ITT_PLATFORM_WIN +ITT_STUB(ITTAPI, __itt_counter, counter_createA_v3, (const __itt_domain* domain, const char *name, __itt_metadata_type type), (ITT_FORMAT domain, name, type), counter_createA_v3, __itt_group_counter, "%p, \"%s\", %d") +ITT_STUB(ITTAPI, __itt_counter, counter_createW_v3, (const __itt_domain* domain, const wchar_t *name, __itt_metadata_type type), (ITT_FORMAT domain, name, type), counter_createW_v3, __itt_group_counter, "%p, \"%s\", %d") +#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ +ITT_STUB(ITTAPI, __itt_counter, counter_create_v3, (const __itt_domain* domain, const char *name, __itt_metadata_type type), (ITT_FORMAT domain, name, type), counter_create_v3, __itt_group_counter, "%p, \"%s\", %d") +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ + +ITT_STUBV(ITTAPI, void, bind_context_metadata_to_counter, (__itt_counter counter, size_t length, __itt_context_metadata* metadata), (ITT_FORMAT counter, length, metadata), bind_context_metadata_to_counter, __itt_group_structure, "%p, %lu, %p") + #endif /* __ITT_INTERNAL_BODY */ ITT_STUBV(ITTAPI, void, enable_attach, (void), (ITT_NO_PARAMS), enable_attach, __itt_group_all, "no args") @@ -296,6 +266,13 @@ ITT_STUB(ITTAPI, __itt_frame, frame_createW, (const wchar_t *domain), (ITT_FORMA #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ ITT_STUB(ITTAPI, __itt_frame, frame_create, (const char *domain), (ITT_FORMAT domain), frame_create, __itt_group_frame, "\"%s\"") #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ + +#if ITT_PLATFORM==ITT_PLATFORM_WIN +ITT_STUB(ITTAPI, __itt_pt_region, pt_region_createA, (const char *name), (ITT_FORMAT name), pt_region_createA, __itt_group_structure, "\"%s\"") +ITT_STUB(ITTAPI, __itt_pt_region, pt_region_createW, (const wchar_t *name), (ITT_FORMAT name), pt_region_createW, __itt_group_structure, "\"%S\"") +#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */ +ITT_STUB(ITTAPI, __itt_pt_region, pt_region_create, (const char *name), (ITT_FORMAT name), pt_region_create, __itt_group_structure, "\"%s\"") +#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ #endif /* __ITT_INTERNAL_BODY */ ITT_STUBV(ITTAPI, void, frame_begin, (__itt_frame frame), (ITT_FORMAT frame), frame_begin, __itt_group_frame, "%p") ITT_STUBV(ITTAPI, void, frame_end, (__itt_frame frame), (ITT_FORMAT frame), frame_end, __itt_group_frame, "%p") @@ -376,14 +353,16 @@ ITT_STUB(ITTAPI, int, av_save, (void *data, int rank, const int *dimensions, in #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ #endif /* __ITT_INTERNAL_BODY */ -#ifndef __ITT_INTERNAL_BODY #if ITT_PLATFORM==ITT_PLATFORM_WIN -ITT_STUBV(ITTAPI, void, module_loadA, (void *start_addr, void* end_addr, const char *path), (ITT_FORMAT start_addr, end_addr, path), module_loadA, __itt_group_none, "%p, %p, %p") -ITT_STUBV(ITTAPI, void, module_loadW, (void *start_addr, void* end_addr, const wchar_t *path), (ITT_FORMAT start_addr, end_addr, path), module_loadW, __itt_group_none, "%p, %p, %p") +ITT_STUBV(ITTAPI, void, module_loadA, (void *start_addr, void* end_addr, const char *path), (ITT_FORMAT start_addr, end_addr, path), module_loadA, __itt_group_module, "%p, %p, %p") +ITT_STUBV(ITTAPI, void, module_loadW, (void *start_addr, void* end_addr, const wchar_t *path), (ITT_FORMAT start_addr, end_addr, path), module_loadW, __itt_group_module, "%p, %p, %p") #else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */ -ITT_STUBV(ITTAPI, void, module_load, (void *start_addr, void *end_addr, const char *path), (ITT_FORMAT start_addr, end_addr, path), module_load, __itt_group_none, "%p, %p, %p") +ITT_STUBV(ITTAPI, void, module_load, (void *start_addr, void *end_addr, const char *path), (ITT_FORMAT start_addr, end_addr, path), module_load, __itt_group_module, "%p, %p, %p") #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -#endif /* __ITT_INTERNAL_BODY */ +ITT_STUBV(ITTAPI, void, module_unload, (void *start_addr), (ITT_FORMAT start_addr), module_unload, __itt_group_module, "%p") +ITT_STUBV(ITTAPI, void, histogram_submit, (__itt_histogram* hist, size_t length, void* x_data, void* y_data), (ITT_FORMAT hist, length, x_data, y_data), histogram_submit, __itt_group_structure, "%p, %lu, %p, %p") + +ITT_STUBV(ITTAPI, void, counter_set_value_v3, (__itt_counter counter, void *value_ptr), (ITT_FORMAT counter, value_ptr), counter_set_value_v3, __itt_group_counter, "%p, %p") #endif /* __ITT_INTERNAL_INIT */ diff --git a/3rdparty/ittnotify/src/ittnotify/ittnotify_types.h b/3rdparty/ittnotify/src/ittnotify/ittnotify_types.h index e10250bd63..7346c8032f 100644 --- a/3rdparty/ittnotify/src/ittnotify/ittnotify_types.h +++ b/3rdparty/ittnotify/src/ittnotify/ittnotify_types.h @@ -1,85 +1,34 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. +/* + Copyright (C) 2005-2019 Intel Corporation - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +*/ #ifndef _ITTNOTIFY_TYPES_H_ #define _ITTNOTIFY_TYPES_H_ typedef enum ___itt_group_id { - __itt_group_none = 0, - __itt_group_legacy = 1<<0, - __itt_group_control = 1<<1, - __itt_group_thread = 1<<2, - __itt_group_mark = 1<<3, - __itt_group_sync = 1<<4, - __itt_group_fsync = 1<<5, - __itt_group_jit = 1<<6, - __itt_group_model = 1<<7, - __itt_group_splitter_min = 1<<7, - __itt_group_counter = 1<<8, - __itt_group_frame = 1<<9, - __itt_group_stitch = 1<<10, - __itt_group_heap = 1<<11, - __itt_group_splitter_max = 1<<12, - __itt_group_structure = 1<<12, - __itt_group_suppress = 1<<13, - __itt_group_arrays = 1<<14, - __itt_group_all = -1 + __itt_group_none = 0, + __itt_group_legacy = 1<<0, + __itt_group_control = 1<<1, + __itt_group_thread = 1<<2, + __itt_group_mark = 1<<3, + __itt_group_sync = 1<<4, + __itt_group_fsync = 1<<5, + __itt_group_jit = 1<<6, + __itt_group_model = 1<<7, + __itt_group_splitter_min = 1<<7, + __itt_group_counter = 1<<8, + __itt_group_frame = 1<<9, + __itt_group_stitch = 1<<10, + __itt_group_heap = 1<<11, + __itt_group_splitter_max = 1<<12, + __itt_group_structure = 1<<12, + __itt_group_suppress = 1<<13, + __itt_group_arrays = 1<<14, + __itt_group_module = 1<<15, + __itt_group_all = -1 } __itt_group_id; #pragma pack(push, 8) @@ -109,6 +58,7 @@ typedef struct ___itt_group_list { __itt_group_structure, "structure" }, \ { __itt_group_suppress, "suppress" }, \ { __itt_group_arrays, "arrays" }, \ + { __itt_group_module, "module" }, \ { __itt_group_none, NULL } \ } diff --git a/3rdparty/ittnotify/src/ittnotify/jitprofiling.c b/3rdparty/ittnotify/src/ittnotify/jitprofiling.c index f834bd834b..31a15ee267 100644 --- a/3rdparty/ittnotify/src/ittnotify/jitprofiling.c +++ b/3rdparty/ittnotify/src/ittnotify/jitprofiling.c @@ -1,76 +1,24 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. +/* + Copyright (C) 2005-2019 Intel Corporation - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +*/ #include "ittnotify_config.h" #if ITT_PLATFORM==ITT_PLATFORM_WIN #include +#include +#include #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -#if ITT_PLATFORM != ITT_PLATFORM_MAC && ITT_PLATFORM != ITT_PLATFORM_FREEBSD +#if ITT_PLATFORM != ITT_PLATFORM_MAC && ITT_PLATFORM != ITT_PLATFORM_FREEBSD && ITT_PLATFORM != ITT_PLATFORM_OPENBSD #include #endif #include #include "jitprofiling.h" -static const char rcsid[] = "\n@(#) $Revision: 471937 $\n"; - -#define DLL_ENVIRONMENT_VAR "VS_PROFILER" +static const char rcsid[] = "\n@(#) $Revision$\n"; #ifndef NEW_DLL_ENVIRONMENT_VAR #if ITT_ARCH==ITT_ARCH_IA32 @@ -81,13 +29,10 @@ static const char rcsid[] = "\n@(#) $Revision: 471937 $\n"; #endif /* NEW_DLL_ENVIRONMENT_VAR */ #if ITT_PLATFORM==ITT_PLATFORM_WIN -#define DEFAULT_DLLNAME "JitPI.dll" HINSTANCE m_libHandle = NULL; #elif ITT_PLATFORM==ITT_PLATFORM_MAC -#define DEFAULT_DLLNAME "libJitPI.dylib" void* m_libHandle = NULL; #else -#define DEFAULT_DLLNAME "libJitPI.so" void* m_libHandle = NULL; #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ @@ -169,6 +114,38 @@ ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive() return executionMode; } +#if ITT_PLATFORM == ITT_PLATFORM_WIN +static int isValidAbsolutePath(char *path, size_t maxPathLength) +{ + if (path == NULL) + { + return 0; + } + + size_t pathLength = strnlen(path, maxPathLength); + if (pathLength == maxPathLength) + { + /* The strnlen() function returns maxPathLength if there is no null terminating + * among the first maxPathLength characters in the string pointed to by path. + */ + return 0; + } + + if (pathLength > 2) + { + if (isalpha(path[0]) && path[1] == ':' && path[2] == '\\') + { + return 1; + } + else if (path[0] == '\\' && path[1] == '\\') + { + return 1; + } + } + return 0; +} +#endif + /* This function loads the collector dll and the relevant functions. * on success: all functions load, iJIT_DLL_is_missing = 0, return value = 1 * on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0 @@ -212,7 +189,7 @@ static int loadiJIT_Funcs() { envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, dllName, dNameLength); - if (envret) + if (envret && isValidAbsolutePath(dllName, dNameLength)) { /* Try to load the dll from the PATH... */ m_libHandle = LoadLibraryExA(dllName, @@ -220,30 +197,9 @@ static int loadiJIT_Funcs() } free(dllName); } - } else { - /* Try to use old VS_PROFILER variable */ - dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0); - if (dNameLength) - { - DWORD envret = 0; - dllName = (char*)malloc(sizeof(char) * (dNameLength + 1)); - if(dllName != NULL) - { - envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, - dllName, dNameLength); - if (envret) - { - /* Try to load the dll from the PATH... */ - m_libHandle = LoadLibraryA(dllName); - } - free(dllName); - } - } } #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ dllName = getenv(NEW_DLL_ENVIRONMENT_VAR); - if (!dllName) - dllName = getenv(DLL_ENVIRONMENT_VAR); #if defined(__ANDROID__) || defined(ANDROID) if (!dllName) dllName = ANDROID_JIT_AGENT_PATH; @@ -251,19 +207,13 @@ static int loadiJIT_Funcs() if (dllName) { /* Try to load the dll from the PATH... */ - m_libHandle = dlopen(dllName, RTLD_LAZY); + if (DL_SYMBOLS) + { + m_libHandle = dlopen(dllName, RTLD_LAZY); + } } #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - if (!m_libHandle) - { -#if ITT_PLATFORM==ITT_PLATFORM_WIN - m_libHandle = LoadLibraryA(DEFAULT_DLLNAME); -#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY); -#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - } - /* if the dll wasn't loaded - exit. */ if (!m_libHandle) { diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d30ecd818..155a8f1b2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -692,6 +692,9 @@ if(UNIX OR MINGW) # TODO: # - std::aligned_alloc() C++17 / C11 endif() + + CHECK_SYMBOL_EXISTS(getauxval sys/auxv.h HAVE_GETAUXVAL) + CHECK_SYMBOL_EXISTS(elf_aux_info sys/auxv.h HAVE_ELF_AUX_INFO) elseif(WIN32) include(CheckIncludeFile) include(CheckSymbolExists) @@ -1647,7 +1650,7 @@ endif() if(CV_TRACE OR OPENCV_TRACE) ocv_build_features_string(trace_status EXCLUSIVE - IF HAVE_ITT THEN "with Intel ITT" + IF HAVE_ITT THEN "with Intel ITT(${ITTNOTIFY_VERSION})" ELSE "built-in") status("") status(" Trace: " OPENCV_TRACE THEN "YES (${trace_status})" ELSE NO) diff --git a/cmake/OpenCVDetectCUDAUtils.cmake b/cmake/OpenCVDetectCUDAUtils.cmake index 72f98de27e..ba08804f89 100644 --- a/cmake/OpenCVDetectCUDAUtils.cmake +++ b/cmake/OpenCVDetectCUDAUtils.cmake @@ -95,7 +95,7 @@ endfunction() macro(ocv_initialize_nvidia_device_generations) OCV_OPTION(CUDA_ENABLE_DEPRECATED_GENERATION "Enable deprecated generations in the list" OFF) - set(_generations "Maxwell" "Pascal" "Volta" "Turing" "Ampere" "Lovelace" "Hopper") + set(_generations "Maxwell" "Pascal" "Volta" "Turing" "Ampere" "Lovelace" "Hopper" "Blackwell") if(CUDA_ENABLE_DEPRECATED_GENERATION) set(_generations "Fermi" "${_generations}") set(_generations "Kepler" "${_generations}") @@ -109,6 +109,7 @@ macro(ocv_initialize_nvidia_device_generations) set(_arch_ampere "8.0;8.6") set(_arch_lovelace "8.9") set(_arch_hopper "9.0") + set(_arch_blackwell "10.0;12.0") if(NOT CMAKE_CROSSCOMPILING) list(APPEND _generations "Auto") endif() @@ -244,6 +245,8 @@ macro(ocv_set_cuda_arch_bin_and_ptx nvcc_executable) set(__cuda_arch_bin ${_arch_lovelace}) elseif(CUDA_GENERATION STREQUAL "Hopper") set(__cuda_arch_bin ${_arch_hopper}) + elseif(CUDA_GENERATION STREQUAL "Blackwell") + set(__cuda_arch_bin ${_arch_blackwell}) elseif(CUDA_GENERATION STREQUAL "Auto") ocv_detect_native_cuda_arch(${nvcc_executable} _nvcc_res _nvcc_out) if(NOT _nvcc_res EQUAL 0) @@ -268,13 +271,14 @@ macro(ocv_set_cuda_arch_bin_and_ptx nvcc_executable) endif() if(NOT _nvcc_res EQUAL 0) message(STATUS "CUDA: Automatic detection of CUDA generation failed. Going to build for all known architectures") - # TX1 (5.3) TX2 (6.2) Xavier (7.2) V100 (7.0) Orin (8.7) + # TX1 (5.3) TX2 (6.2) Xavier (7.2) V100 (7.0) Orin (8.7) Thor (10.1) ocv_filter_available_architecture(${nvcc_executable} __cuda_arch_bin 5.3 6.2 7.2 7.0 8.7 + 10.1 ) else() set(__cuda_arch_bin "${_nvcc_out}") @@ -291,6 +295,7 @@ macro(ocv_set_cuda_arch_bin_and_ptx nvcc_executable) ${_arch_ampere} ${_arch_lovelace} ${_arch_hopper} + ${_arch_blackwell} ) list(GET __cuda_arch_bin -1 __cuda_arch_ptx) endif() @@ -303,12 +308,12 @@ macro(ocv_set_cuda_arch_bin_and_ptx nvcc_executable) # Check if user specified 1.0/2.1 compute capability: we don't support it macro(ocv_wipeout_deprecated_cc target_cc) - if(" ${CUDA_ARCH_BIN} ${CUDA_ARCH_PTX}" MATCHES " ${target_cc}") + if(${target_cc} IN_LIST ARCH_BIN_NO_POINTS OR ${target_cc} IN_LIST ARCH_PTX_NO_POINTS) message(SEND_ERROR "CUDA: ${target_cc} compute capability is not supported - exclude it from ARCH/PTX list and re-run CMake") endif() endmacro() - ocv_wipeout_deprecated_cc("1.0") - ocv_wipeout_deprecated_cc("2.1") + ocv_wipeout_deprecated_cc("10") + ocv_wipeout_deprecated_cc("21") endmacro() macro(ocv_set_nvcc_threads_for_vs) diff --git a/cmake/OpenCVFindAVIF.cmake b/cmake/OpenCVFindAVIF.cmake index 26195a7769..8f9358d70d 100644 --- a/cmake/OpenCVFindAVIF.cmake +++ b/cmake/OpenCVFindAVIF.cmake @@ -19,7 +19,7 @@ if(TARGET avif) MARK_AS_ADVANCED(AVIF_LIBRARY) SET(AVIF_FOUND TRUE) - GET_TARGET_PROPERTY(AVIF_LIBRARY avif LOCATION) + SET(AVIF_LIBRARY avif) GET_TARGET_PROPERTY(AVIF_INCLUDE_DIR1 avif INCLUDE_DIRECTORIES) GET_TARGET_PROPERTY(AVIF_INCLUDE_DIR2 avif INTERFACE_INCLUDE_DIRECTORIES) set(AVIF_INCLUDE_DIR) diff --git a/cmake/OpenCVFindLibsPerf.cmake b/cmake/OpenCVFindLibsPerf.cmake index a72d9976f8..f1822bb6ed 100644 --- a/cmake/OpenCVFindLibsPerf.cmake +++ b/cmake/OpenCVFindLibsPerf.cmake @@ -179,7 +179,14 @@ endif(WITH_KLEIDICV) if(WITH_FASTCV) if((EXISTS ${FastCV_INCLUDE_PATH}) AND (EXISTS ${FastCV_LIB_PATH})) message(STATUS "Use external FastCV ${FastCV_INCLUDE_PATH}, ${FastCV_LIB_PATH}") - set(HAVE_FASTCV TRUE CACHE BOOL "FastCV status") + find_library(FASTCV_LIBRARY NAMES "fastcv" + PATHS "${FastCV_LIB_PATH}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) + mark_as_advanced(FASTCV_LIBRARY) + if (FASTCV_LIBRARY) + set(HAVE_FASTCV TRUE CACHE BOOL "FastCV status") + else() + set(HAVE_FASTCV FALSE CACHE BOOL "FastCV status") + endif() else() include("${OpenCV_SOURCE_DIR}/3rdparty/fastcv/fastcv.cmake") set(FCV_ROOT_DIR "${OpenCV_BINARY_DIR}/3rdparty/fastcv") @@ -188,13 +195,15 @@ if(WITH_FASTCV) set(FastCV_INCLUDE_PATH "${FCV_ROOT_DIR}/inc" CACHE PATH "FastCV includes directory") set(FastCV_LIB_PATH "${FCV_ROOT_DIR}/libs" CACHE PATH "FastCV library directory") ocv_install_3rdparty_licenses(FastCV "${OpenCV_BINARY_DIR}/3rdparty/fastcv/LICENSE") - install(FILES "${FastCV_LIB_PATH}/libfastcvopt.so" - DESTINATION "${OPENCV_LIB_INSTALL_PATH}" COMPONENT "bin") + if(ANDROID) + set(FASTCV_LIBRARY "${FastCV_LIB_PATH}/libfastcvopt.so" CACHE PATH "FastCV library") + install(FILES "${FASTCV_LIBRARY}" DESTINATION "${OPENCV_LIB_INSTALL_PATH}" COMPONENT "bin") + else() + set(FASTCV_LIBRARY "${FastCV_LIB_PATH}/libfastcv.a" CACHE PATH "FastCV library") + install(FILES "${FASTCV_LIBRARY}" DESTINATION "${OPENCV_LIB_INSTALL_PATH}" COMPONENT "dev") + endif() else() set(HAVE_FASTCV FALSE CACHE BOOL "FastCV status") endif() endif() - if(HAVE_FASTCV) - set(FASTCV_LIBRARY "${FastCV_LIB_PATH}/libfastcvopt.so" CACHE PATH "FastCV library") - endif() endif(WITH_FASTCV) diff --git a/cmake/OpenCVFindOpenEXR.cmake b/cmake/OpenCVFindOpenEXR.cmake index 0df626a842..d2f3b57090 100644 --- a/cmake/OpenCVFindOpenEXR.cmake +++ b/cmake/OpenCVFindOpenEXR.cmake @@ -94,17 +94,20 @@ FOREACH(SEARCH_PATH ${SEARCH_PATHS}) IF (${contents} MATCHES "#define OPENEXR_VERSION_MINOR ([0-9]+)") SET(OPENEXR_VERSION_MINOR "${CMAKE_MATCH_1}") ENDIF () + FILE (STRINGS ${OPENEXR_VERSION_FILE} contents REGEX "#define OPENEXR_VERSION_PATCH ") + IF (${contents} MATCHES "#define OPENEXR_VERSION_PATCH ([0-9]+)") + SET(OPENEXR_VERSION_PATCH "${CMAKE_MATCH_1}") + ENDIF () ENDIF () ENDIF () - IF (OPENEXR_VERSION_MAJOR AND OPENEXR_VERSION_MINOR) - set(OPENEXR_VERSION "${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR}") - ENDIF () + set(OPENEXR_VERSION_MM "${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR}") + set(OPENEXR_VERSION "${OPENEXR_VERSION_MAJOR}.${OPENEXR_VERSION_MINOR}.${OPENEXR_VERSION_PATCH}") - ocv_find_openexr("-${OPENEXR_VERSION}") - ocv_find_openexr("-${OPENEXR_VERSION}_s") - ocv_find_openexr("-${OPENEXR_VERSION}_d") - ocv_find_openexr("-${OPENEXR_VERSION}_s_d") + ocv_find_openexr("-${OPENEXR_VERSION_MM}") + ocv_find_openexr("-${OPENEXR_VERSION_MM}_s") + ocv_find_openexr("-${OPENEXR_VERSION_MM}_d") + ocv_find_openexr("-${OPENEXR_VERSION_MM}_s_d") ocv_find_openexr("") ocv_find_openexr("_s") ocv_find_openexr("_d") @@ -118,6 +121,7 @@ FOREACH(SEARCH_PATH ${SEARCH_PATHS}) UNSET(OPENEXR_VERSION_FILE) UNSET(OPENEXR_VERSION_MAJOR) UNSET(OPENEXR_VERSION_MINOR) + UNSET(OPENEXR_VERSION_MM) UNSET(OPENEXR_VERSION) ENDFOREACH() @@ -144,6 +148,11 @@ IF(OPENEXR_FOUND) endif() if(NOT OPENEXR_VERSION) SET(OPENEXR_VERSION "Unknown") + else() + if(HAVE_CXX17 AND OPENEXR_VERSION VERSION_LESS "2.3.0") + message(STATUS " OpenEXR(ver ${OPENEXR_VERSION}) doesn't support C++17 and higher. Updating OpenEXR 2.3.0+ is required.") + SET(OPENEXR_FOUND FALSE) + endif() endif() ELSE() IF(OPENEXR_FIND_REQUIRED) diff --git a/doc/opencv.bib b/doc/opencv.bib index 9abbf3a5f9..7da68ae65c 100644 --- a/doc/opencv.bib +++ b/doc/opencv.bib @@ -6,7 +6,7 @@ pages = {13.1--13.11}, publisher = {{BMVA} Press}, year = {2013}, - url = {https://doi.org/10.5244/C.27.13}, + url = {https://projet.liris.cnrs.fr/imagine/pub/proceedings/BMVC-2013/Papers/paper0013/paper0013.pdf}, doi = {10.5244/C.27.13}, timestamp = {Sat, 09 Apr 2022 12:44:13 +0200}, biburl = {https://dblp.org/rec/conf/bmvc/AlcantarillaNB13.bib}, @@ -22,7 +22,7 @@ location = {Ottawa, Canada}, pages = {430--436}, numpages = {7}, - url = {http://dl.acm.org/citation.cfm?id=1889712.1889775}, + url = {https://inria.hal.science/inria-00590109}, acmid = {1889775}, publisher = {IEEE Computer Society}, address = {Washington, DC, USA}, @@ -36,12 +36,21 @@ isbn = {978-1-4673-1226-4}, pages = {2911--2918}, numpages = {8}, - url = {http://dl.acm.org/citation.cfm?id=2354409.2355123}, + url = {https://www.robots.ox.ac.uk/~vgg/publications/2012/Arandjelovic12/arandjelovic12.pdf}, acmid = {2355123}, publisher = {IEEE Computer Society}, address = {Washington, DC, USA}, keywords = {Vectors,Visualization,Kernel,Standards,Support vector machines,Indexes,Euclidean distance} } +@inproceedings{arthur_kmeanspp_2007, + author = {Arthur, David and Vassilvitskii, Sergei}, + title = {k-means++: The advantages of careful seeding}, + booktitle = {Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms}, + year = {2007}, + pages = {1027--1035}, + publisher = {Society for Industrial and Applied Mathematics}, + url = {https://theory.stanford.edu/~sergei/papers/kMeansPP-soda.pdf} +} @article{BA83, author = {Burt, Peter J and Adelson, Edward H}, title = {A multiresolution spline with application to image mosaics}, @@ -51,7 +60,7 @@ volume = {2}, number = {4}, publisher = {ACM}, - url = {http://persci.mit.edu/pub_pdfs/spline83.pdf} + url = {https://persci.mit.edu/pub_pdfs/spline83.pdf} } @article{BL07, author = {Brown, Matthew and Lowe, David G}, @@ -62,7 +71,7 @@ volume = {74}, number = {1}, publisher = {Springer}, - url = {http://matthewalunbrown.com/papers/ijcv2007.pdf} + url = {http://www.ene.unb.br/mylene/PI/refs/ijcv2007.pdf} } @article{BT96, author = {Birchfield, Stan and Tomasi, Carlo}, @@ -95,7 +104,38 @@ volume = {13}, number = {2}, publisher = {Elsevier}, - url = {https://www.cs.bgu.ac.il/~icbv161/wiki.files/Readings/1981-Ballard-Generalizing_the_Hough_Transform_to_Detect_Arbitrary_Shapes.pdf} + url = {https://www.cs.utexas.edu/~dana/HoughT.pdf} +} +@inproceedings{BarathGCRANSAC, + author = {Barath, Daniel and Matas, Jiri}, + title = {Graph-Cut RANSAC}, + booktitle = {Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, + month = {June}, + year = {2018}, + url = {https://openaccess.thecvf.com/content_cvpr_2018/papers/Barath_Graph-Cut_RANSAC_CVPR_2018_paper.pdf} +} +@misc{barath2019progressive, + title = {Progressive NAPSAC: sampling from gradually growing neighborhoods}, + author = {Barath, Daniel and Ivashechkin, Maksym and Matas, Jiri}, + year = {2019}, + eprint = {1906.02295}, + archivePrefix = {arXiv}, + primaryClass = {cs.CV}, + url = {https://arxiv.org/abs/1906.02295} +} +@inproceedings{BarathMAGSAC, + author = {Barath, Daniel and Noskova, Jana and Ivashechkin, Maksym and Matas, Jiri}, + title = {MAGSAC++, a Fast, Reliable and Accurate Robust Estimator}, + booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)}, + month = {June}, + year = {2020}, + url = {https://arxiv.org/abs/1912.05909} +} +@book{bigun2006vision, + title = {Vision with direction}, + author = {Bigun, Josef}, + year = {2006}, + publisher = {Springer} } @techreport{blanco2010tutorial, title = {A tutorial on SE(3) transformation parameterizations and on-manifold optimization}, @@ -114,7 +154,8 @@ volume = 10485, pages = {48--58}, doi = {10.1007/978-3-319-68548-9_5}, - isbn = {978-3-319-68547-2} + isbn = {978-3-319-68547-2}, + url = {https://www.researchgate.net/publication/319037445_Two_More_Strategies_to_Speed_Up_Connected_Components_Labeling_Algorithms} } @article{Bolelli2019, title = {{Spaghetti Labeling: Directed Acyclic Graphs for Block-Based Connected Components Labeling}}, @@ -126,7 +167,17 @@ number = 1, pages = {1999--2012}, doi = {10.1109/TIP.2019.2946979}, - issn = {1057-7149} + issn = {1057-7149}, + url = {https://federicobolelli.it/pub_files/2019tip.pdf} +} +@article{Bolelli2021, + title = {One DAG to Rule Them All}, + author = {Bolelli, Federico and Allegretti, Stefano and Grana, Costantino}, + journal = {IEEE Transactions on Pattern Analysis and Machine Intelligence}, + year = {2021}, + publisher = {IEEE}, + doi = {10.1109/TPAMI.2021.3055337}, + url = {https://www.researchgate.net/publication/348857725_One_DAG_to_Rule_Them_All} } @article{Borgefors86, author = {Borgefors, Gunilla}, @@ -136,15 +187,16 @@ journal = {Computer vision, graphics, and image processing}, volume = {34}, number = {3}, - publisher = {Elsevier} + publisher = {Elsevier}, + url = {https://people.cmm.minesparis.psl.eu/users/marcoteg/cv/publi_pdf/MM_refs/1986_Borgefors_distance.pdf} } @article{Bouguet00, author = {Bouguet, Jean-Yves}, - title = {Pyramidal implementation of the affine lucas kanade feature tracker description of the algorithm}, + title = {Pyramidal Implementation of the Lucas Kanade Feature Tracker Description of the algorithm}, year = {2001}, journal = {Intel Corporation}, volume = {5}, - url = {https://pdfs.semanticscholar.org/aa97/2b40c0f8e20b07e02d1fd320bc7ebadfdfc7.pdf} + url = {http://robots.stanford.edu/cs223b04/algo_affine_tracking.pdf} } @misc{BouguetMCT, author = {Bouguet, Jean-Yves}, @@ -158,13 +210,14 @@ year = {2000}, pages = {238--244}, publisher = {IEEE}, - url = {http://web.cse.ohio-state.edu/~davis.1719/Publications/mva02.pdf} + url = {https://web.archive.org/web/20240420000446/http://web.cse.ohio-state.edu/~davis.1719/Publications/mva02.pdf} } @article{Bradski98, author = {Bradski, Gary R}, title = {Computer vision face tracking for use in a perceptual user interface}, year = {1998}, - publisher = {Citeseer} + publisher = {Citeseer}, + url = {http://opencv.jp/opencv-1.0.0_org/docs/papers/camshift.pdf} } @incollection{Brox2004, author = {Brox, Thomas and Bruhn, Andres and Papenberg, Nils and Weickert, Joachim}, @@ -173,7 +226,15 @@ year = {2004}, pages = {25--36}, publisher = {Springer}, - url = {http://www.cs.auckland.ac.nz/~rklette/TeachAuckland.html/CIMAT/02a%20BBPW-ECCV04.pdf} + url = {https://www.cs.auckland.ac.nz/~rklette/TeachAuckland.html/CIMAT/02a%20BBPW-ECCV04.pdf} +} +@article{Buades2005DenoisingIS, + title = {Denoising image sequences does not require motion estimation}, + author = {Antoni Buades and Bartomeu Coll and Jean-Michel Morel}, + journal = {IEEE Conference on Advanced Video and Signal Based Surveillance, 2005.}, + year = {2005}, + pages = {70-74}, + url = {https://www.researchgate.net/publication/4215294_Denoising_image_sequences_does_not_require_motion_estimation} } @article{Burges98, author = {Burges, Christopher JC}, @@ -184,7 +245,7 @@ volume = {2}, number = {2}, publisher = {Springer}, - url = {http://www.cmlab.csie.ntu.edu.tw/~cyy/learning/papers/SVM_Tutorial.pdf} + url = {https://web.archive.org/web/20170811202211/http://www.cmlab.csie.ntu.edu.tw/~cyy/learning/papers/SVM_Tutorial.pdf} } @inproceedings{CL12, author = {Lu, Cewu and Xu, Li and Jia, Jiaya}, @@ -193,7 +254,7 @@ year = {2012}, pages = {1--7}, publisher = {IEEE}, - url = {https://www.computer.org/csdl/proceedings/iccp/2012/1662/00/06215215.pdf} + url = {https://www.cse.cuhk.edu.hk/~leojia/projects/color2gray/} } @article{Canny86, author = {Canny, John}, @@ -203,7 +264,7 @@ journal = {Pattern Analysis and Machine Intelligence, IEEE Transactions on}, number = {6}, publisher = {IEEE}, - url = {http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.420.3300&rep=rep1&type=pdf} + url = {https://web.archive.org/web/20220818083832/https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.420.3300&rep=rep1&type=pdf} } @article{ChambolleEtAl, author = {Chambolle, Antonin and Caselles, Vicent and Cremers, Daniel and Novaga, Matteo and Pock, Thomas}, @@ -212,7 +273,8 @@ pages = {263--340}, journal = {Theoretical foundations and numerical methods for sparse recovery}, volume = {9}, - publisher = {Walter de Gruyter} + publisher = {Walter de Gruyter}, + url = {https://hal.science/hal-00437581v1} } @article{Chaumette06, author = {Chaumette, Fran{\c c}ois and Hutchinson, S.}, @@ -228,6 +290,35 @@ hal_id = {inria-00350283}, hal_version = {v1}, } +@inproceedings{ChumPROSAC, + title = {Matching with {PROSAC} - Progressive Sampling Consensus}, + author = {Chum, Ondrej and Matas, Jiri}, + booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)}, + year = {2005}, + url = {https://cmp.felk.cvut.cz/~matas/papers/chum-prosac-cvpr05.pdf} +} +@inproceedings{ChumLORANSAC, + title = {Locally Optimized {RANSAC}}, + author = {Chum, Ondrej and Matas, Jiri and Kittler, Josef}, + booktitle = {DAGM}, + year = {2003}, + url = {https://cmp.felk.cvut.cz/~matas/papers/chum-dagm03.pdf} +} +@inproceedings{ChumEpipolar, + author = {Chum, Ondrej and Werner, Tomas and Matas, Jiri}, + booktitle = {Proceedings of the 17th International Conference on Pattern Recognition. ICPR 2004}, + title = {Epipolar geometry estimation via RANSAC benefits from the oriented epipolar constraint}, + year = {2004}, + volume = {1}, + pages = {112-115 Vol.1}, + url = {https://dspace.cvut.cz/bitstream/handle/10467/9493/2004-Epipolar-geometry-estimation-via-RANSAC-benefits-from-oriented-epipolar-constraint.pdf} +} +@inproceedings{ChumDominant, + title = {Epipolar Geometry Estimation Unaffected by the Dominant Plane}, + author = {Chum, Ondrej and Werner, Tomas and Matas, Jiri.}, + booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)}, + year = {2005} +} @article{Collins14, year = {2014}, issn = {0920-5691}, @@ -236,7 +327,7 @@ number = {3}, doi = {10.1007/s11263-014-0725-5}, title = {Infinitesimal Plane-Based Pose Estimation}, - url = {http://dx.doi.org/10.1007/s11263-014-0725-5}, + url = {https://encov.ip.uca.fr/publications/pubfiles/2014_Collins_etal_IJCV_plane.pdf}, publisher = {Springer US}, keywords = {Plane; Pose; SfM; PnP; Homography}, author = {Collins, Toby and Bartoli, Adrien}, @@ -249,7 +340,8 @@ journal = {International Journal of Robotics Research}, year = {1998}, volume = {18}, - pages = {286--298} + pages = {286--298}, + url = {https://typeset.io/pdf/hand-eye-calibration-using-dual-quaternions-1boiebmyns.pdf} } @inproceedings{DM03, author = {Drago, Fr{\'e}d{\'e}ric and Myszkowski, Karol and Annen, Thomas and Chiba, Norishige}, @@ -260,7 +352,7 @@ volume = {22}, number = {3}, publisher = {Wiley}, - url = {http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.69.8094&rep=rep1&type=pdf} + url = {https://resources.mpi-inf.mpg.de/tmo/logmap/logmap.pdf} } @inproceedings{DM97, author = {Debevec, Paul E and Malik, Jitendra}, @@ -269,7 +361,7 @@ year = {2008}, pages = {31}, publisher = {ACM}, - url = {http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.463.6496&rep=rep1&type=pdf} + url = {https://www.pauldebevec.com/Research/HDR/debevec-siggraph97.pdf} } @inproceedings{Dalal2005, author = {Dalal, Navneet and Triggs, Bill}, @@ -288,19 +380,27 @@ year = {1997}, pages = {928--934}, publisher = {IEEE}, - url = {http://alumni.media.mit.edu/~jdavis/Publications/publications_402.pdf} + url = {https://web.archive.org/web/20230424044650/http://alumni.media.mit.edu/~jdavis/Publications/publications_402.pdf} +} +@inproceedings{duda2018, + title = {Accurate Detection and Localization of Checkerboard Corners for Calibration}, + year = {2018}, + booktitle = {29th British Machine Vision Conference. British Machine Vision Conference (BMVC-29), September 3-6, Newcastle, United Kingdom}, + publisher = {BMVA Press}, + author = {Duda, Alexander and Frese, Udo}, + url = {http://bmvc2018.org/contents/papers/0508.pdf} } @misc{Eade13, author = {Eade, Ethan}, title = {Gauss-Newton / Levenberg-Marquardt Optimization}, year = {2013}, - url = {http://ethaneade.com/optimization.pdf} + url = {https://ethaneade.com/optimization.pdf} } @misc{Eade17, author = {Eade, Ethan}, title = {Lie Groups for 2D and 3D Transformation}, year = {2017}, - url = {http://www.ethaneade.com/lie.pdf} + url = {https://www.ethaneade.com/lie.pdf} } @inproceedings{EM11, author = {Gastal, Eduardo SL and Oliveira, Manuel M}, @@ -351,7 +451,7 @@ year = {2003}, pages = {363--370}, publisher = {Springer}, - url = {https://doi.org/10.1007/3-540-45103-X_50}, + url = {https://www.diva-portal.org/smash/get/diva2:273847/FULLTEXT01.pdf}, doi = {10.1007/3-540-45103-X_50} } @inproceedings{Farsiu03, @@ -362,7 +462,7 @@ pages = {II--291}, volume = {2}, publisher = {IEEE}, - url = {http://www.academia.edu/download/42361965/ICIP2003SR.pdf} + url = {https://users.soe.ucsc.edu/~milanfar/publications/conf/ICIP2003SR.pdf} } @techreport{Felzenszwalb04, author = {Felzenszwalb, Pedro and Huttenlocher, Daniel}, @@ -380,7 +480,7 @@ volume = {32}, number = {9}, publisher = {IEEE}, - url = {http://lear.inrialpes.fr/~oneata/reading_group/dpm.pdf} + url = {https://cs.brown.edu/people/pfelzens/papers/lsvm-pami.pdf} } @article{Felzenszwalb2006, author = {Felzenszwalb, Pedro F and Huttenlocher, Daniel P}, @@ -391,7 +491,19 @@ volume = {70}, number = {1}, publisher = {Springer}, - url = {http://www.cs.duke.edu/research/AI/papers/Felzenszwalb06.pdf} + url = {https://cs.brown.edu/people/pfelzens/papers/bp-cvpr.pdf} +} +@article{FischlerRANSAC, + author = {Fischler, Martin A. and Bolles, Robert C.}, + title = {Random Sample Consensus: A Paradigm for Model Fitting with Applications to Image Analysis and Automated Cartography}, + year = {1981}, + publisher = {Association for Computing Machinery}, + volume = {24}, + number = {6}, + month = {jun}, + pages = {381–395}, + numpages = {15}, + url = {https://dl.acm.org/doi/pdf/10.1145/358669.358692} } @inproceedings{Fitzgibbon95, author = {Fitzgibbon, Andrew W and Fisher, Robert B}, @@ -406,7 +518,24 @@ title = {Numerically Stable Direct Least Squares Fitting of Ellipses}, author = {Radim Hal oy and Jan Flusser}, year = {1998}, - url = {https://www.semanticscholar.org/paper/Numerically-Stable-Direct-Least-Squares-Fitting-of-oy-Flusser/9a8607575ba9c6016e9f3db5e52f5ed4d14d5dfd} + url = {https://autotrace.sourceforge.net/WSCG98.pdf} +} +@inproceedings{forssen2007maximally, + title = {Maximally stable colour regions for recognition and matching}, + author = {Forss{\'e}n, Per-Erik}, + booktitle = {Computer Vision and Pattern Recognition, 2007. CVPR'07. IEEE Conference on}, + pages = {1--8}, + year = {2007}, + publisher = {IEEE}, + url = {https://people.isy.liu.se/cvl/perfo/papers/forssen_cvpr07.pdf} +} +@inproceedings{forstner1987fast, + title = {A fast operator for detection and precise location of distincs points, corners and center of circular features}, + author = {Forstner, W}, + booktitle = {Proc. of the Intercommission Conference on Fast Processing of Photogrammetric Data, Interlaken, Switzerland, 1987}, + pages = {281--305}, + year = {1987}, + url = {https://cseweb.ucsd.edu/classes/sp02/cse252/foerstner/foerstner.pdf} } @article{Gallego2014ACF, title = {A Compact Formula for the Derivative of a 3-D Rotation in Exponential Coordinates}, @@ -414,7 +543,8 @@ journal = {Journal of Mathematical Imaging and Vision}, year = {2014}, volume = {51}, - pages = {378-384} + pages = {378-384}, + url = {https://arxiv.org/abs/1312.0788} } @article{Grana2010, title = {{Optimized Block-Based Connected Components Labeling With Decision Trees}}, @@ -424,21 +554,8 @@ volume = 19, number = 6, pages = {1596--1609}, - doi = {10.1109/TIP.2010.2044963} -} -@article{taubin1991, - abstract = {The author addresses the problem of parametric representation and estimation of complex planar curves in 2-D surfaces in 3-D, and nonplanar space curves in 3-D. Curves and surfaces can be defined either parametrically or implicitly, with the latter representation used here. A planar curve is the set of zeros of a smooth function of two variables x-y, a surface is the set of zeros of a smooth function of three variables x-y-z, and a space curve is the intersection of two surfaces, which are the set of zeros of two linearly independent smooth functions of three variables x-y-z For example, the surface of a complex object in 3-D can be represented as a subset of a single implicit surface, with similar results for planar and space curves. It is shown how this unified representation can be used for object recognition, object position estimation, and segmentation of objects into meaningful subobjects, that is, the detection of `interest regions' that are more complex than high curvature regions and, hence, more useful as features for object recognition}, - author = {Taubin, Gabriel}, - doi = {10.1109/34.103273}, - isbn = {0162-8828}, - issn = {01628828}, - journal = {IEEE Transactions on Pattern Analysis and Machine Intelligence}, - number = {11}, - pages = {1115--1138}, - title = {Estimation of planar curves, surfaces, and nonplanar space curves defined by implicit equations with applications to edge and range image segmentation}, - volume = {13}, - year = {1991}, - url = {https://pdfs.semanticscholar.org/27a7/90a0ca254006fbe37d41e1751516911607ca.pdf} + doi = {10.1109/TIP.2010.2044963}, + url = {https://aimagelab.ing.unimore.it/imagelab/pubblicazioni/2009tiplabeling.pdf} } @inproceedings{G11, author = {Grundmann, Matthias and Kwatra, Vivek and Essa, Irfan}, @@ -458,7 +575,7 @@ volume = {8}, number = {2}, publisher = {Taylor \& Francis}, - url = {http://pages.cs.wisc.edu/~lizhang/courses/cs766-2008f/projects/hdr/jgtpap2.pdf} + url = {https://pages.cs.wisc.edu/~lizhang/courses/cs766-2008f/projects/hdr/jgtpap2.pdf} } @inproceedings{Gold2012, author = {Godbehere, Andrew B and Matsukawa, Akihiro and Goldberg, Ken}, @@ -467,7 +584,19 @@ year = {2012}, pages = {4305--4312}, publisher = {IEEE}, - url = {http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.228.1735&rep=rep1&type=pdf} + url = {https://goldberg.berkeley.edu/pubs/acc-2012-visual-tracking-final.pdf} +} +@article{Gonzalez1987, + title = {Digital Image Fundamentals, Digital Imaging Processing}, + author = {Gonzalez, Rafael C and others}, + year = {1987}, + publisher = {Addison Wesley Publishing Company} +} +@article{gruzman, + title = {Ð¦Ð¸Ñ„Ñ€Ð¾Ð²Ð°Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ° изображений в информационных ÑиÑтемах}, + author = {Грузман, И.С. and Киричук, Ð’.С. and КоÑых, Ð’.П. and ПеретÑгин, Г.И. and Спектор, Ð.Ð.}, + year = {2000}, + publisher = {Изд-во ÐГТУ ÐовоÑибирÑк} } @article{Guil1999, author = {Guil, N and Gonzalez-Linares, Jos{\'e} Mar{\'\i}a and Zapata, Emilio L}, @@ -488,7 +617,7 @@ volume = {30}, number = {2}, publisher = {IEEE}, - url = {http://www.openrs.org/photogrammetry/2015/SGM%202008%20PAMI%20-%20Stereo%20Processing%20by%20Semiglobal%20Matching%20and%20Mutual%20Informtion.pdf} + url = {https://core.ac.uk/download/pdf/11134866.pdf} } @article{Hartley99, author = {Hartley, Richard I}, @@ -499,7 +628,7 @@ volume = {35}, number = {2}, publisher = {Springer}, - url = {http://www.cs.ait.ac.th/~mdailey/cvreadings/Hartley-Rectify.pdf} + url = {http://dev.ipol.im/~morel/Dossier_MVA_2011_Cours_Transparents_Documents/2011_Cours7_Document3_hartley.pdf} } @book{HartleyZ00, author = {Hartley, Richard and Zisserman, Andrew}, @@ -520,7 +649,7 @@ issn = {0278-3649}, pages = {195--210}, numpages = {16}, - url = {http://dx.doi.org/10.1177/027836499501400301}, + url = {https://arxiv.org/abs/2311.12655}, doi = {10.1177/027836499501400301}, acmid = {208622}, publisher = {Sage Publications, Inc.}, @@ -543,7 +672,14 @@ journal = {Information Theory, IRE Transactions on}, volume = {8}, number = {2}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://www.cs.utexas.edu/~grauman/courses/spring2011/psets/pset5/huMoments.pdf} +} +@book{jahne2000computer, + title = {Computer vision and applications: a guide for students and practitioners}, + author = {Jahne, Bernd}, + year = {2000}, + publisher = {Elsevier} } @article{Javier2012, author = {S{\'a}nchez P{\'e}rez, Javier and Meinhardt-Llopis, Enric and Facciolo, Gabriele}, @@ -551,6 +687,25 @@ year = {2012}, url = {http://www.ipol.im/pub/art/2013/26/article_lr.pdf} } +@article{Kannala2006, + author = {Kannala, Juho and Brandt, Sami}, + year = {2006}, + month = {09}, + pages = {1335-40}, + title = {A Generic Camera Model and Calibration Method for Conventional, Wide-Angle, and Fish-Eye Lenses}, + volume = {28}, + journal = {IEEE transactions on pattern analysis and machine intelligence}, + doi = {10.1109/TPAMI.2006.153}, + url = {https://www.researchgate.net/publication/6899685_A_Generic_Camera_Model_and_Calibration_Method_for_Conventional_Wide-Angle_and_Fish-Eye_Lenses} +} +@inproceedings{Ke17, + author = {Ke, Tong and Roumeliotis, Stergios}, + title = {An Efficient Algebraic Solution to the Perspective-Three-Point Problem}, + booktitle = {Computer Vision and Pattern Recognition (CVPR), 2017 IEEE Conference on}, + year = {2017}, + publisher = {IEEE}, + url = {https://arxiv.org/abs/1701.08237} +} @article{KleeLaskowski85, author = {Klee, Victor and Laskowski, Michael C}, title = {Finding the smallest triangles containing a given convex polygon}, @@ -567,17 +722,35 @@ booktitle = {Computer Vision, 2003. Proceedings. Ninth IEEE International Conference on}, year = {2003}, pages = {1033--1040}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://www.cs.cornell.edu/~rdz/Papers/KKZ-ICCV03.pdf} } -@article{YM11, - author = {Yu, Guoshen and Morel, Jean-Michel}, - title = {ASIFT: An Algorithm for Fully Affine Invariant Comparison}, - year = {2011}, - pages = {11--38}, - journal = {Image Processing On Line}, - volume = {1}, - doi = {10.5201/ipol.2011.my-asift}, - url = {http://www.ipol.im/pub/algo/my_affine_sift/} +@inproceedings{Kwatra03, + author = {Kwatra, Vivek and Sch{\"o}dl, Arno and Essa, Irfan and Turk, Greg and Bobick, Aaron}, + title = {Graphcut textures: image and video synthesis using graph cuts}, + booktitle = {ACM Transactions on Graphics (ToG)}, + year = {2003}, + pages = {277--286}, + volume = {22}, + number = {3}, + publisher = {ACM}, + url = {https://dl.acm.org/doi/pdf/10.1145/882262.882264} +} +@article{Li2010SimultaneousRA, + title = {Simultaneous robot-world and hand-eye calibration using dual-quaternions and Kronecker product}, + author = {Aiguo Li and Lin Wang and Defeng Wu}, + journal = {International Journal of Physical Sciences}, + year = {2010}, + volume = {5}, + pages = {1530-1536}, + url = {https://academicjournals.org/article/article1380809659_Li%20et%20al.pdf} +} +@inproceedings{liao2020real, + author = {Liao, Minghui and Wan, Zhaoyi and Yao, Cong and Chen, Kai and Bai, Xiang}, + title = {Real-time Scene Text Detection with Differentiable Binarization}, + booktitle = {Proc. AAAI}, + year = {2020}, + url = {https://arxiv.org/abs/1911.08947} } @article{Louhichi07, author = {Louhichi, H. and Fournel, T. and Lavest, J. M. and Ben Aissia, H.}, @@ -589,13 +762,14 @@ number = {8}, publisher = {IOP Publishing Ltd} } -@article{Li2010SimultaneousRA, - title = {Simultaneous robot-world and hand-eye calibration using dual-quaternions and Kronecker product}, - author = {Aiguo Li and Lin Wang and Defeng Wu}, - journal = {International Journal of Physical Sciences}, - year = {2010}, - volume = {5}, - pages = {1530-1536} +@article{LowIlie2003, + author = {Kok-Lim Low, Adrian Ilie}, + year = {2003}, + pages = {3-15}, + title = {View Frustum Optimization to Maximize Object's Image Area}, + journal = {Journal of Graphics, (GPU, & Game) Tools (JGT)}, + volume = {8}, + url = {https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=1fbd43f3827fffeb76641a9c5ab5b625eb5a75ba} } @article{Lowe04, author = {Lowe, David G.}, @@ -609,7 +783,7 @@ issn = {0920-5691}, pages = {91--110}, numpages = {20}, - url = {https://doi.org/10.1023/B:VISI.0000029664.99615.94}, + url = {https://www.cs.ubc.ca/~lowe/papers/ijcv04.pdf}, doi = {10.1023/B:VISI.0000029664.99615.94}, acmid = {996342}, publisher = {Kluwer Academic Publishers}, @@ -623,7 +797,8 @@ booktitle = {IJCAI}, year = {1981}, pages = {674--679}, - volume = {81} + volume = {81}, + url = {https://hal.science/hal-03697340v1} } @misc{MA13, author = {Mordvintsev, Alexander}, @@ -637,13 +812,31 @@ pages = {60}, publisher = {Informatics and Mathematical Modelling, Technical University of Denmark, {DTU}}, address = {Richard Petersens Plads, Building 321, {DK-}2800 Kgs. Lyngby}, - url = {http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf} + url = {https://www2.imm.dtu.dk/pubdb/edoc/imm3215.pdf} +} +@article{Matas2005RandomizedRW, + title = {Randomized RANSAC with sequential probability ratio test}, + author = {Matas, Jiri and Chum, Ondrej}, + journal = {Tenth IEEE International Conference on Computer Vision (ICCV) Volume 1}, + year = {2005}, + volume = {2}, + pages = {1727-1732 Vol. 2}, + url = {https://cmp.felk.cvut.cz/~matas/papers/chum-waldsac-iccv05.pdf} } @article{MHT2011, author = {Getreuer, Pascal}, title = {Malvar-He-Cutler Linear Image Demosaicking}, year = {2011}, - journal = {Image Processing on Line} + journal = {Image Processing on Line}, + url = {https://www.ipol.im/pub/art/2011/g_mhcd/} +} +@article{mitchell2005logistic, + author = {Mitchell, Tom M}, + title = {Logistic Regression}, + year = {2005}, + pages = {701}, + journal = {Machine learning}, + volume = {10} } @inproceedings{MK07, author = {Mertens, Tom and Kautz, Jan and Van Reeth, Frank}, @@ -651,7 +844,8 @@ booktitle = {Computer Graphics and Applications, 2007. PG'07. 15th Pacific Conference on}, year = {2007}, pages = {382--390}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://web.stanford.edu/class/cs231m/project-1/exposure-fusion.pdf} } @article{MM06, author = {Mantiuk, Rafal and Myszkowski, Karol and Seidel, Hans-Peter}, @@ -661,7 +855,8 @@ journal = {ACM Transactions on Applied Perception (TAP)}, volume = {3}, number = {3}, - publisher = {ACM} + publisher = {ACM}, + url = {https://www.cl.cam.ac.uk/~rkm38/pdfs/mantiuk06pfcphdri.pdf} } @incollection{MOG2001, author = {KaewTraKulPong, Pakorn and Bowden, Richard}, @@ -669,7 +864,8 @@ booktitle = {Video-Based Surveillance Systems}, year = {2002}, pages = {135--144}, - publisher = {Springer} + publisher = {Springer}, + url = {https://www.researchgate.net/profile/Richard-Bowden/publication/2557021_An_Improved_Adaptive_Background_Mixture_Model_for_Realtime_Tracking_with_Shadow_Detection/links/004635190bf9105d52000000/An-Improved-Adaptive-Background-Mixture-Model-for-Realtime-Tracking-with-Shadow-Detection.pdf} } @book{Ma:2003:IVI, author = {Ma, Yi and Soatto, Stefano and Kosecka, Jana and Sastry, S. Shankar}, @@ -723,7 +919,8 @@ booktitle = {Image Processing and its Applications, 1992., International Conference on}, year = {1992}, pages = {303--306}, - publisher = {IET} + publisher = {IET}, + url = {https://www.researchgate.net/publication/279958069_Color_Image_Segmentation} } @incollection{Mitzel09, author = {Mitzel, Dennis and Pock, Thomas and Schoenemann, Thomas and Cremers, Daniel}, @@ -731,9 +928,10 @@ booktitle = {Pattern Recognition}, year = {2009}, pages = {432--441}, - publisher = {Springer} + publisher = {Springer}, + url = {https://cvai.cit.tum.de/_media/spezial/bib/mitzel_et_al_dagm09.pdf} } -@INPROCEEDINGS{Mortensen95intelligentscissors, +@inproceedings{Mortensen95intelligentscissors, author = {Eric N. Mortensen and William A. Barrett}, title = {Intelligent Scissors for Image Composition}, booktitle = {In Computer Graphics, SIGGRAPH Proceedings}, @@ -745,7 +943,15 @@ title = {Fast Approximate Nearest Neighbors with Automatic Algorithm Configuration}, booktitle = {VISAPP (1)}, year = {2009}, - pages = {331--340} + pages = {331--340}, + url = {https://www.cs.ubc.ca/research/flann/uploads/FLANN/flann_visapp09.pdf} +} +@inproceedings{MyattNAPSAC, + author = {Myatt, D. and Torr, Philip and Nasuto, Slawomir and Bishop, John and Craddock, R.}, + year = {2002}, + booktitle = {Proceedings of the British Machine Vision Conference (BMVC)}, + title = {NAPSAC: High Noise, High Dimensional Robust Estimation - it's in the Bag}, + url = {https://bmva-archive.org.uk/bmvc/2002/papers/164/full_164.pdf} } @article{Nister03, author = {Nist{\'e}r, David}, @@ -755,7 +961,17 @@ journal = {Pattern Analysis and Machine Intelligence, IEEE Transactions on}, volume = {26}, number = {6}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://www-users.cse.umn.edu/~hspark/CSci5980/nister.pdf} +} +@incollection{nister2008linear, + title = {Linear time maximally stable extremal regions}, + author = {Nist{\'e}r, David and Stew{\'e}nius, Henrik}, + booktitle = {Computer Vision--ECCV 2008}, + pages = {183--196}, + year = {2008}, + publisher = {Springer}, + url = {https://link.springer.com/content/pdf/10.1007/978-3-540-88688-4_14.pdf} } @article{OF06, author = {Matsushita, Yasuyuki and Ofek, Eyal and Ge, Weina and Tang, Xiaoou and Shum, Heung-Yeung}, @@ -765,7 +981,8 @@ journal = {Pattern Analysis and Machine Intelligence, IEEE Transactions on}, volume = {28}, number = {7}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://mmlab.ie.cuhk.edu.hk/archive/2006/01634345.pdf} } @article{ORourke86, author = {O'Rourke, Joseph and Aggarwal, Alok and Maddila, Sanjeev and Baldwin, Michael}, @@ -775,7 +992,8 @@ journal = {Journal of Algorithms}, volume = {7}, number = {2}, - publisher = {Elsevier} + publisher = {Elsevier}, + url = {https://prografix.narod.ru/source/orourke1986.pdf} } @article{Park94, author = {F. C. Park and B. J. Martin}, @@ -787,7 +1005,8 @@ number = {5}, pages = {717-721}, doi = {10.1109/70.326576}, - issn = {1042-296X} + issn = {1042-296X}, + url = {https://drive.google.com/file/d/1t1uoki3_qOXHMmWq5ixqQcALlEIJzTMh/view} } @inproceedings{PM03, author = {P{\'e}rez, Patrick and Gangnet, Michel and Blake, Andrew}, @@ -797,7 +1016,8 @@ pages = {313--318}, volume = {22}, number = {3}, - publisher = {ACM} + publisher = {ACM}, + url = {https://www.cs.jhu.edu/~misha/Fall07/Papers/Perez03.pdf} } @inproceedings{Puzicha1997, author = {Puzicha, Jan and Hofmann, Thomas and Buhmann, Joachim M}, @@ -805,7 +1025,8 @@ booktitle = {Computer Vision and Pattern Recognition, 1997. Proceedings., 1997 IEEE Computer Society Conference on}, year = {1997}, pages = {267--272}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://static.aminer.org/pdf/PDF/000/128/789/non_parametric_similarity_measures_for_unsupervised_texture_segmentation_and_image.pdf} } @inproceedings{RB99, author = {Robertson, Mark A and Borman, Sean and Stevenson, Robert L}, @@ -814,7 +1035,8 @@ year = {1999}, pages = {159--163}, volume = {3}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://www.seanborman.com/publications/icip99a.pdf} } @article{RD05, author = {Reinhard, Erik and Devlin, Kate}, @@ -824,7 +1046,8 @@ journal = {Visualization and Computer Graphics, IEEE Transactions on}, volume = {11}, number = {1}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://pages.cs.wisc.edu/~lizhang/courses/cs766-2012f/projects/hdr/Reinhard2005DRR.pdf} } @inproceedings{RRKB11, author = {Rublee, Ethan and Rabaud, Vincent and Konolige, Kurt and Bradski, Gary}, @@ -832,13 +1055,15 @@ booktitle = {Computer Vision (ICCV), 2011 IEEE International Conference on}, year = {2011}, pages = {2564--2571}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://www.researchgate.net/publication/221111151_ORB_an_efficient_alternative_to_SIFT_or_SURF} } @techreport{RS04, author = {Szeliski, R}, title = {Image alignment and stitching: a tutorial, Microsoft Corporation, Redmond, WA}, year = {2004}, - institution = {MSR-TR-2004-92} + institution = {MSR-TR-2004-92}, + url = {https://szeliski.org/papers/Szeliski_ImageAlignmentTutorial_FnT06.pdf} } @book{RS10, author = {Szeliski, Richard}, @@ -848,9 +1073,13 @@ url = {https://szeliski.org/Book/} } @article{Rafael12, - author = {von Gioi, Rafael Grompone and Jakubowicz, J{\'e}r{\'e}mie and Morel, Jean-Michel and Randall, Gregory}, - title = {LSD: a line segment detector}, - year = {2012} + title = {{LSD: a Line Segment Detector}}, + author = {Grompone von Gioi, Rafael and Jakubowicz, Jérémie and Morel, Jean-Michel and Randall, Gregory}, + journal = {{Image Processing On Line}}, + volume = {2}, + pages = {35--55}, + year = {2012}, + url = {https://doi.org/10.5201/ipol.2012.gjmr-lsd} } @incollection{Rosten06, author = {Rosten, Edward and Drummond, Tom}, @@ -858,7 +1087,8 @@ booktitle = {Computer Vision--ECCV 2006}, year = {2006}, pages = {430--443}, - publisher = {Springer} + publisher = {Springer}, + url = {https://link.springer.com/content/pdf/10.1007/11744023_34.pdf} } @inproceedings{mair2010_agast, title = {Adaptive and Generic Corner Detection Based on the Accelerated Segment Test}, @@ -866,7 +1096,7 @@ year = {2010}, month = sep, booktitle = {European Conference on Computer Vision (ECCV'10)}, - url = {http://www6.in.tum.de/Main/ResearchAgast}, + url = {https://web.archive.org/web/20170822001934/http://www6.in.tum.de/Main/Publications/Mair2010c.pdf}, month_numeric = {9} } @article{Rubner2000, @@ -877,11 +1107,12 @@ journal = {International Journal of Computer Vision}, volume = {40}, number = {2}, - publisher = {Springer} + publisher = {Springer}, + url = {https://www.cs.cmu.edu/~efros/courses/LBMV07/Papers/rubner-jcviu-00.pdf} } @article{RubnerSept98, author = {Rubner, Yossi and Tomasi, Carlo and Guibas, Leonidas J}, - title = {The Earth Mover''s Distance as a Metric for Image Retrieval}, + title = {The Earth Mover's Distance as a Metric for Image Retrieval}, year = {1998}, publisher = {Stanford University} } @@ -893,7 +1124,8 @@ journal = {International Journal of Computer Vision}, volume = {36}, number = {2}, - publisher = {Springer} + publisher = {Springer}, + url = {https://courses.cs.washington.edu/courses/cse455/09wi/tr-97-23.pdf} } @article{Shah2013SolvingTR, title = {Solving the Robot-World/Hand-Eye Calibration Problem Using the Kronecker Product}, @@ -901,7 +1133,8 @@ journal = {Journal of Mechanisms and Robotics}, year = {2013}, volume = {5}, - pages = {031007} + pages = {031007}, + url = {https://www.researchgate.net/publication/275087810_Solving_the_Robot-WorldHand-Eye_Calibration_Problem_Using_the_Kronecker_Product} } @inproceedings{Shi94, author = {Shi, Jianbo and Tomasi, Carlo}, @@ -909,7 +1142,19 @@ booktitle = {Computer Vision and Pattern Recognition, 1994. Proceedings CVPR'94., 1994 IEEE Computer Society Conference on}, year = {1994}, pages = {593--600}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://users.cs.duke.edu/~tomasi/papers/shi/TR_93-1399_Cornell.pdf} +} +@article{shi2016end, + title = {An end-to-end trainable neural network for image-based sequence recognition and its application to scene text recognition}, + author = {Shi, Baoguang and Bai, Xiang and Yao, Cong}, + journal = {IEEE transactions on pattern analysis and machine intelligence}, + volume = {39}, + number = {11}, + pages = {2298--2304}, + year = {2016}, + publisher = {IEEE}, + url = {https://arxiv.org/abs/1507.05717} } @article{Sklansky82, author = {Sklansky, Jack}, @@ -919,7 +1164,8 @@ journal = {Pattern Recognition Letters}, volume = {1}, number = {2}, - publisher = {Elsevier} + publisher = {Elsevier}, + url = {http://i.stanford.edu/pub/cstr/reports/cs/tr/81/887/CS-TR-81-887.pdf} } @article{Slabaugh, author = {Slabaugh, Gregory G}, @@ -927,19 +1173,31 @@ year = {1999}, pages = {2000}, journal = {Retrieved on August}, - volume = {6} + volume = {6}, + url = {https://eecs.qmul.ac.uk/~gslabaugh/publications/euler.pdf} } @article{Sol2018AML, title = {A micro Lie theory for state estimation in robotics}, author = {Joan Sol{\`a} and J{\'e}r{\'e}mie Deray and Dinesh Atchuthan}, journal = {ArXiv}, year = {2018}, - volume={abs/1812.01537} + volume={abs/1812.01537}, + url = {https://arxiv.org/abs/1812.01537} } @misc{SteweniusCFS, author = {Stewenius, Henrik}, title = {Calibrated Fivepoint solver}, - url = {http://www.vis.uky.edu/~stewe/FIVEPOINT/} + url = {https://web.archive.org/web/20170313091048/http://vis.uky.edu/~stewe/FIVEPOINT/} +} +@article{SteweniusRecent, + author = {Stewenius, Henrik and Engels, Christopher and Nister, David}, + year = {2006}, + month = {06}, + pages = {284-294}, + title = {Recent developments on direct relative orientation}, + volume = {60}, + journal = {ISPRS Journal of Photogrammetry and Remote Sensing}, + url = {https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=514fa8d4981cc2b2aecfc02e0e3a8f4be717bcd7} } @article{Suzuki85, author = {Suzuki, Satoshi and others}, @@ -949,7 +1207,22 @@ journal = {Computer Vision, Graphics, and Image Processing}, volume = {30}, number = {1}, - publisher = {Elsevier} + publisher = {Elsevier}, + url = {https://web.archive.org/web/20231213161741/https://www.nevis.columbia.edu/~vgenty/public/suzuki_et_al.pdf} +} +@article{taubin1991, + abstract = {The author addresses the problem of parametric representation and estimation of complex planar curves in 2-D surfaces in 3-D, and nonplanar space curves in 3-D. Curves and surfaces can be defined either parametrically or implicitly, with the latter representation used here. A planar curve is the set of zeros of a smooth function of two variables x-y, a surface is the set of zeros of a smooth function of three variables x-y-z, and a space curve is the intersection of two surfaces, which are the set of zeros of two linearly independent smooth functions of three variables x-y-z For example, the surface of a complex object in 3-D can be represented as a subset of a single implicit surface, with similar results for planar and space curves. It is shown how this unified representation can be used for object recognition, object position estimation, and segmentation of objects into meaningful subobjects, that is, the detection of `interest regions' that are more complex than high curvature regions and, hence, more useful as features for object recognition}, + author = {Taubin, Gabriel}, + doi = {10.1109/34.103273}, + isbn = {0162-8828}, + issn = {01628828}, + journal = {IEEE Transactions on Pattern Analysis and Machine Intelligence}, + number = {11}, + pages = {1115--1138}, + title = {Estimation of planar curves, surfaces, and nonplanar space curves defined by implicit equations with applications to edge and range image segmentation}, + volume = {13}, + year = {1991}, + url = {http://mesh.brown.edu/taubin/pdfs/taubin-pami91.pdf} } @article{TehChin89, author = {Teh, C-H and Chin, Roland T.}, @@ -959,7 +1232,8 @@ journal = {Pattern Analysis and Machine Intelligence, IEEE Transactions on}, volume = {11}, number = {8}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://www.researchgate.net/publication/3191687_On_the_detection_of_dominant_points_on_digital_curve} } @article{Telea04, author = {Telea, Alexandru}, @@ -969,7 +1243,8 @@ journal = {Journal of graphics tools}, volume = {9}, number = {1}, - publisher = {Taylor \& Francis} + publisher = {Taylor \& Francis}, + url = {https://www.olivier-augereau.com/docs/2004JGraphToolsTelea.pdf} } @article{Tsai89, author = {R. Y. Tsai and R. K. Lenz}, @@ -981,7 +1256,8 @@ number = {3}, pages = {345-358}, doi = {10.1109/70.34770}, - issn = {1042-296X} + issn = {1042-296X}, + url = {https://kmlee.gatech.edu/me6406/handeye.pdf} } @inproceedings{UES01, author = {Uyttendaele, Matthew and Eden, Ashley and Skeliski, R}, @@ -990,22 +1266,56 @@ year = {2001}, pages = {II--509}, volume = {2}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://www.cs.jhu.edu/~misha/ReadingSeminar/Papers/Uyttendaele01.pdf} +} +@article{umeyama1991least, + title = {Least-squares estimation of transformation parameters between two point patterns}, + author = {Umeyama, Shinji}, + journal = {IEEE Computer Architecture Letters}, + volume = {13}, + number = {04}, + pages = {376--380}, + year = {1991}, + publisher = {IEEE Computer Society}, + url = {https://graphics.stanford.edu/courses/cs164-09-spring/Handouts/paper_Umeyama.pdf} +} +@inproceedings{vacavant2013benchmark, + title = {A benchmark dataset for outdoor foreground/background extraction}, + author = {Vacavant, Antoine and Chateau, Thierry and Wilhelm, Alexis and Lequi{\`e}vre, Laurent}, + booktitle = {Computer Vision-ACCV 2012 Workshops}, + pages = {291--300}, + year = {2013}, + publisher = {Springer}, + url = {https://www.researchgate.net/publication/236672430_A_Benchmark_Dataset_for_Outdoor_ForegroundBackground_Extraction} +} +@inproceedings{van1995estimators, + title = {Estimators for orientation and anisotropy in digitized images}, + author = {Van Vliet, Lucas J and Verbeek, Piet W}, + booktitle = {ASCI}, + volume = {95}, + pages = {16--18}, + year = {1995}, + url = {https://www.researchgate.net/publication/27343879_Estimators_for_Orientation_and_Anisotropy_in_Digitized_Images} } @misc{VandLec, author = {Vandenberghe, Lieven}, title = {QR Factorization}, - url = {http://www.seas.ucla.edu/~vandenbe/133A/lectures/qr.pdf} + url = {https://www.seas.ucla.edu/~vandenbe/133A/lectures/qr.pdf} } -@inproceedings{V03, - author = {Kwatra, Vivek and Sch{\"o}dl, Arno and Essa, Irfan and Turk, Greg and Bobick, Aaron}, - title = {Graphcut textures: image and video synthesis using graph cuts}, - booktitle = {ACM Transactions on Graphics (ToG)}, - year = {2003}, - pages = {277--286}, - volume = {22}, - number = {3}, - publisher = {ACM} +@inproceedings{wang2016iros, + author = {John Wang and Edwin Olson}, + title = {{AprilTag} 2: Efficient and robust fiducial detection}, + booktitle = {Proceedings of the {IEEE/RSJ} International Conference on Intelligent Robots and Systems {(IROS)}}, + year = {2016}, + month = {October}, + url = {https://april.eecs.umich.edu/pdfs/wang2016iros.pdf} +} +@misc{Welch95, + author = {Welch, Greg and Bishop, Gary}, + title = {An introduction to the Kalman filter}, + year = {1995}, + url = {https://www.cs.unc.edu/~welch/media/pdf/kalman_intro.pdf} } @inproceedings{WJ10, author = {Xu, Wei and Mulligan, Jane}, @@ -1013,12 +1323,20 @@ booktitle = {Computer Vision and Pattern Recognition (CVPR), 2010 IEEE Conference on}, year = {2010}, pages = {263--270}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://www.researchgate.net/publication/221364690_Performance_Evaluation_of_Color_Correction_Approaches_for_Automatic_Multi-view_Image_and_Video_Stitching} } -@misc{Welch95, - author = {Welch, Greg and Bishop, Gary}, - title = {An introduction to the Kalman filter}, - year = {1995} +@Article{Wu2009, + author = {Wu, Kesheng and Otoo, Ekow and Suzuki, Kenji}, + title = {Optimizing two-pass connected-component labeling algorithms}, + journal = {Pattern Analysis and Applications}, + year = {2009}, + month = {Jun}, + day = {01}, + volume = {12}, + number = {2}, + pages = {117-135}, + url = {https://sdm.lbl.gov/~kewu/ps/paa-final.pdf} } @inproceedings{Yang2010, author = {Yang, Qingxiong and Wang, Liang and Ahuja, Narendra}, @@ -1026,7 +1344,28 @@ booktitle = {Computer Vision and Pattern Recognition (CVPR), 2010 IEEE Conference on}, year = {2010}, pages = {1458--1465}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://vision.ai.illinois.edu/html-files-to-import/publications/yang_cvpr10a.pdf} +} +@article{yang1996structure, + title = {Structure adaptive anisotropic image filtering}, + author = {Yang, Guang-Zhong and Burger, Peter and Firmin, David N and Underwood, SR}, + journal = {Image and Vision Computing}, + volume = {14}, + number = {2}, + pages = {135--145}, + year = {1996}, + publisher = {Elsevier} +} +@article{YM11, + author = {Yu, Guoshen and Morel, Jean-Michel}, + title = {ASIFT: An Algorithm for Fully Affine Invariant Comparison}, + year = {2011}, + pages = {11--38}, + journal = {Image Processing On Line}, + volume = {1}, + doi = {10.5201/ipol.2011.my-asift}, + url = {http://www.ipol.im/pub/algo/my_affine_sift/} } @article{Yuen90, author = {Yuen, HK and Princen, John and Illingworth, John and Kittler, Josef}, @@ -1036,7 +1375,8 @@ journal = {Image and Vision Computing}, volume = {8}, number = {1}, - publisher = {Elsevier} + publisher = {Elsevier}, + url = {https://typeset.io/pdf/a-comparative-study-of-hough-transform-methods-for-circle-2mzwteha3d.pdf} } @incollection{Zach2007, author = {Zach, Christopher and Pock, Thomas and Bischof, Horst}, @@ -1044,7 +1384,8 @@ booktitle = {Pattern Recognition}, year = {2007}, pages = {214--223}, - publisher = {Springer} + publisher = {Springer}, + url = {https://www.researchgate.net/publication/248964741_A_Duality_Based_Approach_for_Realtime_TV-L1_Optical_Flow} } @article{Zhang2000, author = {Zhang, Zhengyou}, @@ -1054,7 +1395,16 @@ journal = {Pattern Analysis and Machine Intelligence, IEEE Transactions on}, volume = {22}, number = {11}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr98-71.pdf} +} +@inproceedings{zhou2017east, + title = {East: an efficient and accurate scene text detector}, + author = {Zhou, Xinyu and Yao, Cong and Wen, He and Wang, Yuzhi and Zhou, Shuchang and He, Weiran and Liang, Jiajun}, + booktitle = {Proceedings of the IEEE conference on Computer Vision and Pattern Recognition}, + pages = {5551--5560}, + year = {2017}, + url = {https://arxiv.org/abs/1704.03155} } @inproceedings{Zivkovic2004, author = {Zivkovic, Zoran}, @@ -1063,7 +1413,8 @@ year = {2004}, pages = {28--31}, volume = {2}, - publisher = {IEEE} + publisher = {IEEE}, + url = {https://www.researchgate.net/publication/4090386_Improved_Adaptive_Gaussian_Mixture_Model_for_Background_Subtraction} } @article{Zivkovic2006, author = {Zivkovic, Zoran and van der Heijden, Ferdinand}, @@ -1076,124 +1427,9 @@ publisher = {Elsevier} } @inproceedings{Zuliani2014RANSACFD, - title={RANSAC for Dummies With examples using the RANSAC toolbox for Matlab \& Octave and more...}, - author={Marco Zuliani}, - year={2014}, - url = {https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.475.1243&rep=rep1&type=pdf} -} -@inproceedings{arthur_kmeanspp_2007, - author = {Arthur, David and Vassilvitskii, Sergei}, - title = {k-means++: The advantages of careful seeding}, - booktitle = {Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms}, - year = {2007}, - pages = {1027--1035}, - publisher = {Society for Industrial and Applied Mathematics} -} -@article{mitchell2005logistic, - author = {Mitchell, Tom M}, - title = {Logistic Regression}, - year = {2005}, - pages = {701}, - journal = {Machine learning}, - volume = {10} -} -@inproceedings{vacavant2013benchmark, - title = {A benchmark dataset for outdoor foreground/background extraction}, - author = {Vacavant, Antoine and Chateau, Thierry and Wilhelm, Alexis and Lequi{\`e}vre, Laurent}, - booktitle = {Computer Vision-ACCV 2012 Workshops}, - pages = {291--300}, - year = {2013}, - publisher = {Springer} -} -@incollection{nister2008linear, - title = {Linear time maximally stable extremal regions}, - author = {Nist{\'e}r, David and Stew{\'e}nius, Henrik}, - booktitle = {Computer Vision--ECCV 2008}, - pages = {183--196}, - year = {2008}, - publisher = {Springer} -} -@inproceedings{forssen2007maximally, - title = {Maximally stable colour regions for recognition and matching}, - author = {Forss{\'e}n, Per-Erik}, - booktitle = {Computer Vision and Pattern Recognition, 2007. CVPR'07. IEEE Conference on}, - pages = {1--8}, - year = {2007}, - publisher = {IEEE} -} -@inproceedings{Ke17, - author = {Ke, Tong and Roumeliotis, Stergios}, - title = {An Efficient Algebraic Solution to the Perspective-Three-Point Problem}, - booktitle = {Computer Vision and Pattern Recognition (CVPR), 2017 IEEE Conference on}, - year = {2017}, - publisher = {IEEE} -} -@article{gonzalez, - title = {Digital Image Fundamentals, Digital Imaging Processing}, - author = {Gonzalez, Rafael C and others}, - year = {1987}, - publisher = {Addison Wesley Publishing Company} -} -@article{gruzman, - title = {Ð¦Ð¸Ñ„Ñ€Ð¾Ð²Ð°Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ° изображений в информационных ÑиÑтемах}, - author = {Грузман, И.С. and Киричук, Ð’.С. and КоÑых, Ð’.П. and ПеретÑгин, Г.И. and Спектор, Ð.Ð.}, - year = {2000}, - publisher = {Изд-во ÐГТУ ÐовоÑибирÑк} -} -@inproceedings{duda2018, - title = {Accurate Detection and Localization of Checkerboard Corners for Calibration}, - year = {2018}, - booktitle = {29th British Machine Vision Conference. British Machine Vision Conference (BMVC-29), September 3-6, Newcastle, United Kingdom}, - publisher = {BMVA Press}, - author = {Duda, Alexander and Frese, Udo} -} -@book{jahne2000computer, - title = {Computer vision and applications: a guide for students and practitioners}, - author = {Jahne, Bernd}, - year = {2000}, - publisher = {Elsevier} -} -@book{bigun2006vision, - title = {Vision with direction}, - author = {Bigun, Josef}, - year = {2006}, - publisher = {Springer} -} -@inproceedings{van1995estimators, - title = {Estimators for orientation and anisotropy in digitized images}, - author = {Van Vliet, Lucas J and Verbeek, Piet W}, - booktitle = {ASCI}, - volume = {95}, - pages = {16--18}, - year = {1995} -} -@article{yang1996structure, - title = {Structure adaptive anisotropic image filtering}, - author = {Yang, Guang-Zhong and Burger, Peter and Firmin, David N and Underwood, SR}, - journal = {Image and Vision Computing}, - volume = {14}, - number = {2}, - pages = {135--145}, - year = {1996}, - publisher = {Elsevier} -} -@Article{Wu2009, - author={Wu, Kesheng - and Otoo, Ekow - and Suzuki, Kenji}, - title={Optimizing two-pass connected-component labeling algorithms}, - journal={Pattern Analysis and Applications}, - year={2009}, - month={Jun}, - day={01}, - volume={12}, - number={2}, - pages={117-135}, -} -@inproceedings{Zuliani2014RANSACFD, - title={RANSAC for Dummies With examples using the RANSAC toolbox for Matlab \& Octave and more...}, - author={Marco Zuliani}, - year={2014}, + title = {RANSAC for Dummies With examples using the RANSAC toolbox for Matlab \& Octave and more...}, + author = {Marco Zuliani}, + year = {2014}, url = {http://www.marcozuliani.com/docs/RANSAC4Dummies.pdf} } @inproceedings{forstner1987fast, diff --git a/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.markdown b/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.markdown index 06716fe5dc..a08a204d6c 100644 --- a/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.markdown +++ b/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.markdown @@ -24,6 +24,8 @@ red line. All the expected straight lines are bulged out. Visit [Distortion ![image](images/calib_radial.jpg) +In the following sections several new parameters are introduced. Visit [Camera Calibration and 3D Reconstruction](#tutorial_table_of_content_calib3d) for more details. + Radial distortion can be represented as follows: \f[x_{distorted} = x( 1 + k_1 r^2 + k_2 r^4 + k_3 r^6) \\ diff --git a/doc/tutorials/calib3d/camera_calibration/camera_calibration.markdown b/doc/tutorials/calib3d/camera_calibration/camera_calibration.markdown index a937b3e0fc..d3be7cef56 100644 --- a/doc/tutorials/calib3d/camera_calibration/camera_calibration.markdown +++ b/doc/tutorials/calib3d/camera_calibration/camera_calibration.markdown @@ -131,7 +131,7 @@ Explanation The formation of the equations I mentioned above aims to finding major patterns in the input: in case of the chessboard this are corners of the squares and for the circles, well, the circles themselves. ChArUco board is equivalent to - chessboard, but corners are mached by ArUco markers. The position of these will form the + chessboard, but corners are matched by ArUco markers. The position of these will form the result which will be written into the *pointBuf* vector. @snippet samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp find_pattern Depending on the type of the input pattern you use either the @ref cv::findChessboardCorners or @@ -144,9 +144,9 @@ Explanation @note Board size and amount of matched points is different for chessboard, circles grid and ChArUco. All chessboard related algorithm expects amount of inner corners as board width and height. - Board size of circles grid is just amount of circles by both grid dimentions. ChArUco board size + Board size of circles grid is just amount of circles by both grid dimensions. ChArUco board size is defined in squares, but detection result is list of inner corners and that's why is smaller - by 1 in both dimentions. + by 1 in both dimensions. Then again in case of cameras we only take camera images when an input delay time is passed. This is done in order to allow user moving the chessboard around and getting different images. diff --git a/doc/tutorials/calib3d/interactive_calibration/interactive_calibration.markdown b/doc/tutorials/calib3d/interactive_calibration/interactive_calibration.markdown index 4a16642475..2afd6a4fc5 100644 --- a/doc/tutorials/calib3d/interactive_calibration/interactive_calibration.markdown +++ b/doc/tutorials/calib3d/interactive_calibration/interactive_calibration.markdown @@ -12,7 +12,7 @@ Interactive camera calibration application {#tutorial_interactive_calibration} | Compatibility | OpenCV >= 3.1 | -According to classical calibration technique user must collect all data first and when run @ref cv::calibrateCamera function +According to classical calibration technique user must collect all data first and then run @ref cv::calibrateCamera function to obtain camera parameters. If average re-projection error is huge or if estimated parameters seems to be wrong, process of selection or collecting data and starting of @ref cv::calibrateCamera repeats. @@ -96,9 +96,9 @@ By default values of advanced parameters are stored in defaultConfig.xml - *charuco_square_length*: size of square on chAruco board (in pixels) - *charuco_marker_size*: size of Aruco markers on chAruco board (in pixels) - *calibration_step*: interval in frames between launches of @ref cv::calibrateCamera -- *max_frames_num*: if number of frames for calibration is greater then this value frames filter starts working. +- *max_frames_num*: if number of frames for calibration is greater than this value frames filter starts working. After filtration size of calibration dataset is equals to *max_frames_num* -- *min_frames_num*: if number of frames is greater then this value turns on auto flags tuning, undistorted view and quality evaluation +- *min_frames_num*: if number of frames is greater than this value turns on auto flags tuning, undistorted view and quality evaluation - *solver_eps*: precision of Levenberg-Marquardt solver in @ref cv::calibrateCamera - *solver_max_iters*: iterations limit of solver - *fast_solver*: if this value is nonzero and Lapack is found QR decomposition is used instead of SVD in solver. @@ -129,7 +129,7 @@ This pattern is very sensitive to quality of production and measurements. Data filtration ------ -When size of calibration dataset is greater then *max_frames_num* starts working +When size of calibration dataset is greater than *max_frames_num* starts working data filter. It tries to remove "bad" frames from dataset. Filter removes the frame on which \f$loss\_function\f$ takes maximum. diff --git a/doc/tutorials/calib3d/real_time_pose/real_time_pose.markdown b/doc/tutorials/calib3d/real_time_pose/real_time_pose.markdown index 1bba591074..48c38982ec 100644 --- a/doc/tutorials/calib3d/real_time_pose/real_time_pose.markdown +++ b/doc/tutorials/calib3d/real_time_pose/real_time_pose.markdown @@ -14,8 +14,7 @@ Real Time pose estimation of a textured object {#tutorial_real_time_pose} Nowadays, augmented reality is one of the top research topic in computer vision and robotics fields. The most elemental problem in augmented reality is the estimation of the camera pose respect of an -object in the case of computer vision area to do later some 3D rendering or in the case of robotics -obtain an object pose in order to grasp it and do some manipulation. However, this is not a trivial +object in the case of computer vision area to perform subsequent 3D rendering or, in robotics, to obtain an object pose for grasping and manipulation. However, this is not a trivial problem to solve due to the fact that the most common issue in image processing is the computational cost of applying a lot of algorithms or mathematical operations for solving a problem which is basic and immediately for humans. @@ -23,7 +22,7 @@ and immediately for humans. Goal ---- -In this tutorial is explained how to build a real time application to estimate the camera pose in +This tutorial explains how to build a real-time application to estimate the camera pose in order to track a textured object with six degrees of freedom given a 2D image and its 3D textured model. @@ -74,7 +73,7 @@ The tutorial consists of two main programs: -# **Model registration** - This application is exclusive to whom don't have a 3D textured model of the object to be detected. + This application is intended for users who do not have a 3D textured model of the object to be detected. You can use this program to create your own textured 3D model. This program only works for planar objects, then if you want to model an object with complex shape you should use a sophisticated software to create it. @@ -82,7 +81,7 @@ The tutorial consists of two main programs: The application needs an input image of the object to be registered and its 3D mesh. We have also to provide the intrinsic parameters of the camera with which the input image was taken. All the files need to be specified using the absolute path or the relative one from your application’s - working directory. If none files are specified the program will try to open the provided default + working directory. If no files are specified the program will try to open the provided default parameters. The application starts up extracting the ORB features and descriptors from the input image and @@ -97,7 +96,7 @@ The tutorial consists of two main programs: -# **Model detection** - The aim of this application is estimate in real time the object pose given its 3D textured model. + The aim of this application is to estimate in real time the object pose given its 3D textured model. The application starts up loading the 3D textured model in YAML file format with the same structure explained in the model registration program. From the scene, the ORB features and @@ -106,7 +105,7 @@ The tutorial consists of two main programs: Using the found matches along with @ref cv::solvePnPRansac function the `R` and `t` of the camera are computed. Finally, a KalmanFilter is applied in order to reject bad poses. - In the case that you compiled OpenCV with the samples, you can find it in opencv/build/bin/cpp-tutorial-pnp_detection\`. + In the case that you compiled OpenCV with the samples, you can find it in opencv/build/bin/cpp-tutorial-pnp_detection`. Then you can run the application and change some parameters: @code{.cpp} This program shows how to detect an object given its 3D textured model. You can choose to use a recorded video or the webcam. @@ -326,7 +325,7 @@ Here is explained in detail the code for the real time application: descriptors, match using *two Nearest Neighbour* the extracted descriptors with the given model descriptors and vice versa. Then, a ratio test is applied to the two direction matches in order to remove these matches which its distance ratio between the first and second best match is larger - than a given threshold. Finally, a symmetry test is applied in order the remove non symmetrical + than a given threshold. Finally, a symmetry test is applied in order to remove non symmetrical matches. @code{.cpp} void RobustMatcher::robustMatch( const cv::Mat& frame, std::vector& good_matches, @@ -489,7 +488,7 @@ Here is explained in detail the code for the real time application: } @endcode - In the following code are the 3th and 4th steps of the main algorithm. The first, calling the + In the following code are the 3rd and 4th steps of the main algorithm. The first, calling the above function and the second taking the output inliers vector from RANSAC to get the 2D scene points for drawing purpose. As seen in the code we must be sure to apply RANSAC if we have matches, in the other case, the function @ref cv::solvePnPRansac crashes due to any OpenCV *bug*. diff --git a/doc/tutorials/calib3d/usac.markdown b/doc/tutorials/calib3d/usac.markdown index 5ed87a59bb..98526f66ed 100644 --- a/doc/tutorials/calib3d/usac.markdown +++ b/doc/tutorials/calib3d/usac.markdown @@ -168,8 +168,8 @@ components: plays significant role as it requires less iterations, furthermore in average P3P solver has around 1.39 estimated models. Also, in new version of `solvePnPRansac(...)` - with `UsacParams` there is an options to pass empty intrinsic - matrix `InputOutputArray cameraMatrix`. If matrix is empty than + with `UsacParams` there is an option to pass empty intrinsic + matrix `InputOutputArray cameraMatrix`. If matrix is empty then using Direct Linear Transformation algorithm (PnP with 6 points) framework outputs not only rotation and translation vector but also calibration matrix. @@ -201,7 +201,7 @@ a neighborhood graph. In framework there are 3 options to do it: cells using hash-table. The method is described in @cite barath2019progressive. Less accurate than `NEIGH_FLANN_RADIUS`, although significantly faster. -Note, `NEIGH_FLANN_RADIUS` and `NEIGH_FLANN_RADIUS` are not able to PnP +Note, `NEIGH_FLANN_RADIUS` and `NEIGH_GRID` are not able to PnP solver, since there are 3D object points. New flags: @@ -236,7 +236,7 @@ A few other important parameters: 2. `loIterations` – number of iterations for Local Optimization method. *The default value is 10*. By increasing `loIterations` the output - model could be more accurate, however, the computationial time may + model could be more accurate, however, the computational time may also increase. 3. `loSampleSize` – maximum sample number for Local Optimization. *The @@ -253,7 +253,7 @@ There are three new sample files in opencv/samples directory. 1. `epipolar_lines.cpp` – input arguments of `main` function are two paths to images. Then correspondences are found using SIFT detector. Fundamental matrix is found using RANSAC from - tentative correspondences and epipolar lines are plot. + tentative correspondences and epipolar lines are plotted. 2. `essential_mat_reconstr.cpp` – input arguments are path to data file containing image names and single intrinsic matrix and directory @@ -266,4 +266,4 @@ There are three new sample files in opencv/samples directory. 3. `essential_mat_reconstr.py` – the same functionality as in .cpp file, however instead of clustering points to plane the 3D map of - object points is plot. + object points is plotted. diff --git a/doc/tutorials/imgproc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.markdown b/doc/tutorials/imgproc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.markdown index d2dc68bc90..becf08e287 100644 --- a/doc/tutorials/imgproc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.markdown +++ b/doc/tutorials/imgproc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.markdown @@ -24,7 +24,7 @@ In this tutorial you will learn: Theory ------ -@note The explanation is based on the books @cite gonzalez and @cite gruzman. Also, you can refer to Matlab's tutorial [Image Deblurring in Matlab] and the article [SmartDeblur]. +@note The explanation is based on the books @cite Gonzalez1987 and @cite gruzman. Also, you can refer to Matlab's tutorial [Image Deblurring in Matlab] and the article [SmartDeblur]. @note The out-of-focus image on this page is a real world image. The out-of-focus was achieved manually by camera optics. ### What is a degradation image model? diff --git a/doc/tutorials/imgproc/periodic_noise_removing_filter/periodic_noise_removing_filter.markdown b/doc/tutorials/imgproc/periodic_noise_removing_filter/periodic_noise_removing_filter.markdown index dff204a2f2..a613a1db37 100644 --- a/doc/tutorials/imgproc/periodic_noise_removing_filter/periodic_noise_removing_filter.markdown +++ b/doc/tutorials/imgproc/periodic_noise_removing_filter/periodic_noise_removing_filter.markdown @@ -20,7 +20,7 @@ In this tutorial you will learn: Theory ------ -@note The explanation is based on the book @cite gonzalez. The image on this page is a real world image. +@note The explanation is based on the book @cite Gonzalez1987. The image on this page is a real world image. Periodic noise produces spikes in the Fourier domain that can often be detected by visual analysis. diff --git a/doc/tutorials/introduction/config_reference/config_reference.markdown b/doc/tutorials/introduction/config_reference/config_reference.markdown index d2a1ab1adb..598383ab2b 100644 --- a/doc/tutorials/introduction/config_reference/config_reference.markdown +++ b/doc/tutorials/introduction/config_reference/config_reference.markdown @@ -293,31 +293,39 @@ TODO: other options: `WITH_OPENCL_SVM`, `WITH_OPENCLAMDFFT`, `WITH_OPENCLAMDBLAS Following formats can be read by OpenCV without help of any third-party library: -- [BMP](https://en.wikipedia.org/wiki/BMP_file_format) -- [HDR](https://en.wikipedia.org/wiki/RGBE_image_format) (`WITH_IMGCODEC_HDR`) -- [Sun Raster](https://en.wikipedia.org/wiki/Sun_Raster) (`WITH_IMGCODEC_SUNRASTER`) -- [PPM, PGM, PBM, PFM](https://en.wikipedia.org/wiki/Netpbm#File_formats) (`WITH_IMGCODEC_PXM`, `WITH_IMGCODEC_PFM`) +| Formats | Option | Default | +| --------| ------ | ------- | +| [BMP](https://en.wikipedia.org/wiki/BMP_file_format) | (Always) | _ON_ | +| [HDR](https://en.wikipedia.org/wiki/RGBE_image_format) | `WITH_IMGCODEC_HDR` | _ON_ | +| [Sun Raster](https://en.wikipedia.org/wiki/Sun_Raster) | `WITH_IMGCODEC_SUNRASTER` | _ON_ | +| [PPM, PGM, PBM, PAM](https://en.wikipedia.org/wiki/Netpbm#File_formats) | `WITH_IMGCODEC_PXM` | _ON_ | +| [PFM](https://en.wikipedia.org/wiki/Netpbm#File_formats) | `WITH_IMGCODEC_PFM` | _ON_ | +| [GIF](https://en.wikipedia.org/wiki/GIF) | `WITH_IMGCODEC_GIF` | _OFF_ | +### PNG, JPEG, TIFF, WEBP, JPEG 2000, EXR, JPEG XL support -### PNG, JPEG, TIFF, WEBP support - -| Formats | Option | Default | Force build own | -| --------| ------ | ------- | --------------- | -| [PNG](https://en.wikipedia.org/wiki/Portable_Network_Graphics) | `WITH_PNG` | _ON_ | `BUILD_PNG` | -| [JPEG](https://en.wikipedia.org/wiki/JPEG) | `WITH_JPEG` | _ON_ | `BUILD_JPEG` | -| [TIFF](https://en.wikipedia.org/wiki/TIFF) | `WITH_TIFF` | _ON_ | `BUILD_TIFF` | -| [WEBP](https://en.wikipedia.org/wiki/WebP) | `WITH_WEBP` | _ON_ | `BUILD_WEBP` | -| [JPEG2000 with OpenJPEG](https://en.wikipedia.org/wiki/OpenJPEG) | `WITH_OPENJPEG` | _ON_ | `BUILD_OPENJPEG` | -| [JPEG2000 with JasPer](https://en.wikipedia.org/wiki/JasPer) | `WITH_JASPER` | _ON_ (see note) | `BUILD_JASPER` | -| [EXR](https://en.wikipedia.org/wiki/OpenEXR) | `WITH_OPENEXR` | _ON_ | Not Supported (see note) | -| [JPEG XL](https://en.wikipedia.org/wiki/JPEG_XL) | `WITH_JPEGXL` | _ON_ | Not supported. (see note) | +| Formats | Library | Option | Default | Force build own | +| --------| ------- | ------ | ------- | --------------- | +| [PNG](https://en.wikipedia.org/wiki/Portable_Network_Graphics) | [libpng](https://en.wikipedia.org/wiki/Libpng)| `WITH_PNG` | _ON_ | `BUILD_PNG` | +|^| [libspng(simple png)](https://libspng.org/) | `WITH_SPNG` | _OFF_ | `BUILD_SPNG` | +| [JPEG](https://en.wikipedia.org/wiki/JPEG) | [libjpeg-turbo](https://en.wikipedia.org/wiki/Libjpeg) | `WITH_JPEG` | _ON_ | `BUILD_JPEG` | +|^| [libjpeg](https://en.wikipedia.org/wiki/Libjpeg) | `WITH_JPEG` | _OFF_ | `BUILD_JPEG` with `BUILD_JPEG_TURBO_DISABLE` | +| [TIFF](https://en.wikipedia.org/wiki/TIFF) | [LibTIFF](https://en.wikipedia.org/wiki/LibTIFF) | `WITH_TIFF` | _ON_ | `BUILD_TIFF` | +| [WebP](https://en.wikipedia.org/wiki/WebP) || `WITH_WEBP` | _ON_ | `BUILD_WEBP` | +| [JPEG 2000](https://en.wikipedia.org/wiki/JPEG_2000) | [OpenJPEG](https://en.wikipedia.org/wiki/OpenJPEG) | `WITH_OPENJPEG` | _ON_ | `BUILD_OPENJPEG` | +|^| [JasPer](https://en.wikipedia.org/wiki/JasPer) | `WITH_JASPER` | _ON_ (see note) | `BUILD_JASPER` | +| [OpenEXR](https://en.wikipedia.org/wiki/OpenEXR) || `WITH_OPENEXR` | _ON_ | `BUILD_OPENEXR` | +| [JPEG XL](https://en.wikipedia.org/wiki/JPEG_XL) || `WITH_JPEGXL` | _ON_ | Not supported. (see note) | All libraries required to read images in these formats are included into OpenCV and will be built automatically if not found at the configuration stage. Corresponding `BUILD_*` options will force building and using own libraries, they are enabled by default on some platforms, e.g. Windows. -@note OpenJPEG have higher priority than JasPer which is deprecated. In order to use JasPer, OpenJPEG must be disabled. +@note (All) Only one library for each image format can be enabled(e.g. In order to use JasPer for JPEG 2000 format, OpenJPEG must be disabled). +@note (JPEG 2000) OpenJPEG have higher priority than JasPer which is deprecated. @note (JPEG XL) OpenCV doesn't contain libjxl source code, so `BUILD_JPEGXL` is not supported. @note (EXR) OpenCV 5 doesn't contain OpenEXR source code, so `BUILD_OPENEXR` is not supported. +@warning OpenEXR ver 2.2 or earlier cannot be used in combination with C++17 or later. In this case, updating OpenEXR ver 2.3.0 or later is required. + ### GDAL integration `WITH_GDAL` (default: _OFF_) diff --git a/modules/3d/include/opencv2/3d.hpp b/modules/3d/include/opencv2/3d.hpp index 4120f3be56..71d3da9127 100644 --- a/modules/3d/include/opencv2/3d.hpp +++ b/modules/3d/include/opencv2/3d.hpp @@ -2650,6 +2650,42 @@ CV_EXPORTS_W bool solvePnP( InputArray objectPoints, InputArray imagePoints, TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 10, 1e-8) ); +/** +@brief Finds an object pose from 3D-2D point correspondences using the RANSAC scheme for fisheye camera moodel. + +@param objectPoints Array of object points in the object coordinate space, Nx3 1-channel or +1xN/Nx1 3-channel, where N is the number of points. vector\ can be also passed here. +@param imagePoints Array of corresponding image points, Nx2 1-channel or 1xN/Nx1 2-channel, +where N is the number of points. vector\ can be also passed here. +@param cameraMatrix Input camera intrinsic matrix \f$\cameramatrix{A}\f$ . +@param distCoeffs Input vector of distortion coefficients (4x1/1x4). +@param rvec Output rotation vector (see @ref Rodrigues ) that, together with tvec, brings points from +the model coordinate system to the camera coordinate system. +@param tvec Output translation vector. +@param useExtrinsicGuess Parameter used for #SOLVEPNP_ITERATIVE. If true (1), the function uses +the provided rvec and tvec values as initial approximations of the rotation and translation +vectors, respectively, and further optimizes them. +@param iterationsCount Number of iterations. +@param reprojectionError Inlier threshold value used by the RANSAC procedure. The parameter value +is the maximum allowed distance between the observed and computed point projections to consider it +an inlier. +@param confidence The probability that the algorithm produces a useful result. +@param inliers Output vector that contains indices of inliers in objectPoints and imagePoints . +@param flags Method for solving a PnP problem: see @ref calib3d_solvePnP_flags +@param criteria Termination criteria for internal undistortPoints call. +The function interally undistorts points with @ref undistortPoints and call @ref cv::solvePnP, +thus the input are very similar. More information about Perspective-n-Points is described in @ref calib3d_solvePnP +for more information. +*/ +CV_EXPORTS_W bool solvePnPRansac( InputArray objectPoints, InputArray imagePoints, + InputArray cameraMatrix, InputArray distCoeffs, + OutputArray rvec, OutputArray tvec, + bool useExtrinsicGuess = false, int iterationsCount = 100, + float reprojectionError = 8.0, double confidence = 0.99, + OutputArray inliers = noArray(), int flags = SOLVEPNP_ITERATIVE, + TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 10, 1e-8) + ); + } // namespace fisheye /** @brief Octree for 3D vision. diff --git a/modules/3d/src/fisheye.cpp b/modules/3d/src/fisheye.cpp index 14902b4467..32a1645782 100644 --- a/modules/3d/src/fisheye.cpp +++ b/modules/3d/src/fisheye.cpp @@ -646,4 +646,17 @@ bool cv::fisheye::solvePnP( InputArray opoints, InputArray ipoints, return cv::solvePnP(opoints, imagePointsNormalized, cameraMatrix, noArray(), rvec, tvec, useExtrinsicGuess, flags); } +bool cv::fisheye::solvePnPRansac( InputArray opoints, InputArray ipoints, + InputArray cameraMatrix, InputArray distCoeffs, + OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess, + int iterationsCount, float reprojectionError, + double confidence, OutputArray inliers, + int flags, TermCriteria criteria) +{ + Mat imagePointsNormalized; + cv::fisheye::undistortPoints(ipoints, imagePointsNormalized, cameraMatrix, distCoeffs, noArray(), cameraMatrix, criteria); + return cv::solvePnPRansac(opoints, imagePointsNormalized, cameraMatrix, noArray(), rvec, tvec, + useExtrinsicGuess, iterationsCount, reprojectionError, confidence, inliers, flags); +} + } // namespace cv diff --git a/modules/3d/src/fundam.cpp b/modules/3d/src/fundam.cpp index 2318e22cbf..8e67cc1d89 100644 --- a/modules/3d/src/fundam.cpp +++ b/modules/3d/src/fundam.cpp @@ -1297,7 +1297,7 @@ double sampsonDistance(InputArray _pt1, InputArray _pt2, InputArray _F) { CV_INSTRUMENT_REGION(); - CV_Assert(_pt1.type() == CV_64F && _pt2.type() == CV_64F && _F.type() == CV_64F); + CV_Assert(_pt1.depth() == CV_64F && _pt2.depth() == CV_64F && _F.depth() == CV_64F); CV_DbgAssert(_pt1.rows() == 3 && _F.size() == Size(3, 3) && _pt1.rows() == _pt2.rows()); Mat pt1(_pt1.getMat()); diff --git a/modules/3d/src/solvepnp.cpp b/modules/3d/src/solvepnp.cpp index b8571251fd..a4f03b0269 100644 --- a/modules/3d/src/solvepnp.cpp +++ b/modules/3d/src/solvepnp.cpp @@ -56,7 +56,7 @@ namespace cv { using namespace std; -#if defined _DEBUG || defined CV_STATIC_ANALYSIS +#if !defined(NDEBUG) || defined(CV_STATIC_ANALYSIS) static bool isPlanarObjectPoints(InputArray _objectPoints, double threshold) { CV_CheckType(_objectPoints.type(), _objectPoints.type() == CV_32FC3 || _objectPoints.type() == CV_64FC3, @@ -924,7 +924,7 @@ int solvePnPGeneric( InputArray _opoints, InputArray _ipoints, { CV_Assert(npoints == 4); -#if defined _DEBUG || defined CV_STATIC_ANALYSIS +#if !defined(NDEBUG) || defined(CV_STATIC_ANALYSIS) double Xs[4][3]; if (opoints.depth() == CV_32F) { diff --git a/modules/3d/test/test_fisheye.cpp b/modules/3d/test/test_fisheye.cpp index 74c2e62883..f77e14270f 100644 --- a/modules/3d/test/test_fisheye.cpp +++ b/modules/3d/test/test_fisheye.cpp @@ -245,6 +245,58 @@ TEST_F(fisheyeTest, solvePnP) ASSERT_TRUE(converged); } +TEST_F(fisheyeTest, solvePnPRansac) +{ + const int inliers_n = 16; + const int outliers_n = 4; + const bool use_extrinsic_guess = false; + const int iterations_count = 100; + const float reprojection_error = 1.0; + const double confidence = 0.99; + + const cv::Matx33d R_mat ( 9.9756700084424932e-01, 6.9698277640183867e-02, 1.4929569991321144e-03, + -6.9711825162322980e-02, 9.9748249845531767e-01, 1.2997180766418455e-02, + -5.8331736398316541e-04,-1.3069635393884985e-02, 9.9991441852366736e-01); + + const cv::Vec3d T(-9.9217369356044638e-02, 3.1741831972356663e-03, 1.8551007952921010e-04); + + cv::Mat rvec; + cv::Rodrigues(R_mat, rvec); + + // inliers + cv::Mat inlier_obj_points(1, inliers_n, CV_64FC3); + theRNG().fill(inlier_obj_points, cv::RNG::NORMAL, 2, 1); + inlier_obj_points = cv::abs(inlier_obj_points) * 10; + cv::Mat inlier_img_points; + cv::fisheye::projectPoints(inlier_obj_points, inlier_img_points, rvec, T, this->K, this->D); + + // outliers + cv::Mat outlier_obj_points(1, outliers_n, CV_64FC3); + theRNG().fill(outlier_obj_points, cv::RNG::NORMAL, 2, 1); + outlier_obj_points = cv::abs(outlier_obj_points) * 10; + cv::Mat outlier_img_points; + cv::fisheye::projectPoints(outlier_obj_points, outlier_img_points, rvec, (T * 10), this->K, this->D); + + cv::Mat obj_points; + cv::hconcat(outlier_obj_points, inlier_obj_points, obj_points); + + cv::Mat img_points; + cv::hconcat(outlier_img_points, inlier_img_points, img_points); + + cv::Mat rvec_pred; + cv::Mat tvec_pred; + cv::Mat inliers_pred; + + bool converged = cv::fisheye::solvePnPRansac(obj_points, img_points, this->K, this->D, + rvec_pred, tvec_pred, use_extrinsic_guess, + iterations_count, reprojection_error, confidence, inliers_pred); + + EXPECT_MAT_NEAR(rvec, rvec_pred, 1e-5); + EXPECT_MAT_NEAR(T, tvec_pred, 1e-5); + EXPECT_EQ(inliers_pred.size[0], inliers_n); + ASSERT_TRUE(converged); +} + TEST_F(fisheyeTest, undistortImage) { // we use it to reduce patch size for images in testdata diff --git a/modules/calib/misc/python/test/test_calibration.py b/modules/calib/misc/python/test/test_calibration.py index c3093ce2ef..8c3e2c6467 100755 --- a/modules/calib/misc/python/test/test_calibration.py +++ b/modules/calib/misc/python/test/test_calibration.py @@ -84,5 +84,13 @@ class calibration_test(NewOpenCVTests): self.assertTrue(imagePoints is not None) self.assertTrue(jacobian is not None) + def test_sampsonDistance_valid2D(self): + pt1 = (np.random.rand(3, 10) * 256).astype(np.float64) + pt2 = (np.random.rand(3, 10) * 256).astype(np.float64) + F = (np.random.rand(3, 3) * 256).astype(np.float64) + dist = cv.sampsonDistance(pt1, pt2, F) + self.assertTrue(isinstance(dist, (float, np.floating))) + self.assertGreaterEqual(dist, 0.0) + if __name__ == '__main__': NewOpenCVTests.bootstrap() diff --git a/modules/calib/src/chessboard.cpp b/modules/calib/src/chessboard.cpp index 5f526addf7..9b24148473 100644 --- a/modules/calib/src/chessboard.cpp +++ b/modules/calib/src/chessboard.cpp @@ -3720,10 +3720,11 @@ Chessboard::Board Chessboard::detectImpl(const Mat& gray,std::vector &f continue; } + iter_boards->normalizeOrientation(false); + if(iter_boards->getSize() == parameters.chessboard_size || iter_boards->getSize() == chessboard_size2) { - iter_boards->normalizeOrientation(false); if(iter_boards->getSize() != parameters.chessboard_size) { if(iter_boards->isCellBlack(0,0) == iter_boards->isCellBlack(0,int(iter_boards->colCount())-1)) diff --git a/modules/calib/test/test_chesscorners.cpp b/modules/calib/test/test_chesscorners.cpp index 3d13602780..f391e42e6a 100644 --- a/modules/calib/test/test_chesscorners.cpp +++ b/modules/calib/test/test_chesscorners.cpp @@ -849,5 +849,18 @@ TEST(Calib3d_RotatedCirclesPatternDetector, issue_24964) EXPECT_LE(error, precise_success_error_level); } +TEST(Calib3d_CornerOrdering, issue_26830) { + const cv::String dataDir = string(TS::ptr()->get_data_path()) + "cv/cameracalibration/"; + const cv::Mat image = cv::imread(dataDir + "checkerboard_marker_white.png"); + + std::vector cornersMinimumSizeMatchesPatternSize; + ASSERT_TRUE(cv::findChessboardCornersSB(image, Size(14, 9), cornersMinimumSizeMatchesPatternSize, CALIB_CB_MARKER | CALIB_CB_LARGER)); + + std::vector cornersMinimumSizeSmallerThanPatternSize; + ASSERT_TRUE(cv::findChessboardCornersSB(image, Size(4, 4), cornersMinimumSizeSmallerThanPatternSize, CALIB_CB_MARKER | CALIB_CB_LARGER)); + + ASSERT_EQ(cornersMinimumSizeMatchesPatternSize, cornersMinimumSizeSmallerThanPatternSize); +} + }} // namespace /* End of file. */ diff --git a/modules/core/CMakeLists.txt b/modules/core/CMakeLists.txt index d8a2b7ae7e..82d820f3b3 100644 --- a/modules/core/CMakeLists.txt +++ b/modules/core/CMakeLists.txt @@ -117,6 +117,12 @@ endif() if(HAVE_WIN32_ALIGNED_MALLOC) ocv_append_source_file_compile_definitions(${CMAKE_CURRENT_SOURCE_DIR}/src/alloc.cpp "HAVE_WIN32_ALIGNED_MALLOC=1") endif() +if(HAVE_GETAUXVAL) + ocv_append_source_file_compile_definitions(${CMAKE_CURRENT_SOURCE_DIR}/src/system.cpp "HAVE_GETAUXVAL=1") +endif() +if(HAVE_ELF_AUX_INFO) + ocv_append_source_file_compile_definitions(${CMAKE_CURRENT_SOURCE_DIR}/src/system.cpp "HAVE_ELF_AUX_INFO=1") +endif() if(HAVE_VA_INTEL_OLD_HEADER) ocv_append_source_file_compile_definitions("${CMAKE_CURRENT_LIST_DIR}/src/va_intel.cpp" "HAVE_VA_INTEL_OLD_HEADER") endif() diff --git a/modules/core/include/opencv2/core/base.hpp b/modules/core/include/opencv2/core/base.hpp index 1d50fb61ea..4975f9df97 100644 --- a/modules/core/include/opencv2/core/base.hpp +++ b/modules/core/include/opencv2/core/base.hpp @@ -197,8 +197,72 @@ enum DftFlags { DCT_ROWS = DFT_ROWS }; -//! Various border types, image boundaries are denoted with `|` -//! @see borderInterpolate, copyMakeBorder +/*! Various border types, image boundaries are denoted with the `|` character in the table below, when describing each method. + +The following examples show the result of the @ref copyMakeBorder call according to different methods. +Input image is `6x4` (width x height) size and the @ref copyMakeBorder function is used with a border size of 2 pixels +in each direction, giving a resulting image of `10x8` resolution. + +@code +Input image: +[[ 0 1 2 3 4 5] + [ 6 7 8 9 10 11] + [12 13 14 15 16 17] + [18 19 20 21 22 23]] + +Border type: BORDER_CONSTANT (a constant value of 255 is used) +[[255 255 255 255 255 255 255 255 255 255] + [255 255 255 255 255 255 255 255 255 255] + [255 255 0 1 2 3 4 5 255 255] + [255 255 6 7 8 9 10 11 255 255] + [255 255 12 13 14 15 16 17 255 255] + [255 255 18 19 20 21 22 23 255 255] + [255 255 255 255 255 255 255 255 255 255] + [255 255 255 255 255 255 255 255 255 255]] + +Border type: BORDER_REPLICATE +[[ 0 0 0 1 2 3 4 5 5 5] + [ 0 0 0 1 2 3 4 5 5 5] + [ 0 0 0 1 2 3 4 5 5 5] + [ 6 6 6 7 8 9 10 11 11 11] + [12 12 12 13 14 15 16 17 17 17] + [18 18 18 19 20 21 22 23 23 23] + [18 18 18 19 20 21 22 23 23 23] + [18 18 18 19 20 21 22 23 23 23]] + +Border type: BORDER_REFLECT +[[ 7 6 6 7 8 9 10 11 11 10] + [ 1 0 0 1 2 3 4 5 5 4] + [ 1 0 0 1 2 3 4 5 5 4] + [ 7 6 6 7 8 9 10 11 11 10] + [13 12 12 13 14 15 16 17 17 16] + [19 18 18 19 20 21 22 23 23 22] + [19 18 18 19 20 21 22 23 23 22] + [13 12 12 13 14 15 16 17 17 16]] + +Border type: BORDER_WRAP +[[16 17 12 13 14 15 16 17 12 13] + [22 23 18 19 20 21 22 23 18 19] + [ 4 5 0 1 2 3 4 5 0 1] + [10 11 6 7 8 9 10 11 6 7] + [16 17 12 13 14 15 16 17 12 13] + [22 23 18 19 20 21 22 23 18 19] + [ 4 5 0 1 2 3 4 5 0 1] + [10 11 6 7 8 9 10 11 6 7]] + +Border type: BORDER_REFLECT_101 +[[14 13 12 13 14 15 16 17 16 15] + [ 8 7 6 7 8 9 10 11 10 9] + [ 2 1 0 1 2 3 4 5 4 3] + [ 8 7 6 7 8 9 10 11 10 9] + [14 13 12 13 14 15 16 17 16 15] + [20 19 18 19 20 21 22 23 22 21] + [14 13 12 13 14 15 16 17 16 15] + [ 8 7 6 7 8 9 10 11 10 9]] +@endcode + +@see borderInterpolate, copyMakeBorder + */ enum BorderTypes { BORDER_CONSTANT = 0, //!< `iiiiii|abcdefgh|iiiiiii` with some specified `i` BORDER_REPLICATE = 1, //!< `aaaaaa|abcdefgh|hhhhhhh` @@ -214,7 +278,6 @@ enum BorderTypes { //! @} core_array - //! @addtogroup core_utils //! @{ diff --git a/modules/core/include/opencv2/core/private.hpp b/modules/core/include/opencv2/core/private.hpp index 074607eb7d..93a81d9005 100644 --- a/modules/core/include/opencv2/core/private.hpp +++ b/modules/core/include/opencv2/core/private.hpp @@ -202,6 +202,7 @@ T* allocSingletonNew() { return new(allocSingletonNewBuffer(sizeof(T))) T(); } #define IPP_DISABLE_XYZ_RGB 1 // big accuracy difference #define IPP_DISABLE_HOUGH 1 // improper integration/results #define IPP_DISABLE_FILTER2D_BIG_MASK 1 // different results on masks > 7x7 +#define IPP_DISABLE_NORM_8U 1 // accuracy difference in perf test sanity check // Temporary disabled named IPP region. Performance #define IPP_DISABLE_PERF_COPYMAKE 1 // performance variations diff --git a/modules/core/include/opencv2/core/vsx_utils.hpp b/modules/core/include/opencv2/core/vsx_utils.hpp index 79a1074d59..4d5a694bae 100644 --- a/modules/core/include/opencv2/core/vsx_utils.hpp +++ b/modules/core/include/opencv2/core/vsx_utils.hpp @@ -257,8 +257,8 @@ VSX_IMPL_1VRG(vec_udword2, vec_udword2, vpopcntd, vec_popcntu) VSX_IMPL_1VRG(vec_udword2, vec_dword2, vpopcntd, vec_popcntu) // converts between single and double-precision -VSX_REDIRECT_1RG(vec_float4, vec_double2, vec_cvfo, __builtin_vsx_xvcvdpsp) -VSX_REDIRECT_1RG(vec_double2, vec_float4, vec_cvfo, __builtin_vsx_xvcvspdp) +VSX_REDIRECT_1RG(vec_float4, vec_double2, vec_cvfo, vec_floate) +VSX_REDIRECT_1RG(vec_double2, vec_float4, vec_cvfo, vec_doubleo) // converts word and doubleword to double-precision #undef vec_ctd @@ -399,10 +399,6 @@ VSX_REDIRECT_1RG(vec_ushort8, vec_ushort8, vec_popcntu, vec_popcnt) VSX_REDIRECT_1RG(vec_uint4, vec_uint4, vec_popcntu, vec_popcnt) VSX_REDIRECT_1RG(vec_udword2, vec_udword2, vec_popcntu, vec_popcnt) -// converts between single and double precision -VSX_REDIRECT_1RG(vec_float4, vec_double2, vec_cvfo, __builtin_vsx_xvcvdpsp) -VSX_REDIRECT_1RG(vec_double2, vec_float4, vec_cvfo, __builtin_vsx_xvcvspdp) - // converts word and doubleword to double-precision #ifdef vec_ctd # undef vec_ctd diff --git a/modules/core/src/convert.dispatch.cpp b/modules/core/src/convert.dispatch.cpp index d710810fec..c18fc2faef 100644 --- a/modules/core/src/convert.dispatch.cpp +++ b/modules/core/src/convert.dispatch.cpp @@ -167,6 +167,15 @@ void Mat::convertTo(OutputArray dst, int type_, double alpha, double beta) const dst.create( dims, size, dtype, -1, allowTransposed ); Mat dstMat = dst.getMat(); + if( dims <= 2 ) + { + CALL_HAL(convertScale, cv_hal_convertScale, src.data, src.step, dstMat.data, dstMat.step, src.cols * cn, src.rows, sdepth, ddepth, alpha, beta); + } + else if( src.isContinuous() && dstMat.isContinuous() ) + { + CALL_HAL(convertScale, cv_hal_convertScale, src.data, 0, dstMat.data, 0, (int)src.total() * cn, 1, sdepth, ddepth, alpha, beta); + } + BinaryFunc func = noScale ? getConvertFunc(sdepth, ddepth) : getConvertScaleFunc(sdepth, ddepth); double scale[] = {alpha, beta}; CV_Assert( func != 0 ); diff --git a/modules/core/src/hal_replacement.hpp b/modules/core/src/hal_replacement.hpp index 9b7b73718c..1df71244e2 100644 --- a/modules/core/src/hal_replacement.hpp +++ b/modules/core/src/hal_replacement.hpp @@ -214,7 +214,7 @@ inline int hal_ni_absDiffScalar8u8u (const uchar* src_data, size_t src_step, uc Bitwise AND: _dst[i] = src1[i] & src2[i]_ @n Bitwise OR: _dst[i] = src1[i] | src2[i]_ @n Bitwise XOR: _dst[i] = src1[i] ^ src2[i]_ @n -Bitwise NOT: _dst[i] = !src[i]_ +Bitwise NOT: _dst[i] = ~src[i]_ @param src1_data first source image data @param src1_step first source image step @param src2_data second source image data @@ -313,7 +313,7 @@ For 8s input type 128 is added to LUT index Destination should have the same element type and number of channels as lookup table elements @param src_data Source image data @param src_step Source image step -@param src_type Sorce image type +@param src_type Source image type @param lut_data Pointer to lookup table @param lut_channel_size Size of each channel in bytes @param lut_channels Number of channels in lookup table @@ -357,9 +357,69 @@ Hamming distance between two vectors inline int hal_ni_normHammingDiff8u(const uchar* a, const uchar* b, int n, int cellSize, int* result) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } //! @} +/** +@brief Generic norm of an array. +@param src Source image +@param src_step Source image +@param mask Specified array region. +@param mask_step Mask array step. +@param width Source image dimensions +@param height Source image dimensions +@param type Element type of source image +@param norm_type Type of the norm +@param result Pointer to result output +*/ +//! @addtogroup core_hal_interface_norm Absolute norm +//! @{ +inline int hal_ni_norm(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, + int height, int type, int norm_type, double* result) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +//! @} + +/** +@brief Generic norm between two arrays. +@param src1 First source image +@param src1_step First source image +@param src2 Second source image +@param src2_step Second source image +@param mask Specified array region. +@param mask_step Mask array step. +@param width Source image dimensions +@param height Source image dimensions +@param type Element type of source image +@param norm_type Type of the norm +@param result Pointer to result output +*/ +//! @addtogroup core_hal_interface_norm Absolute norm +//! @{ +inline int hal_ni_normDiff(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, + size_t mask_step, int width, int height, int type, int norm_type, double* result) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +//! @} + +/** +@brief Convert array to another with specified type. +@param src Source image +@param src_step Source image +@param dst Destination image +@param dst_step Destination image +@param width Source image dimensions +@param height Source image dimensions +@param sdepth Depth of source image +@param ddepth Depth of destination image +@param alpha Scale value +@param beta Shift value +*/ +//! @addtogroup core_hal_interface_convert Array convert +//! @{ +inline int hal_ni_convertScale(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, + int sdepth, int ddepth, double alpha, double beta) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +//! @} + //! @cond IGNORED #define cv_hal_normHamming8u hal_ni_normHamming8u #define cv_hal_normHammingDiff8u hal_ni_normHammingDiff8u +#define cv_hal_norm hal_ni_norm +#define cv_hal_normDiff hal_ni_normDiff +#define cv_hal_convertScale hal_ni_convertScale //! @endcond /** @@ -464,7 +524,7 @@ inline int hal_ni_div16bf(const cv_hal_bf16 *src1_data, size_t src1_step, const //! @} /** -Computes reciprocial: _dst[i] = scale / src[i]_ +Computes reciprocal: _dst[i] = scale / src[i]_ @param src_data source image data @param src_step source image step @param dst_data destination image data @@ -473,7 +533,7 @@ Computes reciprocial: _dst[i] = scale / src[i]_ @param height height of the images @param scale additional multiplier */ -//! @addtogroup core_hal_interface_reciprocial Element-wise reciprocial +//! @addtogroup core_hal_interface_reciprocal Element-wise reciprocal //! @{ inline int hal_ni_recip8u(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } inline int hal_ni_recip8s(const schar *src_data, size_t src_step, schar *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } @@ -864,14 +924,14 @@ inline int hal_ni_dctFree2D(cvhalDFT *context) { return CV_HAL_ERROR_NOT_IMPLEME Performs \f$LU\f$ decomposition of square matrix \f$A=P*L*U\f$ (where \f$P\f$ is permutation matrix) and solves matrix equation \f$A*X=B\f$. Function returns the \f$sign\f$ of permutation \f$P\f$ via parameter info. @param src1 pointer to input matrix \f$A\f$ stored in row major order. After finish of work src1 contains at least \f$U\f$ part of \f$LU\f$ -decomposition which is appropriate for determainant calculation: \f$det(A)=sign*\prod_{j=1}^{M}a_{jj}\f$. +decomposition which is appropriate for determinant calculation: \f$det(A)=sign*\prod_{j=1}^{M}a_{jj}\f$. @param src1_step number of bytes between two consequent rows of matrix \f$A\f$. @param m size of square matrix \f$A\f$. @param src2 pointer to \f$M\times N\f$ matrix \f$B\f$ which is the right-hand side of system \f$A*X=B\f$. \f$B\f$ stored in row major order. If src2 is null pointer only \f$LU\f$ decomposition will be performed. After finish of work src2 contains solution \f$X\f$ of system \f$A*X=B\f$. @param src2_step number of bytes between two consequent rows of matrix \f$B\f$. @param n number of right-hand vectors in \f$M\times N\f$ matrix \f$B\f$. -@param info indicates success of decomposition. If *info is equals to zero decomposition failed, othervise *info is equals to \f$sign\f$. +@param info indicates success of decomposition. If *info is equals to zero decomposition failed, otherwise *info is equals to \f$sign\f$. */ //! @addtogroup core_hal_interface_decomp_lu LU matrix decomposition //! @{ @@ -1011,8 +1071,26 @@ inline int hal_ni_gemm64fc(const double* src1, size_t src1_step, const double* s inline int hal_ni_minMaxIdx(const uchar* src_data, size_t src_step, int width, int height, int depth, double* minVal, double* maxVal, int* minIdx, int* maxIdx, uchar* mask) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +/** + @brief Finds the global minimum and maximum in an array. + @param src_data Source image + @param src_step Source image + @param width Source image dimensions + @param height Source image dimensions + @param depth Depth of source image + @param minVal Pointer to the returned global minimum and maximum in an array. + @param maxVal Pointer to the returned global minimum and maximum in an array. + @param minIdx Pointer to the returned minimum and maximum location. + @param maxIdx Pointer to the returned minimum and maximum location. + @param mask Specified array region. + @param mask_step Mask array step. +*/ +inline int hal_ni_minMaxIdxMaskStep(const uchar* src_data, size_t src_step, int width, int height, int depth, double* minVal, double* maxVal, + int* minIdx, int* maxIdx, uchar* mask, size_t mask_step) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } + //! @cond IGNORED #define cv_hal_minMaxIdx hal_ni_minMaxIdx +#define cv_hal_minMaxIdxMaskStep hal_ni_minMaxIdxMaskStep //! @endcond /** @@ -1126,26 +1204,23 @@ inline int hal_ni_transpose2d(const uchar* src_data, size_t src_step, uchar* dst #include "custom_hal.hpp" //! @cond IGNORED -#define CALL_HAL_RET(name, fun, retval, ...) \ + +#define CALL_HAL_RET2(name, fun, retval, ...) \ { \ - int res = __CV_EXPAND(fun(__VA_ARGS__, &retval)); \ + int res = __CV_EXPAND(fun(__VA_ARGS__)); \ if (res == CV_HAL_ERROR_OK) \ return retval; \ else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) \ CV_Error_(cv::Error::StsInternal, \ - ("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res)); \ + ("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res)); \ } +#define CALL_HAL_RET(name, fun, retval, ...) \ +CALL_HAL_RET2(name, fun, retval, __VA_ARGS__, &retval) #define CALL_HAL(name, fun, ...) \ -{ \ - int res = __CV_EXPAND(fun(__VA_ARGS__)); \ - if (res == CV_HAL_ERROR_OK) \ - return; \ - else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) \ - CV_Error_(cv::Error::StsInternal, \ - ("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res)); \ -} +CALL_HAL_RET2(name, fun, ,__VA_ARGS__) + //! @endcond #endif diff --git a/modules/core/src/lut.cpp b/modules/core/src/lut.cpp index 008a4e212a..a08b176f5e 100644 --- a/modules/core/src/lut.cpp +++ b/modules/core/src/lut.cpp @@ -363,7 +363,6 @@ void cv::LUT( InputArray _src, InputArray _lut, OutputArray _dst ) _dst.createSameSize(_src, CV_MAKETYPE(_lut.depth(), cn)); Mat dst = _dst.getMat(); - CALL_HAL(LUT, cv_hal_lut, src.data, src.step, src.type(), lut.data, lut.elemSize1(), lutcn, dst.data, dst.step, src.cols, src.rows); diff --git a/modules/core/src/matrix_operations.cpp b/modules/core/src/matrix_operations.cpp index 774ae6ad3a..b2f4daabfd 100644 --- a/modules/core/src/matrix_operations.cpp +++ b/modules/core/src/matrix_operations.cpp @@ -92,7 +92,7 @@ void cv::hconcat(InputArray _src, OutputArray dst) std::vector src; _src.getMatVector(src); - hconcat(!src.empty() ? &src[0] : 0, src.size(), dst); + hconcat(!src.empty() ? &src[0] : nullptr, src.size(), dst); } void cv::vconcat(const Mat* src, size_t nsrc, OutputArray _dst) @@ -137,7 +137,7 @@ void cv::vconcat(InputArray _src, OutputArray dst) std::vector src; _src.getMatVector(src); - vconcat(!src.empty() ? &src[0] : 0, src.size(), dst); + vconcat(!src.empty() ? &src[0] : nullptr, src.size(), dst); } //////////////////////////////////////// set identity //////////////////////////////////////////// @@ -175,7 +175,7 @@ static bool ocl_setIdentity( InputOutputArray _m, const Scalar& s ) ocl::KernelArg::Constant(Mat(1, 1, sctype, s))); size_t globalsize[2] = { (size_t)m.cols * cn / kercn, ((size_t)m.rows + rowsPerWI - 1) / rowsPerWI }; - return k.run(2, globalsize, NULL, false); + return k.run(2, globalsize, nullptr, false); } } @@ -216,8 +216,9 @@ void cv::setIdentity( InputOutputArray _m, const Scalar& s ) for( int i = 0; i < rows; i++, data += step ) { - for( int j = 0; j < cols; j++ ) - data[j] = j == i ? val : 0; + std::fill(data, data + cols, 0.0); + if (i < cols) + data[i] = val; } } else diff --git a/modules/core/src/mean.dispatch.cpp b/modules/core/src/mean.dispatch.cpp index 745a4f2d17..3c4a0893af 100644 --- a/modules/core/src/mean.dispatch.cpp +++ b/modules/core/src/mean.dispatch.cpp @@ -129,13 +129,29 @@ Scalar mean(InputArray _src, InputArray _mask) CV_Assert( mask.empty() || mask.type() == CV_8U || mask.type() == CV_8S || mask.type() == CV_Bool); int k, cn = src.channels(), depth = src.depth(); - Scalar s; + Scalar s = Scalar::all(0.0); + + CV_Assert( cn <= 4 ); CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_mean(src, mask, s), s) + if (src.isContinuous() && mask.isContinuous()) + { + CALL_HAL_RET2(meanStdDev, cv_hal_meanStdDev, s, src.data, 0, (int)src.total(), 1, src.type(), + &s[0], nullptr /*stddev*/, mask.data, 0); + } + else + { + if (src.dims <= 2) + { + CALL_HAL_RET2(meanStdDev, cv_hal_meanStdDev, s, src.data, src.step, src.cols, src.rows, src.type(), + &s[0], nullptr, mask.data, mask.step); + } + } + SumFunc func = getSumFunc(depth); - CV_Assert( cn <= 4 && func != 0 ); + CV_Assert( func != 0 ); const Mat* arrays[] = {&src, &mask, 0}; uchar* ptrs[2] = {}; @@ -318,7 +334,6 @@ static bool ocl_meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv } #endif - #ifdef HAVE_IPP static bool ipp_meanStdDev(Mat& src, OutputArray _mean, OutputArray _sdv, Mat& mask) { @@ -532,7 +547,8 @@ void meanStdDev(InputArray _src, OutputArray _mean, OutputArray _sdv, InputArray uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); int total = (int)it.size, blockSize = total, partialBlockSize = 0; - int j, count = 0, nz0 = 0; + int j; + int64_t count = 0, nz0 = 0; double _buf[CV_CN_MAX*4]; double *s = _buf, *sq = s + cn; int *sbuf = (int*)s, *sqbuf = (int*)sq; diff --git a/modules/core/src/minmax.dispatch.cpp b/modules/core/src/minmax.dispatch.cpp index 20e7bd2750..a79eadb543 100644 --- a/modules/core/src/minmax.dispatch.cpp +++ b/modules/core/src/minmax.dispatch.cpp @@ -314,10 +314,18 @@ void cv::minMaxIdx(InputArray _src, double* minVal, if (src.dims <= 2) { - CALL_HAL(minMaxIdx, cv_hal_minMaxIdx, src.data, src.step, src.cols*cn, src.rows, - src.depth(), minVal, maxVal, minIdx, maxIdx, mask.data); + if ((size_t)src.step == (size_t)mask.step) + { + CALL_HAL(minMaxIdx, cv_hal_minMaxIdx, src.data, src.step, src.cols*cn, src.rows, + src.depth(), minVal, maxVal, minIdx, maxIdx, mask.data); + } + else + { + CALL_HAL(minMaxIdxMaskStep, cv_hal_minMaxIdxMaskStep, src.data, src.step, src.cols*cn, src.rows, + src.depth(), minVal, maxVal, minIdx, maxIdx, mask.data, mask.step); + } } - else if (src.isContinuous()) + else if (src.isContinuous() && mask.isContinuous()) { int res = cv_hal_minMaxIdx(src.data, 0, (int)src.total()*cn, 1, src.depth(), minVal, maxVal, minIdx, maxIdx, mask.data); diff --git a/modules/core/src/norm.cpp b/modules/core/src/norm.cpp index c2b5b5a2f7..f462149497 100644 --- a/modules/core/src/norm.cpp +++ b/modules/core/src/norm.cpp @@ -756,7 +756,10 @@ static bool ipp_norm(Mat &src, int normType, Mat &mask, double &result) type == CV_16SC1 ? (ippiNormFuncNoHint)ippiNorm_L1_16s_C1R : 0) : normType == NORM_L2 || normType == NORM_L2SQR ? - (type == CV_8UC1 ? (ippiNormFuncNoHint)ippiNorm_L2_8u_C1R : + ( + #if !IPP_DISABLE_NORM_8U + type == CV_8UC1 ? (ippiNormFuncNoHint)ippiNorm_L2_8u_C1R : + #endif type == CV_16UC1 ? (ippiNormFuncNoHint)ippiNorm_L2_16u_C1R : type == CV_16SC1 ? (ippiNormFuncNoHint)ippiNorm_L2_16s_C1R : 0) : 0; @@ -800,9 +803,20 @@ double norm( InputArray _src, int normType, InputArray _mask ) #endif Mat src = _src.getMat(), mask = _mask.getMat(); + int depth = src.depth(), cn = src.channels(); + if( src.dims <= 2 ) + { + double result; + CALL_HAL_RET(norm, cv_hal_norm, result, src.data, src.step, mask.data, mask.step, src.cols, src.rows, src.type(), normType); + } + else if( src.isContinuous() && mask.isContinuous() ) + { + double result; + CALL_HAL_RET(norm, cv_hal_norm, result, src.data, 0, mask.data, 0, (int)src.total(), 1, src.type(), normType); + } + CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_norm(src, normType, mask, _result), _result); - int depth = src.depth(), cn = src.channels(); if( src.isContinuous() && mask.empty() ) { size_t len = src.total()*cn; @@ -1083,18 +1097,27 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra 0) : 0; ippiNormRelFuncNoHint ippiNormRel = normType == NORM_INF ? - (type == CV_8U ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_8u_C1R : + ( + #if !IPP_DISABLE_NORM_8U + type == CV_8U ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_8u_C1R : + #endif type == CV_16U ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_16u_C1R : type == CV_16S ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_16s_C1R : type == CV_32F ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_32f_C1R : 0) : normType == NORM_L1 ? - (type == CV_8U ? (ippiNormRelFuncNoHint)ippiNormRel_L1_8u_C1R : + ( + #if !IPP_DISABLE_NORM_8U + type == CV_8U ? (ippiNormRelFuncNoHint)ippiNormRel_L1_8u_C1R : + #endif type == CV_16U ? (ippiNormRelFuncNoHint)ippiNormRel_L1_16u_C1R : type == CV_16S ? (ippiNormRelFuncNoHint)ippiNormRel_L1_16s_C1R : 0) : normType == NORM_L2 || normType == NORM_L2SQR ? - (type == CV_8U ? (ippiNormRelFuncNoHint)ippiNormRel_L2_8u_C1R : + ( + #if !IPP_DISABLE_NORM_8U + type == CV_8U ? (ippiNormRelFuncNoHint)ippiNormRel_L2_8u_C1R : + #endif type == CV_16U ? (ippiNormRelFuncNoHint)ippiNormRel_L2_16u_C1R : type == CV_16S ? (ippiNormRelFuncNoHint)ippiNormRel_L2_16s_C1R : 0) : 0; @@ -1202,18 +1225,27 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra 0) : 0; ippiNormDiffFuncNoHint ippiNormDiff = normType == NORM_INF ? - (type == CV_8U ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_8u_C1R : + ( + #if !IPP_DISABLE_NORM_8U + type == CV_8U ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_8u_C1R : + #endif type == CV_16U ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_16u_C1R : type == CV_16S ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_16s_C1R : type == CV_32F ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_32f_C1R : 0) : normType == NORM_L1 ? - (type == CV_8U ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_8u_C1R : + ( + #if !IPP_DISABLE_NORM_8U + type == CV_8U ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_8u_C1R : + #endif type == CV_16U ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_16u_C1R : type == CV_16S ? (ippiNormDiffFuncNoHint)ippiNormDiff_L1_16s_C1R : 0) : normType == NORM_L2 || normType == NORM_L2SQR ? - (type == CV_8U ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_8u_C1R : + ( + #if !IPP_DISABLE_NORM_8U + type == CV_8U ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_8u_C1R : + #endif type == CV_16U ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_16u_C1R : type == CV_16S ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_16s_C1R : 0) : 0; @@ -1255,6 +1287,19 @@ double norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask _result) #endif + Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat(); + int depth = src1.depth(), cn = src1.channels(); + if( src1.dims <= 2 ) + { + double result; + CALL_HAL_RET(normDiff, cv_hal_normDiff, result, src1.data, src1.step, src2.data, src2.step, mask.data, mask.step, src1.cols, src1.rows, src1.type(), normType); + } + else if( src1.isContinuous() && src2.isContinuous() && mask.isContinuous() ) + { + double result; + CALL_HAL_RET(normDiff, cv_hal_normDiff, result, src1.data, 0, src2.data, 0, mask.data, 0, (int)src1.total(), 1, src1.type(), normType); + } + CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_norm(_src1, _src2, normType, _mask, _result), _result); if( normType & NORM_RELATIVE ) @@ -1262,9 +1307,6 @@ double norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask return norm(_src1, _src2, normType & ~NORM_RELATIVE, _mask)/(norm(_src2, normType, _mask) + DBL_EPSILON); } - Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat(); - int depth = src1.depth(), cn = src1.channels(); - normType &= 7; CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 || normType == NORM_L2SQR || diff --git a/modules/core/src/opencl/runtime/opencl_core.cpp b/modules/core/src/opencl/runtime/opencl_core.cpp index 35d24eb1cd..37ab5f104c 100644 --- a/modules/core/src/opencl/runtime/opencl_core.cpp +++ b/modules/core/src/opencl/runtime/opencl_core.cpp @@ -152,7 +152,7 @@ static void* WinGetProcAddress(const char* name) #define CV_CL_GET_PROC_ADDRESS(name) WinGetProcAddress(name) #endif // _WIN32 -#if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) #include #include diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index 4f62701e47..e9decf64b4 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -152,7 +152,7 @@ const uint64_t AT_HWCAP = NT_GNU_HWCAP; #endif -#if (defined __ppc64__ || defined __PPC64__) && defined __unix__ +#if ((defined __ppc64__ || defined __PPC64__) && (defined HAVE_GETAUXVAL || defined HAVE_ELF_AUX_INFO)) # include "sys/auxv.h" # ifndef AT_HWCAP2 # define AT_HWCAP2 26 @@ -738,7 +738,7 @@ struct HWFeatures have[CV_CPU_MSA] = true; #endif - #if (defined __ppc64__ || defined __PPC64__) && defined __linux__ + #if (defined __ppc64__ || defined __PPC64__) && defined HAVE_GETAUXVAL unsigned int hwcap = getauxval(AT_HWCAP); if (hwcap & PPC_FEATURE_HAS_VSX) { hwcap = getauxval(AT_HWCAP2); @@ -748,7 +748,7 @@ struct HWFeatures have[CV_CPU_VSX] = (hwcap & PPC_FEATURE2_ARCH_2_07) != 0; } } - #elif (defined __ppc64__ || defined __PPC64__) && defined __FreeBSD__ + #elif (defined __ppc64__ || defined __PPC64__) && defined HAVE_ELF_AUX_INFO unsigned long hwcap = 0; elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); if (hwcap & PPC_FEATURE_HAS_VSX) { @@ -760,7 +760,7 @@ struct HWFeatures } } #else - // TODO: AIX, OpenBSD + // TODO: AIX #if CV_VSX || defined _ARCH_PWR8 || defined __POWER9_VECTOR__ have[CV_CPU_VSX] = true; #endif diff --git a/modules/core/test/test_arithm.cpp b/modules/core/test/test_arithm.cpp index e998db494b..b203e6bb18 100644 --- a/modules/core/test/test_arithm.cpp +++ b/modules/core/test/test_arithm.cpp @@ -3006,6 +3006,19 @@ TEST(Core_MeanStdDev, regression_multichannel) } } +// Related issue : https://github.com/opencv/opencv/issues/26861 +TEST(Core_MeanStdDevTest, LargeImage) +{ + applyTestTag(CV_TEST_TAG_VERYLONG); + applyTestTag(CV_TEST_TAG_MEMORY_14GB); + // (1<<16) * ((1<<15)+10) = ~2.147 billion + cv::Mat largeImage = cv::Mat::ones((1 << 16), ((1 << 15) + 10), CV_8U); + cv::Scalar mean, stddev; + cv::meanStdDev(largeImage, mean, stddev); + EXPECT_NEAR(mean[0], 1.0, 1e-5); + EXPECT_NEAR(stddev[0], 0.0, 1e-5); +} + template static inline void testDivideInitData(Mat& src1, Mat& src2) { diff --git a/modules/core/test/test_math.cpp b/modules/core/test/test_math.cpp index 1fc826c396..5a3e1a5a36 100644 --- a/modules/core/test/test_math.cpp +++ b/modules/core/test/test_math.cpp @@ -505,7 +505,7 @@ double Core_DotProductTest::get_success_error_level( int test_case_idx, int i, i #ifdef __riscv const int depth = test_mat[i][j].depth(); if (depth == CV_64F) - return 1.7e-5; + return 2.5e-5; #endif return Core_MatrixTest::get_success_error_level( test_case_idx, i, j ); } diff --git a/modules/dnn/src/vkcom/src/context.cpp b/modules/dnn/src/vkcom/src/context.cpp index 99aea0f922..d73dcf23bd 100644 --- a/modules/dnn/src/vkcom/src/context.cpp +++ b/modules/dnn/src/vkcom/src/context.cpp @@ -187,13 +187,6 @@ bool checkExtensionAvailability(const char *extension_name, static int init_instance_extension(VkInstance& kInstance) { -#if defined(__ANDROID_API__) && __ANDROID_API__ >= 26 - if (support_VK_KHR_android_surface) - { - vkCreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR)vkGetInstanceProcAddr(kInstance, "vkCreateAndroidSurfaceKHR"); - } -#endif // __ANDROID_API__ >= 26 - return 0; } @@ -648,7 +641,7 @@ GPUInfo Context::parseGPUInfo(VkPhysicalDevice& kPhysicalDevice) info.support_VK_EXT_memory_budget = 0; info.support_VK_EXT_queue_family_foreign = 0; #if defined(__ANDROID_API__) && __ANDROID_API__ >= 26 - gpu_info.support_VK_ANDROID_external_memory_android_hardware_buffer = 0; + info.support_VK_ANDROID_external_memory_android_hardware_buffer = 0; #endif // __ANDROID_API__ >= 26 info.support_VK_NV_cooperative_matrix = 0; for (uint32_t j = 0; j < deviceExtensionPropertyCount; j++) diff --git a/modules/features/src/fast.cpp b/modules/features/src/fast.cpp index dadcb3483c..793999073b 100644 --- a/modules/features/src/fast.cpp +++ b/modules/features/src/fast.cpp @@ -368,8 +368,6 @@ static bool ocl_FAST( InputArray _img, std::vector& keypoints, } #endif - - static inline int hal_FAST(cv::Mat& src, std::vector& keypoints, int threshold, bool nonmax_suppression, FastFeatureDetector::DetectorType type) { if (threshold > 20) @@ -437,7 +435,9 @@ void FAST(InputArray _img, std::vector& keypoints, int threshold, bool cv::Mat img = _img.getMat(); CALL_HAL(fast_dense, hal_FAST, img, keypoints, threshold, nonmax_suppression, type); - size_t keypoints_count; + size_t keypoints_count = 10000; + keypoints.clear(); + keypoints.resize(keypoints_count); CALL_HAL(fast, cv_hal_FAST, img.data, img.step, img.cols, img.rows, (uchar*)(keypoints.data()), &keypoints_count, threshold, nonmax_suppression, type); diff --git a/modules/features/test/test_fast.cpp b/modules/features/test/test_fast.cpp index 2fc5602be5..8f8f587586 100644 --- a/modules/features/test/test_fast.cpp +++ b/modules/features/test/test_fast.cpp @@ -118,8 +118,8 @@ void CV_FastTest::run( int ) read( fs["exp_kps2"], exp_kps2, Mat() ); fs.release(); - if ( exp_kps1.size != kps1.size || 0 != cvtest::norm(exp_kps1, kps1, NORM_L2) || - exp_kps2.size != kps2.size || 0 != cvtest::norm(exp_kps2, kps2, NORM_L2)) + if ( exp_kps1.size != kps1.size || 0 != cvtest::norm(exp_kps1, kps1, NORM_L2) || + exp_kps2.size != kps2.size || 0 != cvtest::norm(exp_kps2, kps2, NORM_L2)) { ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); return; @@ -135,4 +135,34 @@ void CV_FastTest::run( int ) TEST(Features2d_FAST, regression) { CV_FastTest test; test.safe_run(); } +// #define DUMP_TEST_DATA + +TEST(Features2d_FAST, noNMS) +{ + Mat img = imread(string(cvtest::TS::ptr()->get_data_path()) + "inpaint/orig.png", cv::IMREAD_GRAYSCALE); + string xml = string(cvtest::TS::ptr()->get_data_path()) + "fast/result_no_nonmax.xml"; + + vector keypoints; + FAST(img, keypoints, 100, false, FastFeatureDetector::DetectorType::TYPE_9_16); + Mat kps(1, (int)(keypoints.size() * sizeof(KeyPoint)), CV_8U, &keypoints[0]); + + Mat gt_kps; + FileStorage fs(xml, FileStorage::READ); +#ifdef DUMP_TEST_DATA + if (!fs.isOpened()) + { + fs.open(xml, FileStorage::WRITE); + fs << "exp_kps" << kps; + fs.release(); + fs.open(xml, FileStorage::READ); + } +#endif + ASSERT_TRUE(fs.isOpened()); + fs["exp_kps"] >> gt_kps; + fs.release(); + ASSERT_GT(gt_kps.total(), size_t(0)); + + ASSERT_EQ( 0, cvtest::norm(gt_kps, kps, NORM_L2)); +} + }} // namespace diff --git a/modules/highgui/src/window_cocoa.mm b/modules/highgui/src/window_cocoa.mm index 84293dc652..4570b0b64f 100644 --- a/modules/highgui/src/window_cocoa.mm +++ b/modules/highgui/src/window_cocoa.mm @@ -75,7 +75,6 @@ int waitKeyImpl (int maxWait) {return 0;} const int MIN_SLIDER_WIDTH=200; static NSApplication *application = nil; -static NSAutoreleasePool *pool = nil; static NSMutableDictionary *windows = nil; static bool wasInitialized = false; @@ -129,24 +128,10 @@ static bool wasInitialized = false; - (void)createSliderWithName:(const char *)name maxValue:(int)max value:(int *)value callback:(CvTrackbarCallback)callback; @end -/*static void icvCocoaCleanup(void) -{ - //cout << "icvCocoaCleanup" << endl; - if( application ) - { - destroyAllWindowsImpl(); - //[application terminate:nil]; - application = 0; - [pool release]; - } -}*/ - static int cocoa_InitSystem( int , char** ) { - //cout << "cocoa_InitSystem" << endl; wasInitialized = true; - pool = [[NSAutoreleasePool alloc] init]; application = [NSApplication sharedApplication]; windows = [[NSMutableDictionary alloc] init]; @@ -158,152 +143,141 @@ static int cocoa_InitSystem( int , char** ) if( floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5 ) [application setActivationPolicy:NSApplicationActivationPolicyRegular]; #endif - //[application finishLaunching]; - //atexit(icvCocoaCleanup); - setlocale(LC_NUMERIC,"C"); return 0; } static CVWindow *cvGetWindow(const char *name) { - //cout << "cvGetWindow" << endl; - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; - NSString *cvname = [NSString stringWithFormat:@"%s", name]; - CVWindow* retval = (CVWindow*) [windows valueForKey:cvname] ; - //cout << "retain count: " << [retval retainCount] << endl; - //retval = [retval retain]; - //cout << "retain count: " << [retval retainCount] << endl; - [localpool drain]; - //cout << "retain count: " << [retval retainCount] << endl; - return retval; + CVWindow* retval = nil; + @autoreleasepool{ + NSString *cvname = [NSString stringWithFormat:@"%s", name]; + retval = (CVWindow*) [windows valueForKey:cvname]; + if (retval != nil) { + [retval retain]; + } + } + return [retval autorelease]; } void destroyWindowImpl( const char* name) { - - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; - //cout << "destroyWindowImpl" << endl; - CVWindow *window = cvGetWindow(name); - if(window) { - if ([window styleMask] & NSFullScreenWindowMask) { - [window toggleFullScreen:nil]; + @autoreleasepool{ + CVWindow *window = cvGetWindow(name); + if(window) { + if ([window styleMask] & NSFullScreenWindowMask) { + [window toggleFullScreen:nil]; + } + [window close]; + [windows removeObjectForKey:[NSString stringWithFormat:@"%s", name]]; } - [window close]; - [windows removeObjectForKey:[NSString stringWithFormat:@"%s", name]]; } - [localpool drain]; } void destroyAllWindowsImpl( void ) { - //cout << "destroyAllWindowsImpl" << endl; - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; - NSDictionary* list = [NSDictionary dictionaryWithDictionary:windows]; - for(NSString *key in list) { - destroyWindowImpl([key cStringUsingEncoding:NSASCIIStringEncoding]); + @autoreleasepool { + NSDictionary* list = [NSDictionary dictionaryWithDictionary:windows]; + for(NSString *key in list) { + destroyWindowImpl([key cStringUsingEncoding:NSASCIIStringEncoding]); + } } - [localpool drain]; } void showImageImpl( const char* name, cv::InputArray arr) { - //cout << "showImageImpl" << endl; - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; - CVWindow *window = cvGetWindow(name); - if(!window) - { - namedWindowImpl(name, cv::WINDOW_AUTOSIZE); - window = cvGetWindow(name); - } - - if(window) - { - bool empty = [[window contentView] image] == nil; - NSRect vrectOld = [[window contentView] frame]; - NSSize oldImageSize = [[[window contentView] image] size]; - [[window contentView] setImageData:arr]; - if([window autosize] || [window firstContent] || empty) + @autoreleasepool { + CVWindow *window = cvGetWindow(name); + if(!window) { - NSSize imageSize = [[[window contentView] image] size]; - // Only adjust the image size if the new image is a different size from the previous - if (oldImageSize.height != imageSize.height || oldImageSize.width != imageSize.width) + namedWindowImpl(name, cv::WINDOW_AUTOSIZE); + window = cvGetWindow(name); + } + + if(window) + { + bool empty = [[window contentView] image] == nil; + NSRect vrectOld = [[window contentView] frame]; + NSSize oldImageSize = [[[window contentView] image] size]; + [[window contentView] setImageData:arr]; + if([window autosize] || [window firstContent] || empty) { - //Set new view size considering sliders (reserve height and min width) - NSSize scaledImageSize = imageSize; - if ([[window contentView] respondsToSelector:@selector(convertSizeFromBacking:)]) + NSSize imageSize = [[[window contentView] image] size]; + // Only adjust the image size if the new image is a different size from the previous + if (oldImageSize.height != imageSize.height || oldImageSize.width != imageSize.width) { - // Only resize for retina displays if the image is bigger than the screen - NSSize screenSize = NSScreen.mainScreen.visibleFrame.size; - CGFloat titleBarHeight = window.frame.size.height - [window contentRectForFrameRect:window.frame].size.height; - screenSize.height -= titleBarHeight; - if (imageSize.width > screenSize.width || imageSize.height > screenSize.height) + //Set new view size considering sliders (reserve height and min width) + NSSize scaledImageSize = imageSize; + if ([[window contentView] respondsToSelector:@selector(convertSizeFromBacking:)]) { - CGFloat fx = screenSize.width/std::max(imageSize.width, (CGFloat)1.f); - CGFloat fy = screenSize.height/std::max(imageSize.height, (CGFloat)1.f); - CGFloat min_f = std::min(fx, fy); - scaledImageSize = [[window contentView] convertSizeFromBacking:imageSize]; - scaledImageSize.width = std::min(scaledImageSize.width, min_f*imageSize.width); - scaledImageSize.height = std::min(scaledImageSize.height, min_f*imageSize.height); + // Only resize for retina displays if the image is bigger than the screen + NSSize screenSize = NSScreen.mainScreen.visibleFrame.size; + CGFloat titleBarHeight = window.frame.size.height - [window contentRectForFrameRect:window.frame].size.height; + screenSize.height -= titleBarHeight; + if (imageSize.width > screenSize.width || imageSize.height > screenSize.height) + { + CGFloat fx = screenSize.width/std::max(imageSize.width, (CGFloat)1.f); + CGFloat fy = screenSize.height/std::max(imageSize.height, (CGFloat)1.f); + CGFloat min_f = std::min(fx, fy); + scaledImageSize = [[window contentView] convertSizeFromBacking:imageSize]; + scaledImageSize.width = std::min(scaledImageSize.width, min_f*imageSize.width); + scaledImageSize.height = std::min(scaledImageSize.height, min_f*imageSize.height); + } } - } - NSSize contentSize = vrectOld.size; - contentSize.height = scaledImageSize.height + [window contentView].sliderHeight; - contentSize.width = std::max(scaledImageSize.width, MIN_SLIDER_WIDTH); - [window setContentSize:contentSize]; //adjust sliders to fit new window size - if([window firstContent]) - { - int x = [window x0]; - int y = [window y0]; - if(x >= 0 && y >= 0) + NSSize contentSize = vrectOld.size; + contentSize.height = scaledImageSize.height + [window contentView].sliderHeight; + contentSize.width = std::max(scaledImageSize.width, MIN_SLIDER_WIDTH); + [window setContentSize:contentSize]; //adjust sliders to fit new window size + if([window firstContent]) { - y = [[window screen] visibleFrame].size.height - y; - [window setFrameTopLeftPoint:NSMakePoint(x, y)]; + int x = [window x0]; + int y = [window y0]; + if(x >= 0 && y >= 0) + { + y = [[window screen] visibleFrame].size.height - y; + [window setFrameTopLeftPoint:NSMakePoint(x, y)]; + } } } } + [window setFirstContent:NO]; } - [window setFirstContent:NO]; } - [localpool drain]; } void resizeWindowImpl( const char* name, int width, int height) { - - //cout << "resizeWindowImpl" << endl; - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; - CVWindow *window = cvGetWindow(name); - if(window && ![window autosize]) { - height += [window contentView].sliderHeight; - NSSize size = { (CGFloat)width, (CGFloat)height }; - [window setContentSize:size]; + @autoreleasepool { + CVWindow *window = cvGetWindow(name); + if(window && ![window autosize]) { + height += [window contentView].sliderHeight; + NSSize size = { (CGFloat)width, (CGFloat)height }; + [window setContentSize:size]; + } } - [localpool drain]; } void moveWindowImpl( const char* name, int x, int y) { - NSAutoreleasePool* localpool1 = [[NSAutoreleasePool alloc] init]; CVWindow *window = nil; if(name == NULL) CV_Error( cv::Error::StsNullPtr, "NULL window name" ); - //cout << "moveWindowImpl"<< endl; - window = cvGetWindow(name); - if(window) { - if([window firstContent]) { - [window setX0:x]; - [window setY0:y]; - } - else { - y = [[window screen] visibleFrame].size.height - y; - [window setFrameTopLeftPoint:NSMakePoint(x, y)]; + @autoreleasepool { + window = cvGetWindow(name); + if(window) { + if([window firstContent]) { + [window setX0:x]; + [window setY0:y]; + } + else { + y = [[window screen] visibleFrame].size.height - y; + [window setFrameTopLeftPoint:NSMakePoint(x, y)]; + } } } - [localpool1 drain]; } static int cocoa_CreateTrackbar (const char* trackbar_name, @@ -311,28 +285,22 @@ static int cocoa_CreateTrackbar (const char* trackbar_name, int* val, int count, CvTrackbarCallback on_notify) { - - int result = 0; CVWindow *window = nil; - NSAutoreleasePool* localpool2 = nil; - - if (localpool2 != nil) [localpool2 drain]; - localpool2 = [[NSAutoreleasePool alloc] init]; if(window_name == NULL) CV_Error( cv::Error::StsNullPtr, "NULL window name" ); - //cout << "cocoa_CreateTrackbar" << endl ; - window = cvGetWindow(window_name); - if(window) { - [window createSliderWithName:trackbar_name - maxValue:count - value:val - callback:on_notify]; - result = 1; + @autoreleasepool { + window = cvGetWindow(window_name); + if(window) { + [window createSliderWithName:trackbar_name + maxValue:count + value:val + callback:on_notify]; + result = 1; + } } - [localpool2 drain]; return result; } @@ -343,18 +311,17 @@ int createTrackbar2Impl(const char* trackbar_name, CvTrackbarCallback2 on_notify2, void* userdata) { - //cout <<"createTrackbar2Impl" << endl; - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; int res = cocoa_CreateTrackbar(trackbar_name, window_name, val, count, NULL); - if(res) { - CVWindow *window = cvGetWindow(window_name); - if (window && [window respondsToSelector:@selector(sliders)]) { - CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; - [slider setCallback2:on_notify2]; - [slider setUserData:userdata]; + @autoreleasepool { + if(res) { + CVWindow *window = cvGetWindow(window_name); + if (window && [window respondsToSelector:@selector(sliders)]) { + CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; + [slider setCallback2:on_notify2]; + [slider setUserData:userdata]; + } } } - [localpool drain]; return res; } @@ -362,43 +329,34 @@ int createTrackbar2Impl(const char* trackbar_name, void setMouseCallbackImpl( const char* name, CvMouseCallback function, void* info) { CVWindow *window = nil; - NSAutoreleasePool* localpool3 = nil; - //cout << "setMouseCallbackImpl" << endl; - - if (localpool3 != nil) [localpool3 drain]; - localpool3 = [[NSAutoreleasePool alloc] init]; if(name == NULL) CV_Error( cv::Error::StsNullPtr, "NULL window name" ); - - window = cvGetWindow(name); - if(window) { - [window setMouseCallback:function]; - [window setMouseParam:info]; + @autoreleasepool { + window = cvGetWindow(name); + if(window) { + [window setMouseCallback:function]; + [window setMouseParam:info]; + } } - [localpool3 drain]; } int getTrackbarPosImpl( const char* trackbar_name, const char* window_name ) { CVWindow *window = nil; int pos = -1; - NSAutoreleasePool* localpool4 = nil; - //cout << "getTrackbarPosImpl" << endl; if(trackbar_name == NULL || window_name == NULL) CV_Error( cv::Error::StsNullPtr, "NULL trackbar or window name" ); - if (localpool4 != nil) [localpool4 drain]; - localpool4 = [[NSAutoreleasePool alloc] init]; - - window = cvGetWindow(window_name); - if(window && [window respondsToSelector:@selector(sliders)]) { - CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; - if(slider) { - pos = [[slider slider] intValue]; + @autoreleasepool { + window = cvGetWindow(window_name); + if(window && [window respondsToSelector:@selector(sliders)]) { + CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; + if(slider) { + pos = [[slider slider] intValue]; + } } } - [localpool4 drain]; return pos; } @@ -406,82 +364,71 @@ void setTrackbarPosImpl(const char* trackbar_name, const char* window_name, int { CVWindow *window = nil; CVSlider *slider = nil; - NSAutoreleasePool* localpool5 = nil; - //cout << "setTrackbarPosImpl" << endl; if(trackbar_name == NULL || window_name == NULL) CV_Error( cv::Error::StsNullPtr, "NULL trackbar or window name" ); if(pos < 0) CV_Error( cv::Error::StsOutOfRange, "Bad trackbar maximal value" ); - if (localpool5 != nil) [localpool5 drain]; - localpool5 = [[NSAutoreleasePool alloc] init]; - - window = cvGetWindow(window_name); - if(window && [window respondsToSelector:@selector(sliders)]) { - slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; - if(slider) { - [[slider slider] setIntValue:pos]; - if([slider respondsToSelector:@selector(handleSlider)]) { - [slider performSelector:@selector(handleSlider)]; + @autoreleasepool { + window = cvGetWindow(window_name); + if(window && [window respondsToSelector:@selector(sliders)]) { + slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; + if(slider) { + [[slider slider] setIntValue:pos]; + if([slider respondsToSelector:@selector(handleSlider)]) { + [slider performSelector:@selector(handleSlider)]; + } } } } - [localpool5 drain]; } void setTrackbarMaxImpl(const char* trackbar_name, const char* window_name, int maxval) { CVWindow *window = nil; CVSlider *slider = nil; - NSAutoreleasePool* localpool5 = nil; - //cout << "setTrackbarPosImpl" << endl; if(trackbar_name == NULL || window_name == NULL) CV_Error( cv::Error::StsNullPtr, "NULL trackbar or window name" ); - if (localpool5 != nil) [localpool5 drain]; - localpool5 = [[NSAutoreleasePool alloc] init]; - - window = cvGetWindow(window_name); - if(window && [window respondsToSelector:@selector(sliders)]) { - slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; - if(slider) { - if(maxval >= 0) { - int minval = [[slider slider] minValue]; - maxval = (minval>maxval)?minval:maxval; - [[slider slider] setMaxValue:maxval]; + @autoreleasepool { + window = cvGetWindow(window_name); + if(window && [window respondsToSelector:@selector(sliders)]) { + slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; + if(slider) { + if(maxval >= 0) { + int minval = [[slider slider] minValue]; + maxval = (minval>maxval)?minval:maxval; + [[slider slider] setMaxValue:maxval]; + } } } } - [localpool5 drain]; } void setTrackbarMinImpl(const char* trackbar_name, const char* window_name, int minval) { CVWindow *window = nil; CVSlider *slider = nil; - NSAutoreleasePool* localpool5 = nil; if(trackbar_name == NULL || window_name == NULL) CV_Error( cv::Error::StsNullPtr, "NULL trackbar or window name" ); - if (localpool5 != nil) [localpool5 drain]; - localpool5 = [[NSAutoreleasePool alloc] init]; - - window = cvGetWindow(window_name); - if(window && [window respondsToSelector:@selector(sliders)]) { - slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; - if(slider) { - if(minval >= 0) { - int maxval = [[slider slider] maxValue]; - minval = (minval= 0) { + int maxval = [[slider slider] maxValue]; + minval = (minval= maxWait && maxWait>0) - break; + while(true) { + if(([[NSDate date] timeIntervalSince1970] - start) * 1000 >= maxWait && maxWait>0) + break; - //event = [application currentEvent]; - [localpool drain]; - localpool = [[NSAutoreleasePool alloc] init]; + NSEvent *event = + [application + nextEventMatchingMask:NSAnyEventMask + untilDate://[NSDate dateWithTimeIntervalSinceNow: 1./100] + [NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; - NSEvent *event = - [application - nextEventMatchingMask:NSAnyEventMask - untilDate://[NSDate dateWithTimeIntervalSinceNow: 1./100] - [NSDate distantPast] - inMode:NSDefaultRunLoopMode - dequeue:YES]; + if([event type] == NSKeyDown && [[event characters] length]) { + returnCode = [[event characters] characterAtIndex:0]; + break; + } - if([event type] == NSKeyDown && [[event characters] length]) { - returnCode = [[event characters] characterAtIndex:0]; - break; + [application sendEvent:event]; + [application updateWindows]; + + [NSThread sleepForTimeInterval:1/100.]; } - [application sendEvent:event]; - [application updateWindows]; - - [NSThread sleepForTimeInterval:1/100.]; + return returnCode; } - [localpool drain]; - - return returnCode; } cv::Rect cvGetWindowRect_COCOA( const char* name ) @@ -637,8 +575,6 @@ void cvSetModeWindow_COCOA( const char* name, double prop_value ) NSDictionary *fullscreenOptions = nil; #endif - NSAutoreleasePool* localpool = nil; - if( name == NULL ) { CV_Error( cv::Error::StsNullPtr, "NULL name string" ); @@ -655,46 +591,45 @@ void cvSetModeWindow_COCOA( const char* name, double prop_value ) return; } - localpool = [[NSAutoreleasePool alloc] init]; - + @autoreleasepool { #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_6 - if ( ([window styleMask] & NSFullScreenWindowMask) && prop_value==cv::WINDOW_NORMAL ) - { - [window toggleFullScreen:nil]; + if ( ([window styleMask] & NSFullScreenWindowMask) && prop_value==cv::WINDOW_NORMAL ) + { + [window toggleFullScreen:nil]; - window.status=cv::WINDOW_NORMAL; - } - else if( !([window styleMask] & NSFullScreenWindowMask) && prop_value==cv::WINDOW_FULLSCREEN ) - { - [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + window.status=cv::WINDOW_NORMAL; + } + else if( !([window styleMask] & NSFullScreenWindowMask) && prop_value==cv::WINDOW_FULLSCREEN ) + { + [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; - NSScreen* screen = [window screen]; + NSScreen* screen = [window screen]; - NSRect frame = [screen frame]; - [window setFrame:frame display:YES]; + NSRect frame = [screen frame]; + [window setFrame:frame display:YES]; - [window setContentSize:frame.size]; + [window setContentSize:frame.size]; - [window toggleFullScreen:nil]; + [window toggleFullScreen:nil]; - [window setFrameTopLeftPoint: frame.origin]; + [window setFrameTopLeftPoint: frame.origin]; - window.status=cv::WINDOW_FULLSCREEN; - } + window.status=cv::WINDOW_FULLSCREEN; + } #else - fullscreenOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:NSFullScreenModeSetting]; - if ( [[window contentView] isInFullScreenMode] && prop_value==cv::WINDOW_NORMAL ) - { - [[window contentView] exitFullScreenModeWithOptions:fullscreenOptions]; - window.status=cv::WINDOW_NORMAL; - } - else if( ![[window contentView] isInFullScreenMode] && prop_value==cv::WINDOW_FULLSCREEN ) - { - [[window contentView] enterFullScreenMode:[NSScreen mainScreen] withOptions:fullscreenOptions]; - window.status=cv::WINDOW_FULLSCREEN; - } + fullscreenOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:NSFullScreenModeSetting]; + if ( [[window contentView] isInFullScreenMode] && prop_value==cv::WINDOW_NORMAL ) + { + [[window contentView] exitFullScreenModeWithOptions:fullscreenOptions]; + window.status=cv::WINDOW_NORMAL; + } + else if( ![[window contentView] isInFullScreenMode] && prop_value==cv::WINDOW_FULLSCREEN ) + { + [[window contentView] enterFullScreenMode:[NSScreen mainScreen] withOptions:fullscreenOptions]; + window.status=cv::WINDOW_FULLSCREEN; + } #endif - [localpool drain]; + } } double cvGetPropVisible_COCOA(const char* name) @@ -741,56 +676,53 @@ double cvGetPropTopmost_COCOA(const char* name) void cvSetPropTopmost_COCOA( const char* name, const bool topmost ) { CVWindow *window = nil; - NSAutoreleasePool* localpool = nil; if( name == NULL ) { CV_Error( cv::Error::StsNullPtr, "NULL name string" ); } - window = cvGetWindow(name); - if ( window == NULL ) - { - CV_Error( cv::Error::StsNullPtr, "NULL window" ); - } + @autoreleasepool { + window = cvGetWindow(name); + if ( window == NULL ) + { + CV_Error( cv::Error::StsNullPtr, "NULL window" ); + } - if (([window styleMask] & NSFullScreenWindowMask)) - { - return; - } + if (([window styleMask] & NSFullScreenWindowMask)) + { + return; + } - localpool = [[NSAutoreleasePool alloc] init]; - if (topmost) - { - [window makeKeyAndOrderFront:window.self]; - [window setLevel:CGWindowLevelForKey(kCGMaximumWindowLevelKey)]; + if (topmost) + { + [window makeKeyAndOrderFront:window.self]; + [window setLevel:CGWindowLevelForKey(kCGMaximumWindowLevelKey)]; + } + else + { + [window makeKeyAndOrderFront:nil]; + } } - else - { - [window makeKeyAndOrderFront:nil]; - } - [localpool drain]; } void setWindowTitle_COCOA(const cv::String& winname, const cv::String& title) { - CVWindow *window = cvGetWindow(winname.c_str()); + @autoreleasepool { + CVWindow *window = cvGetWindow(winname.c_str()); - if (window == NULL) - { - cv::namedWindow(winname); - window = cvGetWindow(winname.c_str()); + if (window == NULL) + { + cv::namedWindow(winname); + window = cvGetWindow(winname.c_str()); + } + + if (window == NULL) + CV_Error(cv::Error::StsNullPtr, "NULL window"); + + NSString *windowTitle = [NSString stringWithFormat:@"%s", title.c_str()]; + [window setTitle:windowTitle]; } - - if (window == NULL) - CV_Error(cv::Error::StsNullPtr, "NULL window"); - - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; - - NSString *windowTitle = [NSString stringWithFormat:@"%s", title.c_str()]; - [window setTitle:windowTitle]; - - [localpool drain]; } static NSSize constrainAspectRatio(NSSize base, NSSize constraint) { @@ -824,9 +756,7 @@ static NSSize constrainAspectRatio(NSSize base, NSSize constraint) { - (void)cvSendMouseEvent:(NSEvent *)event type:(int)type flags:(int)flags { (void)event; - //cout << "cvSendMouseEvent" << endl; NSPoint mp = [NSEvent mouseLocation]; - //NSRect visible = [[self contentView] frame]; mp = [self convertScreenToBase: mp]; CVView *contentView = [self contentView]; NSSize viewSize = contentView.frame.size; @@ -857,11 +787,9 @@ static NSSize constrainAspectRatio(NSSize base, NSSize constraint) { } else if( mp.x >= 0 && mp.y >= 0 && mp.x < imageSize.width && mp.y < imageSize.height ) { mouseCallback(type, mp.x, mp.y, flags, mouseParam); } - } - (void)cvMouseEvent:(NSEvent *)event { - //cout << "cvMouseEvent" << endl; if(!mouseCallback) return; @@ -870,8 +798,19 @@ static NSSize constrainAspectRatio(NSSize base, NSSize constraint) { if([event modifierFlags] & NSControlKeyMask) flags |= cv::EVENT_FLAG_CTRLKEY; if([event modifierFlags] & NSAlternateKeyMask) flags |= cv::EVENT_FLAG_ALTKEY; - if([event type] == NSLeftMouseDown) {[self cvSendMouseEvent:event type:cv::EVENT_LBUTTONDOWN flags:flags | cv::EVENT_FLAG_LBUTTON];} - if([event type] == NSLeftMouseUp) {[self cvSendMouseEvent:event type:cv::EVENT_LBUTTONUP flags:flags | cv::EVENT_FLAG_LBUTTON];} + //modified code using ternary operator: + if ([event type] == NSLeftMouseDown) { + [self cvSendMouseEvent:event + type:([event modifierFlags] & NSControlKeyMask) ? cv::EVENT_RBUTTONDOWN : cv::EVENT_LBUTTONDOWN + flags:flags | (([event modifierFlags] & NSControlKeyMask) ? cv::EVENT_FLAG_RBUTTON : cv::EVENT_FLAG_LBUTTON)]; + } + + if ([event type] == NSLeftMouseUp) { + [self cvSendMouseEvent:event + type:([event modifierFlags] & NSControlKeyMask) ? cv::EVENT_RBUTTONUP : cv::EVENT_LBUTTONUP + flags:flags | (([event modifierFlags] & NSControlKeyMask) ? cv::EVENT_FLAG_RBUTTON : cv::EVENT_FLAG_LBUTTON)]; + } + if([event type] == NSRightMouseDown){[self cvSendMouseEvent:event type:cv::EVENT_RBUTTONDOWN flags:flags | cv::EVENT_FLAG_RBUTTON];} if([event type] == NSRightMouseUp) {[self cvSendMouseEvent:event type:cv::EVENT_RBUTTONUP flags:flags | cv::EVENT_FLAG_RBUTTON];} if([event type] == NSOtherMouseDown){[self cvSendMouseEvent:event type:cv::EVENT_MBUTTONDOWN flags:flags];} @@ -887,20 +826,15 @@ static NSSize constrainAspectRatio(NSSize base, NSSize constraint) { [self cvMouseEvent:theEvent]; } - (void)keyDown:(NSEvent *)theEvent { - //cout << "keyDown" << endl; [super keyDown:theEvent]; } - (void)rightMouseDragged:(NSEvent *)theEvent { - //cout << "rightMouseDragged" << endl ; [self cvMouseEvent:theEvent]; } - (void)rightMouseUp:(NSEvent *)theEvent { - //cout << "rightMouseUp" << endl; [self cvMouseEvent:theEvent]; } - (void)rightMouseDown:(NSEvent *)theEvent { - // Does not seem to work? - //cout << "rightMouseDown" << endl; [self cvMouseEvent:theEvent]; } - (void)mouseMoved:(NSEvent *)theEvent { @@ -926,7 +860,6 @@ static NSSize constrainAspectRatio(NSSize base, NSSize constraint) { } - (void)createSliderWithName:(const char *)name maxValue:(int)max value:(int *)value callback:(CvTrackbarCallback)callback { - //cout << "createSliderWithName" << endl; if(sliders == nil) sliders = [[NSMutableDictionary alloc] init]; @@ -961,7 +894,6 @@ static NSSize constrainAspectRatio(NSSize base, NSSize constraint) { [slidersKeys addObject:cvname]; [[self contentView] addSubview:slider]; - //update contentView size to contain sliders NSSize viewSize=[[self contentView] frame].size, sliderSize=[slider frame].size; @@ -990,36 +922,33 @@ static NSSize constrainAspectRatio(NSSize base, NSSize constraint) { @synthesize image; - (id)init { - //cout << "CVView init" << endl; [super init]; return self; } - (void)setImageData:(cv::InputArray)arr { - //cout << "setImageData" << endl; - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; + @autoreleasepool { + cv::Mat arrMat = arr.getMat(); - cv::Mat arrMat = arr.getMat(); - /*CGColorSpaceRef colorspace = NULL; - CGDataProviderRef provider = NULL; - int width = cvimage->width; - int height = cvimage->height; + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL + pixelsWide:arrMat.cols + pixelsHigh:arrMat.rows + bitsPerSample:8 + samplesPerPixel:3 + hasAlpha:NO + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bitmapFormat: kCGImageAlphaNone + bytesPerRow:((arrMat.cols * 3 + 3) & -4) + bitsPerPixel:24]; - colorspace = CGColorSpaceCreateDeviceRGB(); - - int size = 8; - int nbChannels = 3; - - provider = CGDataProviderCreateWithData(NULL, cvimage->data.ptr, width * height , NULL ); - - CGImageRef imageRef = CGImageCreate(width, height, size , size*nbChannels , cvimage->step, colorspace, kCGImageAlphaNone , provider, NULL, true, kCGRenderingIntentDefault); - - NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCGImage:imageRef]; - if(image) { - [image release]; - }*/ - - NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL + if (bitmap) { + cv::Mat dst(arrMat.rows, arrMat.cols, CV_8UC3, [bitmap bitmapData], [bitmap bytesPerRow]); + convertToShow(arrMat, dst); + } + else { + // It's not guaranteed to like the bitsPerPixel:24, but this is a lot slower so we'd rather not do it + bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:arrMat.cols pixelsHigh:arrMat.rows bitsPerSample:8 @@ -1027,119 +956,93 @@ static NSSize constrainAspectRatio(NSSize base, NSSize constraint) { hasAlpha:NO isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace - bitmapFormat: kCGImageAlphaNone - bytesPerRow:((arrMat.cols * 3 + 3) & -4) - bitsPerPixel:24]; - - if (bitmap) { - cv::Mat dst(arrMat.rows, arrMat.cols, CV_8UC3, [bitmap bitmapData], [bitmap bytesPerRow]); - convertToShow(arrMat, dst); - } - else { - // It's not guaranteed to like the bitsPerPixel:24, but this is a lot slower so we'd rather not do it - bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:arrMat.cols - pixelsHigh:arrMat.rows - bitsPerSample:8 - samplesPerPixel:3 - hasAlpha:NO - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:(arrMat.cols * 4) - bitsPerPixel:32]; - cv::Mat dst(arrMat.rows, arrMat.cols, CV_8UC4, [bitmap bitmapData], [bitmap bytesPerRow]); - convertToShow(arrMat, dst); - } - - if( image ) { - [image release]; - } - - image = [[NSImage alloc] init]; - [image addRepresentation:bitmap]; - [bitmap release]; - - // This isn't supported on older versions of macOS - // The performance issues this solves are mainly on newer versions of macOS, so that's fine - if( floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5 ) { - if (![self imageView]) { - [self setImageView:[[NSView alloc] init]]; - [[self imageView] setWantsLayer:true]; - [self addSubview:[self imageView]]; + bytesPerRow:(arrMat.cols * 4) + bitsPerPixel:32]; + cv::Mat dst(arrMat.rows, arrMat.cols, CV_8UC4, [bitmap bitmapData], [bitmap bytesPerRow]); + convertToShow(arrMat, dst); } - [[[self imageView] layer] setContents:image]; + if( image ) { + [image release]; + } - NSRect imageViewFrame = [self frame]; - imageViewFrame.size.height -= [self sliderHeight]; - NSRect constrainedFrame = { imageViewFrame.origin, constrainAspectRatio(imageViewFrame.size, [image size]) }; - [[self imageView] setFrame:constrainedFrame]; + image = [[NSImage alloc] init]; + [image addRepresentation:bitmap]; + [bitmap release]; + + // This isn't supported on older versions of macOS + // The performance issues this solves are mainly on newer versions of macOS, so that's fine + if( floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5 ) { + if (![self imageView]) { + [self setImageView:[[NSView alloc] init]]; + [[self imageView] setWantsLayer:true]; + [self addSubview:[self imageView]]; + } + + [[[self imageView] layer] setContents:image]; + + NSRect imageViewFrame = [self frame]; + imageViewFrame.size.height -= [self sliderHeight]; + NSRect constrainedFrame = { imageViewFrame.origin, constrainAspectRatio(imageViewFrame.size, [image size]) }; + [[self imageView] setFrame:constrainedFrame]; + } + else { + NSRect redisplayRect = [self frame]; + redisplayRect.size.height -= [self sliderHeight]; + [self setNeedsDisplayInRect:redisplayRect]; + } } - else { - NSRect redisplayRect = [self frame]; - redisplayRect.size.height -= [self sliderHeight]; - [self setNeedsDisplayInRect:redisplayRect]; - } - - /*CGColorSpaceRelease(colorspace); - CGDataProviderRelease(provider); - CGImageRelease(imageRef);*/ - - [localpool drain]; } - (void)setFrameSize:(NSSize)size { - //cout << "setFrameSize" << endl; [super setFrameSize:size]; - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; int height = size.height; - CVWindow *cvwindow = (CVWindow *)[self window]; - if ([cvwindow respondsToSelector:@selector(sliders)]) { - for(NSString *key in [cvwindow slidersKeys]) { - CVSlider *slider = [[cvwindow sliders] valueForKey:key]; - NSRect r = [slider frame]; - r.origin.y = height - r.size.height; - r.size.width = [[cvwindow contentView] frame].size.width; + @autoreleasepool { + CVWindow *cvwindow = (CVWindow *)[self window]; + if ([cvwindow respondsToSelector:@selector(sliders)]) { + for(NSString *key in [cvwindow slidersKeys]) { + CVSlider *slider = [[cvwindow sliders] valueForKey:key]; + NSRect r = [slider frame]; + r.origin.y = height - r.size.height; + r.size.width = [[cvwindow contentView] frame].size.width; - CGRect sliderRect = slider.slider.frame; - CGFloat targetWidth = r.size.width - (sliderRect.origin.x + 10); - sliderRect.size.width = targetWidth < 0 ? 0 : targetWidth; - slider.slider.frame = sliderRect; + CGRect sliderRect = slider.slider.frame; + CGFloat targetWidth = r.size.width - (sliderRect.origin.x + 10); + sliderRect.size.width = targetWidth < 0 ? 0 : targetWidth; + slider.slider.frame = sliderRect; - [slider setFrame:r]; - height -= r.size.height; + [slider setFrame:r]; + height -= r.size.height; + } + } + NSRect frame = self.frame; + if (frame.size.height < self.sliderHeight) { + frame.size.height = self.sliderHeight; + self.frame = frame; + } + if ([self imageView]) { + NSRect imageViewFrame = frame; + imageViewFrame.size.height -= [self sliderHeight]; + NSRect constrainedFrame = { imageViewFrame.origin, constrainAspectRatio(imageViewFrame.size, [image size]) }; + [[self imageView] setFrame:constrainedFrame]; } } - NSRect frame = self.frame; - if (frame.size.height < self.sliderHeight) { - frame.size.height = self.sliderHeight; - self.frame = frame; - } - if ([self imageView]) { - NSRect imageViewFrame = frame; - imageViewFrame.size.height -= [self sliderHeight]; - NSRect constrainedFrame = { imageViewFrame.origin, constrainAspectRatio(imageViewFrame.size, [image size]) }; - [[self imageView] setFrame:constrainedFrame]; - } - [localpool drain]; } - (void)drawRect:(NSRect)rect { - //cout << "drawRect" << endl; [super drawRect:rect]; // If imageView exists, all drawing will be done by it and nothing needs to happen here if ([self image] && ![self imageView]) { - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; - - if(image != nil) { - [image drawInRect: [self frame] - fromRect: NSZeroRect - operation: NSCompositeSourceOver - fraction: 1.0]; + @autoreleasepool { + if(image != nil) { + [image drawInRect: [self frame] + fromRect: NSZeroRect + operation: NSCompositeSourceOver + fraction: 1.0]; + } } - [localpool release]; } } @@ -1184,8 +1087,6 @@ static NSSize constrainAspectRatio(NSSize base, NSSize constraint) { [self setAutoresizingMask:NSViewWidthSizable]; - //[self setFrame:NSMakeRect(12, 0, 100, 30)]; - return self; } diff --git a/modules/highgui/src/window_w32.cpp b/modules/highgui/src/window_w32.cpp index 7132275e45..42df4d4aee 100644 --- a/modules/highgui/src/window_w32.cpp +++ b/modules/highgui/src/window_w32.cpp @@ -2123,9 +2123,15 @@ static void showSaveDialog(CvWindow& window) #ifdef HAVE_WEBP "WebP files (*.webp)\0*.webp\0" #endif - "Portable image format (*.pbm;*.pgm;*.ppm;*.pxm;*.pnm)\0*.pbm;*.pgm;*.ppm;*.pxm;*.pnm\0" + "Portable image format (*.pbm;*.pgm;*.ppm;*.pnm;*.pam)\0*.pbm;*.pgm;*.ppm;*.pnm;*.pam\0" #ifdef HAVE_OPENEXR "OpenEXR Image files (*.exr)\0*.exr\0" +#endif +#ifdef HAVE_AVIF + "AVIF files (*.avif)\0*.avif\0" +#endif +#ifdef HAVE_IMGCODEC_GIF + "Graphics Interchange Format 89a(*.gif)\0*.gif\0" #endif "Radiance HDR (*.hdr;*.pic)\0*.hdr;*.pic\0" "Sun raster files (*.sr;*.ras)\0*.sr;*.ras\0" @@ -2147,7 +2153,7 @@ static void showSaveDialog(CvWindow& window) } #else CV_UNUSED(window); - CV_LOG_WARNING("Save dialog requires enabled 'imgcodecs' module."); + CV_LOG_WARNING(NULL, "Save dialog requires enabled 'imgcodecs' module."); return; #endif } diff --git a/modules/imgcodecs/include/opencv2/imgcodecs.hpp b/modules/imgcodecs/include/opencv2/imgcodecs.hpp index 54a5dcfe08..ed8dfd1e2d 100644 --- a/modules/imgcodecs/include/opencv2/imgcodecs.hpp +++ b/modules/imgcodecs/include/opencv2/imgcodecs.hpp @@ -65,6 +65,7 @@ namespace cv //! @{ //! Imread flags +//! @note IMREAD_COLOR_BGR (IMREAD_COLOR) and IMREAD_COLOR_RGB can not be set at the same time. enum ImreadModes { IMREAD_UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped). Ignore EXIF orientation. IMREAD_GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image (codec internal conversion). @@ -263,11 +264,11 @@ struct CV_EXPORTS_W_SIMPLE Animation - If a negative value or a value beyond the maximum of `0xffff` (65535) is provided, it is reset to `0` (infinite looping) to maintain valid bounds. - @param bgColor A `Scalar` object representing the background color in BGRA format: + @param bgColor A `Scalar` object representing the background color in BGR format: - Defaults to `Scalar()`, indicating an empty color (usually transparent if supported). - This background color provides a solid fill behind frames that have transparency, ensuring a consistent display appearance. */ - Animation(int loopCount = 0, Scalar bgColor = Scalar()); + CV_WRAP Animation(int loopCount = 0, Scalar bgColor = Scalar()); }; /** @brief Loads an image from a file. @@ -413,13 +414,13 @@ can be saved using this function, with these exceptions: - With JPEG 2000 encoder, 8-bit unsigned (CV_8U) and 16-bit unsigned (CV_16U) images can be saved. - With JPEG XL encoder, 8-bit unsigned (CV_8U), 16-bit unsigned (CV_16U) and 32-bit float(CV_32F) images can be saved. - JPEG XL images with an alpha channel can be saved using this function. - To do this, create 8-bit (or 16-bit, 32-bit float) 4-channel image BGRA, where the alpha channel goes last. - Fully transparent pixels should have alpha set to 0, fully opaque pixels should have alpha set to 255/65535/1.0. + To achieve this, create an 8-bit 4-channel (CV_8UC4) / 16-bit 4-channel (CV_16UC4) / 32-bit float 4-channel (CV_32FC4) BGRA image, ensuring the alpha channel is the last component. + Fully transparent pixels should have an alpha value of 0, while fully opaque pixels should have an alpha value of 255/65535/1.0. - With PAM encoder, 8-bit unsigned (CV_8U) and 16-bit unsigned (CV_16U) images can be saved. - With PNG encoder, 8-bit unsigned (CV_8U) and 16-bit unsigned (CV_16U) images can be saved. - - PNG images with an alpha channel can be saved using this function. To do this, create - 8-bit (or 16-bit) 4-channel image BGRA, where the alpha channel goes last. Fully transparent pixels - should have alpha set to 0, fully opaque pixels should have alpha set to 255/65535 (see the code sample below). + - PNG images with an alpha channel can be saved using this function. + To achieve this, create an 8-bit 4-channel (CV_8UC4) / 16-bit 4-channel (CV_16UC4) BGRA image, ensuring the alpha channel is the last component. + Fully transparent pixels should have an alpha value of 0, while fully opaque pixels should have an alpha value of 255/65535(see the code sample below). - With PGM/PPM encoder, 8-bit unsigned (CV_8U) and 16-bit unsigned (CV_16U) images can be saved. - With TIFF encoder, 8-bit unsigned (CV_8U), 8-bit signed (CV_8S), 16-bit unsigned (CV_16U), 16-bit signed (CV_16S), @@ -429,6 +430,11 @@ can be saved using this function, with these exceptions: - Multiple images (vector of Mat) can be saved in TIFF format (see the code sample below). - 32-bit float 3-channel (CV_32FC3) TIFF images will be saved using the LogLuv high dynamic range encoding (4 bytes per pixel) +- With GIF encoder, 8-bit unsigned (CV_8U) images can be saved. + - GIF images with an alpha channel can be saved using this function. + To achieve this, create an 8-bit 4-channel (CV_8UC4) BGRA image, ensuring the alpha channel is the last component. + Fully transparent pixels should have an alpha value of 0, while fully opaque pixels should have an alpha value of 255. + - 8-bit single-channel images (CV_8UC1) are not supported due to GIF's limitation to indexed color formats. If the image format is not supported, the image will be converted to 8-bit unsigned (CV_8U) and saved that way. diff --git a/modules/imgcodecs/misc/java/test/ImgcodecsTest.java b/modules/imgcodecs/misc/java/test/ImgcodecsTest.java index ba22aac06e..1f5de6a2ef 100644 --- a/modules/imgcodecs/misc/java/test/ImgcodecsTest.java +++ b/modules/imgcodecs/misc/java/test/ImgcodecsTest.java @@ -1,13 +1,46 @@ package org.opencv.test.imgcodecs; +import org.opencv.core.Mat; import org.opencv.core.MatOfByte; import org.opencv.core.MatOfInt; +import org.opencv.imgproc.Imgproc; import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgcodecs.Animation; import org.opencv.test.OpenCVTestCase; import org.opencv.test.OpenCVTestRunner; +import java.util.ArrayList; +import java.util.List; + public class ImgcodecsTest extends OpenCVTestCase { + public void testAnimation() { + Mat src = Imgcodecs.imread(OpenCVTestRunner.LENA_PATH, Imgcodecs.IMREAD_REDUCED_COLOR_4); + assertFalse(src.empty()); + + Mat rgb = new Mat(); + Imgproc.cvtColor(src, rgb, Imgproc.COLOR_BGR2RGB); + + Animation animation = new Animation(); + List frames = new ArrayList<>(); + MatOfInt durations = new MatOfInt(100, 100); + + frames.add(src); + frames.add(rgb); + + animation.set_frames(frames); + animation.set_durations(durations); + + String filename = OpenCVTestRunner.getTempFileName("png"); + assertTrue(Imgcodecs.imwriteanimation(filename, animation)); + + Animation readAnimation = new Animation(); + assertTrue(Imgcodecs.imreadanimation(filename, readAnimation)); + + List readFrames = readAnimation.get_frames(); + assertTrue(readFrames.size() == 2); + } + public void testImdecode() { fail("Not yet implemented"); } diff --git a/modules/imgcodecs/perf/perf_decode_encode.cpp b/modules/imgcodecs/perf/perf_decode_encode.cpp new file mode 100644 index 0000000000..ce693cb878 --- /dev/null +++ b/modules/imgcodecs/perf/perf_decode_encode.cpp @@ -0,0 +1,131 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#include "perf_precomp.hpp" + +namespace opencv_test +{ + +#ifdef HAVE_PNG + +using namespace perf; + +typedef perf::TestBaseWithParam Decode; +typedef perf::TestBaseWithParam Encode; + +const string exts[] = { +#ifdef HAVE_AVIF + ".avif", +#endif + ".bmp", +#ifdef HAVE_IMGCODEC_GIF + ".gif", +#endif +#if (defined(HAVE_JASPER) && defined(OPENCV_IMGCODECS_ENABLE_JASPER_TESTS)) \ + || defined(HAVE_OPENJPEG) + ".jp2", +#endif +#ifdef HAVE_JPEG + ".jpg", +#endif +#ifdef HAVE_JPEGXL + ".jxl", +#endif + ".png", +#ifdef HAVE_IMGCODEC_PXM + ".ppm", +#endif +#ifdef HAVE_IMGCODEC_SUNRASTER + ".ras", +#endif +#ifdef HAVE_TIFF + ".tiff", +#endif +#ifdef HAVE_WEBP + ".webp", +#endif +}; + +const string exts_multi[] = { +#ifdef HAVE_AVIF + ".avif", +#endif +#ifdef HAVE_IMGCODEC_GIF + ".gif", +#endif + ".png", +#ifdef HAVE_TIFF + ".tiff", +#endif +#ifdef HAVE_WEBP + ".webp", +#endif +}; + +PERF_TEST_P(Decode, bgr, testing::ValuesIn(exts)) +{ + String filename = getDataPath("perf/1920x1080.png"); + + Mat src = imread(filename); + EXPECT_FALSE(src.empty()) << "Cannot open test image perf/1920x1080.png"; + vector buf; + EXPECT_TRUE(imencode(GetParam(), src, buf)); + + TEST_CYCLE() imdecode(buf, IMREAD_UNCHANGED); + + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(Decode, rgb, testing::ValuesIn(exts)) +{ + String filename = getDataPath("perf/1920x1080.png"); + + Mat src = imread(filename); + EXPECT_FALSE(src.empty()) << "Cannot open test image perf/1920x1080.png"; + vector buf; + EXPECT_TRUE(imencode(GetParam(), src, buf)); + + TEST_CYCLE() imdecode(buf, IMREAD_COLOR_RGB); + + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(Encode, bgr, testing::ValuesIn(exts)) +{ + String filename = getDataPath("perf/1920x1080.png"); + + Mat src = imread(filename); + EXPECT_FALSE(src.empty()) << "Cannot open test image perf/1920x1080.png"; + vector buf; + + TEST_CYCLE() imencode(GetParam(), src, buf); + + std::cout << "Encoded buffer size: " << buf.size() + << " bytes, Compression ratio: " << std::fixed << std::setprecision(2) + << (static_cast(buf.size()) / (src.total() * src.channels())) * 100.0 << "%" << std::endl; + + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(Encode, multi, testing::ValuesIn(exts_multi)) +{ + String filename = getDataPath("perf/1920x1080.png"); + vector vec; + EXPECT_TRUE(imreadmulti(filename, vec)); + vec.push_back(vec.back().clone()); + circle(vec.back(), Point(100, 100), 45, Scalar(0, 0, 255, 0), 2, LINE_AA); + vector buf; + EXPECT_TRUE(imwrite("test" + GetParam(), vec)); + + TEST_CYCLE() imencode(GetParam(), vec, buf); + + std::cout << "Encoded buffer size: " << buf.size() + << " bytes, Compression ratio: " << std::fixed << std::setprecision(2) + << (static_cast(buf.size()) / (vec[0].total() * vec[0].channels())) * 100.0 << "%" << std::endl; + + SANITY_CHECK_NOTHING(); +} +#endif // HAVE_PNG + +} // namespace diff --git a/modules/imgcodecs/src/grfmt_avif.cpp b/modules/imgcodecs/src/grfmt_avif.cpp index d3fb500604..c35eb50306 100644 --- a/modules/imgcodecs/src/grfmt_avif.cpp +++ b/modules/imgcodecs/src/grfmt_avif.cpp @@ -298,11 +298,6 @@ bool AvifEncoder::isFormatSupported(int depth) const { return (depth == CV_8U || depth == CV_16U); } -bool AvifEncoder::write(const Mat &img, const std::vector ¶ms) { - std::vector img_vec(1, img); - return writemulti(img_vec, params); -} - bool AvifEncoder::writeanimation(const Animation& animation, const std::vector ¶ms) { int bit_depth = 8; diff --git a/modules/imgcodecs/src/grfmt_avif.hpp b/modules/imgcodecs/src/grfmt_avif.hpp index 87b765619e..9f097aaf55 100644 --- a/modules/imgcodecs/src/grfmt_avif.hpp +++ b/modules/imgcodecs/src/grfmt_avif.hpp @@ -41,7 +41,6 @@ class AvifEncoder CV_FINAL : public BaseImageEncoder { ~AvifEncoder() CV_OVERRIDE; bool isFormatSupported(int depth) const CV_OVERRIDE; - bool write(const Mat& img, const std::vector& params) CV_OVERRIDE; bool writeanimation(const Animation& animation, const std::vector& params) CV_OVERRIDE; ImageEncoder newEncoder() const CV_OVERRIDE; diff --git a/modules/imgcodecs/src/grfmt_base.cpp b/modules/imgcodecs/src/grfmt_base.cpp index 1e09882780..dc3d07ab78 100644 --- a/modules/imgcodecs/src/grfmt_base.cpp +++ b/modules/imgcodecs/src/grfmt_base.cpp @@ -140,6 +140,11 @@ bool BaseImageEncoder::setDestination( std::vector& buf ) return true; } +bool BaseImageEncoder::write(const Mat &img, const std::vector ¶ms) { + std::vector img_vec(1, img); + return writemulti(img_vec, params); +} + bool BaseImageEncoder::writemulti(const std::vector& img_vec, const std::vector& params) { if(img_vec.size() > 1) @@ -157,6 +162,7 @@ bool BaseImageEncoder::writemulti(const std::vector& img_vec, const std::ve bool BaseImageEncoder::writeanimation(const Animation&, const std::vector& ) { + CV_LOG_WARNING(NULL, "No Animation encoder for specified file extension"); return false; } @@ -165,7 +171,7 @@ ImageEncoder BaseImageEncoder::newEncoder() const return ImageEncoder(); } -void BaseImageEncoder::throwOnEror() const +void BaseImageEncoder::throwOnError() const { if(!m_last_error.empty()) { diff --git a/modules/imgcodecs/src/grfmt_base.hpp b/modules/imgcodecs/src/grfmt_base.hpp index a90bd8a3de..ae5622528c 100644 --- a/modules/imgcodecs/src/grfmt_base.hpp +++ b/modules/imgcodecs/src/grfmt_base.hpp @@ -202,12 +202,11 @@ public: /** * @brief Encode and write the image data. - * This is a pure virtual function that must be implemented by derived classes. * @param img The Mat object containing the image data to be encoded. * @param params A vector of parameters controlling the encoding process (e.g., compression level). * @return true if the image was successfully written, false otherwise. */ - virtual bool write(const Mat& img, const std::vector& params) = 0; + virtual bool write(const Mat& img, const std::vector& params); /** * @brief Encode and write multiple images (e.g., for animated formats). @@ -236,7 +235,7 @@ public: * @brief Throw an exception based on the last error encountered during encoding. * This method can be used to propagate error conditions back to the caller. */ - virtual void throwOnEror() const; + virtual void throwOnError() const; protected: String m_description; ///< Description of the encoder (e.g., format name, capabilities). diff --git a/modules/imgcodecs/src/grfmt_gif.cpp b/modules/imgcodecs/src/grfmt_gif.cpp index 05b27e4ddd..5e5695b07b 100644 --- a/modules/imgcodecs/src/grfmt_gif.cpp +++ b/modules/imgcodecs/src/grfmt_gif.cpp @@ -14,7 +14,7 @@ namespace cv ////////////////////////////////////////////////////////////////////// GifDecoder::GifDecoder() { m_signature = R"(GIF)"; - m_type = CV_8UC4; + m_type = CV_8UC3; bgColor = -1; m_buf_supported = true; globalColorTableSize = 0; @@ -172,12 +172,17 @@ bool GifDecoder::readData(Mat &img) { } else { cvtColor(img_, img, COLOR_BGRA2BGR); } - } else { + } else if (img.channels() == 4){ if (m_use_rgb) { cvtColor(img_, img, COLOR_BGRA2RGBA); } else { img_.copyTo(img); } + } else if (img.channels() == 1){ + cvtColor(img_, img, COLOR_BGRA2GRAY); + } else { + CV_LOG_WARNING(NULL, cv::format("Unsupported channels: %d", img.channels())); + hasRead = false; } } @@ -414,6 +419,7 @@ bool GifDecoder::getFrameCount_() { if (extension == 0xFF) { int len = m_strm.getByte(); while (len) { + // TODO: In strictly, Application Identifier and Authentication Code should be checked. if (len == 3) { if (m_strm.getByte() == 0x01) { m_animation.loop_count = m_strm.getWord(); @@ -427,9 +433,28 @@ bool GifDecoder::getFrameCount_() { } len = m_strm.getByte(); } + } else if (extension == 0xF9) { + int len = m_strm.getByte(); + while (len) { + if (len == 4) { + int packedFields = m_strm.getByte(); + // 3 bit : Reserved + // 3 bit : Disposal Method + // 1 bit : User Input Flag + // 1 bit : Transparent Color Flag + if ( (packedFields & 0x01)== 0x01) { + m_type = CV_8UC4; // Transparent Index is given. + } + m_strm.skip(2); // Delay Time + m_strm.skip(1); // Transparent Color Index + } else { + m_strm.skip(len); + } + len = m_strm.getByte(); + } } else { // if it does not belong to any of the extension type mentioned in the GIF Specification - if (extension != 0xF9 && extension != 0xFE && extension != 0x01) { + if (extension != 0xFE && extension != 0x01) { CV_LOG_WARNING(NULL, "found Unknown Extension Type: " + std::to_string(extension)); } int len = m_strm.getByte(); @@ -514,19 +539,11 @@ GifEncoder::~GifEncoder() { close(); } -bool GifEncoder::isFormatSupported(int depth) const { - return depth == CV_8U; -} - -bool GifEncoder::write(const Mat &img, const std::vector ¶ms) { - std::vector img_vec(1, img); - return writemulti(img_vec, params); -} - bool GifEncoder::writeanimation(const Animation& animation, const std::vector& params) { if (animation.frames.empty()) { return false; } + CV_CheckDepthEQ(animation.frames[0].depth(), CV_8U, "GIF encoder supports only 8-bit unsigned images"); if (m_buf) { if (!strm.open(*m_buf)) { diff --git a/modules/imgcodecs/src/grfmt_gif.hpp b/modules/imgcodecs/src/grfmt_gif.hpp index 8f520745ba..8552718d00 100644 --- a/modules/imgcodecs/src/grfmt_gif.hpp +++ b/modules/imgcodecs/src/grfmt_gif.hpp @@ -83,9 +83,6 @@ public: GifEncoder(); ~GifEncoder() CV_OVERRIDE; - bool isFormatSupported(int depth) const CV_OVERRIDE; - - bool write(const Mat& img, const std::vector& params) CV_OVERRIDE; bool writeanimation(const Animation& animation, const std::vector& params) CV_OVERRIDE; ImageEncoder newEncoder() const CV_OVERRIDE; diff --git a/modules/imgcodecs/src/grfmt_jpegxl.cpp b/modules/imgcodecs/src/grfmt_jpegxl.cpp index fc89dd2c6e..060174eb02 100644 --- a/modules/imgcodecs/src/grfmt_jpegxl.cpp +++ b/modules/imgcodecs/src/grfmt_jpegxl.cpp @@ -12,16 +12,31 @@ namespace cv { +// Callback functions for JpegXLDecoder +static void cbRGBtoBGR_8U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels); +static void cbRGBAtoBGRA_8U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels); +static void cbRGBtoBGR_16U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels); +static void cbRGBAtoBGRA_16U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels); +static void cbRGBtoBGR_32F(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels); +static void cbRGBAtoBGRA_32F(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels); +static void cbRGBtoGRAY_8U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels); +static void cbRGBAtoGRAY_8U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels); +static void cbRGBtoGRAY_16U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels); +static void cbRGBAtoGRAY_16U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels); +static void cbRGBtoGRAY_32F(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels); +static void cbRGBAtoGRAY_32F(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels); /////////////////////// JpegXLDecoder /////////////////// -JpegXLDecoder::JpegXLDecoder() : m_f(nullptr, &fclose) +JpegXLDecoder::JpegXLDecoder() : m_f(nullptr, &fclose), + m_read_buffer(16384,0) // 16KB chunks { m_signature = "\xFF\x0A"; m_decoder = nullptr; - m_buf_supported = false; - m_type = m_convert = -1; + m_buf_supported = true; + m_type = -1; m_status = JXL_DEC_NEED_MORE_INPUT; + m_is_mbuf_set = false; } JpegXLDecoder::~JpegXLDecoder() @@ -32,13 +47,14 @@ JpegXLDecoder::~JpegXLDecoder() void JpegXLDecoder::close() { if (m_decoder) - m_decoder.release(); + m_decoder.reset(); if (m_f) - m_f.release(); + m_f.reset(); m_read_buffer = {}; m_width = m_height = 0; - m_type = m_convert = -1; + m_type = -1; m_status = JXL_DEC_NEED_MORE_INPUT; + m_is_mbuf_set = false; } // see https://github.com/libjxl/libjxl/blob/v0.10.0/doc/format_overview.md @@ -76,13 +92,16 @@ ImageDecoder JpegXLDecoder::newDecoder() const return makePtr(); } -bool JpegXLDecoder::read(Mat* pimg) +bool JpegXLDecoder::readHeader() { - // Open file - if (!m_f) { - m_f.reset(fopen(m_filename.c_str(), "rb")); - if (!m_f) - return false; + if (m_buf.empty()) { + // Open file + if (!m_f) { + m_f.reset(fopen(m_filename.c_str(), "rb")); + if (!m_f) { + return false; + } + } } // Initialize decoder @@ -106,51 +125,132 @@ bool JpegXLDecoder::read(Mat* pimg) } } - // Create buffer for reading - const size_t read_buffer_size = 16384; // 16KB chunks - if (m_read_buffer.capacity() < read_buffer_size) - m_read_buffer.resize(read_buffer_size); + // Reset to read header data stream + m_is_mbuf_set = false; - // Create image if needed - if (m_type != -1 && pimg) { - pimg->create(m_height, m_width, m_type); - if (!pimg->isContinuous()) + return read(); +} + +bool JpegXLDecoder::readData(Mat& img) +{ + if (!m_decoder || m_width == 0 || m_height == 0 || m_type == -1) + return false; + + // Prepare to decode image + const uint32_t scn = CV_MAT_CN(m_type); // from image + const uint32_t dcn = (uint32_t)img.channels(); // to OpenCV + const int depth = CV_MAT_DEPTH(img.type()); + JxlImageOutCallback cbFunc = nullptr; + + CV_CheckChannels(scn, (scn == 1 || scn == 3 || scn == 4), "Unsupported src channels"); + CV_CheckChannels(dcn, (dcn == 1 || dcn == 3 || dcn == 4), "Unsupported dst channels"); + CV_CheckDepth(depth, (depth == CV_8U || depth == CV_16U || depth == CV_32F), "Unsupported depth"); + + m_format = { + dcn, + JXL_TYPE_UINT8, // (temporary) + JXL_NATIVE_ENDIAN, // endianness + 0 // align stride to bytes + }; + switch (depth) { + case CV_8U: m_format.data_type = JXL_TYPE_UINT8; break; + case CV_16U: m_format.data_type = JXL_TYPE_UINT16; break; + case CV_32F: m_format.data_type = JXL_TYPE_FLOAT; break; + default: break; + } + // libjxl cannot read to BGR pixel order directly. + // So we have to use callback function to convert from RGB(A) to BGR(A). + if (!m_use_rgb) { + switch (dcn) { + case 1: break; + case 3: cbFunc = (depth == CV_32F)? cbRGBtoBGR_32F: (depth == CV_16U)? cbRGBtoBGR_16U: cbRGBtoBGR_8U; break; + case 4: cbFunc = (depth == CV_32F)? cbRGBAtoBGRA_32F: (depth == CV_16U)? cbRGBAtoBGRA_16U: cbRGBAtoBGRA_8U; break; + default: break; + } + } + // libjxl cannot convert from color image to gray image directly. + // So we have to use callback function to convert from RGB(A) to GRAY. + if( (scn >= 3) && (dcn == 1) ) + { + m_format.num_channels = scn; + switch (scn) { + case 3: cbFunc = (depth == CV_32F)? cbRGBtoGRAY_32F: (depth == CV_16U)? cbRGBtoGRAY_16U: cbRGBtoGRAY_8U; break; + case 4: cbFunc = (depth == CV_32F)? cbRGBAtoGRAY_32F: (depth == CV_16U)? cbRGBAtoGRAY_16U: cbRGBAtoGRAY_8U; break; + default: break; + } + } + if(cbFunc != nullptr) + { + if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutCallback(m_decoder.get(), + &m_format, + cbFunc, + static_cast(&img))) + { return false; + } + }else{ if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(m_decoder.get(), &m_format, - pimg->ptr(), - pimg->total() * pimg->elemSize())) { + img.ptr(), + img.total() * img.elemSize())) + { return false; } } + return read(); +} + +// Common reading routine for readHeader() and readBody() +bool JpegXLDecoder::read() +{ // Start decoding loop do { // Check if we need more input if (m_status == JXL_DEC_NEED_MORE_INPUT) { - size_t remaining = JxlDecoderReleaseInput(m_decoder.get()); - // Move any remaining bytes to the beginning - if (remaining > 0) - memmove(m_read_buffer.data(), m_read_buffer.data() + m_read_buffer.size() - remaining, remaining); - // Read more data from file - size_t bytes_read = fread(m_read_buffer.data() + remaining, - 1, m_read_buffer.size() - remaining, m_f.get()); - if (bytes_read == 0) { - if (ferror(m_f.get())) { - CV_LOG_WARNING(NULL, "Error reading input file"); + uint8_t* data_ptr = nullptr; + size_t data_len = 0; + + if( !m_buf.empty() ) { + // When data source in on memory + if (m_is_mbuf_set) { + // We expect m_buf contains whole JpegXL data stream. + // If it had been truncated, m_status will be JXL_DEC_NEED_MORE_INPUT again. + CV_LOG_WARNING(NULL, "Truncated JXL data in memory"); return false; } - // If we reached EOF but decoder needs more input, file is truncated - if (m_status == JXL_DEC_NEED_MORE_INPUT) { - CV_LOG_WARNING(NULL, "Truncated JXL file"); - return false; + data_ptr = m_buf.ptr(); + data_len = m_buf.total(); + m_is_mbuf_set = true; + } + else { + // When data source is on file + // Release input buffer if it had been set already. If not, there are no errors. + size_t remaining = JxlDecoderReleaseInput(m_decoder.get()); + // Move any remaining bytes to the beginning + if (remaining > 0) + memmove(m_read_buffer.data(), m_read_buffer.data() + m_read_buffer.size() - remaining, remaining); + // Read more data from file + size_t bytes_read = fread(m_read_buffer.data() + remaining, + 1, m_read_buffer.size() - remaining, m_f.get()); + if (bytes_read == 0) { + if (ferror(m_f.get())) { + CV_LOG_WARNING(NULL, "Error reading input file"); + return false; + } + // If we reached EOF but decoder needs more input, file is truncated + if (m_status == JXL_DEC_NEED_MORE_INPUT) { + CV_LOG_WARNING(NULL, "Truncated JXL file"); + return false; + } } + data_ptr = m_read_buffer.data(); + data_len = bytes_read + remaining; } // Set input buffer - if (JXL_DEC_SUCCESS != JxlDecoderSetInput(m_decoder.get(), - m_read_buffer.data(), - bytes_read + remaining)) { + // It must be kept until calling JxlDecoderReleaseInput() or m_decoder.reset(). + if (JXL_DEC_SUCCESS != JxlDecoderSetInput(m_decoder.get(), data_ptr, data_len)) { return false; } } @@ -163,6 +263,7 @@ bool JpegXLDecoder::read(Mat* pimg) case JXL_DEC_BASIC_INFO: { if (m_type != -1) return false; + JxlBasicInfo info; if (JXL_DEC_SUCCESS != JxlDecoderGetBasicInfo(m_decoder.get(), &info)) return false; @@ -172,49 +273,18 @@ bool JpegXLDecoder::read(Mat* pimg) m_width = info.xsize; m_height = info.ysize; - m_format = { - ncn, - JXL_TYPE_UINT8, // (temporary) - JXL_LITTLE_ENDIAN, // endianness - 0 // align stride to bytes - }; - if (!m_use_rgb) { - switch (ncn) { - case 3: - m_convert = cv::COLOR_RGB2BGR; - break; - case 4: - m_convert = cv::COLOR_RGBA2BGRA; - break; - default: - m_convert = -1; - } + int depth = (info.exponent_bits_per_sample > 0)?CV_32F: + (info.bits_per_sample == 16)?CV_16U: + (info.bits_per_sample == 8)?CV_8U: -1; + if(depth == -1) + { + return false; // Return to readHeader() } - if (info.exponent_bits_per_sample > 0) { - m_format.data_type = JXL_TYPE_FLOAT; - m_type = CV_MAKETYPE( CV_32F, ncn ); - } else { - switch (info.bits_per_sample) { - case 8: - m_format.data_type = JXL_TYPE_UINT8; - m_type = CV_MAKETYPE( CV_8U, ncn ); - break; - case 16: - m_format.data_type = JXL_TYPE_UINT16; - m_type = CV_MAKETYPE( CV_16U, ncn ); - break; - default: - return false; - } - } - if (!pimg) - return true; - break; + m_type = CV_MAKETYPE( depth, ncn ); + return true; } case JXL_DEC_FULL_IMAGE: { // Image is ready - if (m_convert != -1) - cv::cvtColor(*pimg, *pimg, m_convert); break; } case JXL_DEC_ERROR: { @@ -229,17 +299,172 @@ bool JpegXLDecoder::read(Mat* pimg) return true; } -bool JpegXLDecoder::readHeader() +// Callback functopms +static void cbRGBtoBGR_8U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels) { - close(); - return read(nullptr); + const uint8_t* src = static_cast(pixels); + + constexpr int dstStep = 3; + const cv::Mat *pDst = static_cast(opaque); + uint8_t* dstBase = const_cast(pDst->ptr(y)); + uint8_t* dst = dstBase + x * dstStep; + + icvCvt_RGB2BGR_8u_C3R( src, 0, dst, 0, Size(num_pixels , 1) ); +} +static void cbRGBAtoBGRA_8U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels) +{ + const uint8_t* src = static_cast(pixels); + + constexpr int dstStep = 4; + const cv::Mat *pDst = static_cast(opaque); + uint8_t* dstBase = const_cast(reinterpret_cast(pDst->ptr(y))); + uint8_t* dst = dstBase + x * dstStep; + + icvCvt_RGBA2BGRA_8u_C4R( src, 0, dst, 0, Size(num_pixels, 1) ); +} +static void cbRGBtoBGR_16U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels) +{ + const uint16_t* src = static_cast(pixels); + + constexpr int dstStep = 3; + const cv::Mat *pDst = static_cast(opaque); + uint16_t* dstBase = const_cast(reinterpret_cast(pDst->ptr(y))); + uint16_t* dst = dstBase + x * dstStep; + + icvCvt_BGR2RGB_16u_C3R( src, 0, dst, 0, Size(num_pixels, 1)); +} +static void cbRGBAtoBGRA_16U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels) +{ + const uint16_t* src = static_cast(pixels); + + constexpr int dstStep = 4; + const cv::Mat *pDst = static_cast(opaque); + uint16_t* dstBase = const_cast(reinterpret_cast(pDst->ptr(y))); + uint16_t* dst = dstBase + x * dstStep; + + icvCvt_BGRA2RGBA_16u_C4R( src, 0, dst, 0, Size(num_pixels, 1)); +} +static void cbRGBtoBGR_32F(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels) +{ + constexpr int srcStep = 3; + const uint32_t* src = static_cast(pixels); + + constexpr int dstStep = 3; + const cv::Mat *pDst = static_cast(opaque); + uint32_t* dstBase = const_cast(reinterpret_cast(pDst->ptr(y))); + uint32_t* dst = dstBase + x * dstStep; + + for(size_t i = 0 ; i < num_pixels; i++) + { + dst[ i * dstStep + 0 ] = src[ i * srcStep + 2]; + dst[ i * dstStep + 1 ] = src[ i * srcStep + 1]; + dst[ i * dstStep + 2 ] = src[ i * srcStep + 0]; + } +} +static void cbRGBAtoBGRA_32F(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels) +{ + constexpr int srcStep = 4; + const uint32_t* src = static_cast(pixels); + + constexpr int dstStep = 4; + const cv::Mat *pDst = static_cast(opaque); + uint32_t* dstBase = const_cast(reinterpret_cast(pDst->ptr(y))); + uint32_t* dst = dstBase + x * dstStep; + + for(size_t i = 0 ; i < num_pixels; i++) + { + dst[ i * dstStep + 0 ] = src[ i * srcStep + 2]; + dst[ i * dstStep + 1 ] = src[ i * srcStep + 1]; + dst[ i * dstStep + 2 ] = src[ i * srcStep + 0]; + dst[ i * dstStep + 3 ] = src[ i * srcStep + 3]; + } } -bool JpegXLDecoder::readData(Mat& img) +static void cbRGBtoGRAY_8U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels) { - if (!m_decoder || m_width == 0 || m_height == 0) - return false; - return read(&img); + const uint8_t* src = static_cast(pixels); + + constexpr int dstStep = 1; + const cv::Mat *pDst = static_cast(opaque); + uint8_t* dstBase = const_cast(reinterpret_cast(pDst->ptr(y))); + uint8_t* dst = dstBase + x * dstStep; + + icvCvt_BGR2Gray_8u_C3C1R(src, 0, dst, 0, Size(num_pixels, 1) ); +} +static void cbRGBAtoGRAY_8U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels) +{ + const uint8_t* src = static_cast(pixels); + + constexpr int dstStep = 1; + const cv::Mat *pDst = static_cast(opaque); + uint8_t* dstBase = const_cast(reinterpret_cast(pDst->ptr(y))); + uint8_t* dst = dstBase + x * dstStep; + + icvCvt_BGRA2Gray_8u_C4C1R(src, 0, dst, 0, Size(num_pixels, 1) ); +} +static void cbRGBtoGRAY_16U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels) +{ + const uint16_t* src = static_cast(pixels); + + constexpr int dstStep = 1; + const cv::Mat *pDst = static_cast(opaque); + uint16_t* dstBase = const_cast(reinterpret_cast(pDst->ptr(y))); + uint16_t* dst = dstBase + x * dstStep; + + icvCvt_BGRA2Gray_16u_CnC1R(src, 0, dst, 0, Size(num_pixels, 1), /* ncn= */ 3 ); +} +static void cbRGBAtoGRAY_16U(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels) +{ + const uint16_t* src = static_cast(pixels); + + constexpr int dstStep = 1; + const cv::Mat *pDst = static_cast(opaque); + uint16_t* dstBase = const_cast(reinterpret_cast(pDst->ptr(y))); + uint16_t* dst = dstBase + x * dstStep; + + icvCvt_BGRA2Gray_16u_CnC1R(src, 0, dst, 0, Size(num_pixels, 1), /* ncn= */ 4 ); +} +static void cbRGBtoGRAY_32F(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels) +{ + constexpr float cR = 0.299f; + constexpr float cG = 0.587f; + constexpr float cB = 1.000f - cR - cG; + + constexpr int srcStep = 3; + const float* src = static_cast(pixels); + + constexpr int dstStep = 1; + const cv::Mat *pDst = static_cast(opaque); + float* dstBase = const_cast(reinterpret_cast(pDst->ptr(y))); + float* dst = dstBase + x * dstStep; + + for(size_t i = 0 ; i < num_pixels; i++) + { + dst[ i * dstStep ] = src[ i * srcStep + 0] * cR + + src[ i * srcStep + 1] * cG + + src[ i * srcStep + 2] * cB; + } +} +static void cbRGBAtoGRAY_32F(void *opaque, size_t x, size_t y, size_t num_pixels, const void *pixels) +{ + constexpr float cR = 0.299f; + constexpr float cG = 0.587f; + constexpr float cB = 1.000f - cR - cG; + + constexpr int srcStep = 4; + const float* src = static_cast(pixels); + + constexpr int dstStep = 1; + const cv::Mat *pDst = static_cast(opaque); + float* dstBase = const_cast(reinterpret_cast(pDst->ptr(y))); + float* dst = dstBase + x * dstStep; + + for(size_t i = 0 ; i < num_pixels; i++) + { + dst[ i * dstStep ] = src[ i * srcStep + 0] * cR + + src[ i * srcStep + 1] * cG + + src[ i * srcStep + 2] * cB; + } } /////////////////////// JpegXLEncoder /////////////////// diff --git a/modules/imgcodecs/src/grfmt_jpegxl.hpp b/modules/imgcodecs/src/grfmt_jpegxl.hpp index 87e4bfcba5..d9b046b779 100644 --- a/modules/imgcodecs/src/grfmt_jpegxl.hpp +++ b/modules/imgcodecs/src/grfmt_jpegxl.hpp @@ -41,12 +41,12 @@ protected: JxlDecoderPtr m_decoder; JxlThreadParallelRunnerPtr m_parallel_runner; JxlPixelFormat m_format; - int m_convert; std::vector m_read_buffer; JxlDecoderStatus m_status; + bool m_is_mbuf_set; private: - bool read(Mat* pimg); + bool read(); }; diff --git a/modules/imgcodecs/src/grfmt_png.cpp b/modules/imgcodecs/src/grfmt_png.cpp index 1ecc01f17f..84df975471 100644 --- a/modules/imgcodecs/src/grfmt_png.cpp +++ b/modules/imgcodecs/src/grfmt_png.cpp @@ -121,15 +121,16 @@ namespace cv { -const uint32_t id_IHDR = 0x52444849; // PNG header -const uint32_t id_acTL = 0x4C546361; // Animation control chunk -const uint32_t id_fcTL = 0x4C546366; // Frame control chunk -const uint32_t id_IDAT = 0x54414449; // first frame and/or default image -const uint32_t id_fdAT = 0x54416466; // Frame data chunk -const uint32_t id_PLTE = 0x45544C50; -const uint32_t id_bKGD = 0x44474B62; -const uint32_t id_tRNS = 0x534E5274; -const uint32_t id_IEND = 0x444E4549; // end/footer chunk +const uint32_t id_IHDR = 0x49484452; // PNG header +const uint32_t id_acTL = 0x6163544C; // Animation control chunk +const uint32_t id_fcTL = 0x6663544C; // Frame control chunk +const uint32_t id_IDAT = 0x49444154; // first frame and/or default image +const uint32_t id_fdAT = 0x66644154; // Frame data chunk +const uint32_t id_PLTE = 0x504C5445; // The PLTE chunk contains a color palette for indexed-color images +const uint32_t id_bKGD = 0x624B4744; // The bKGD chunk specifies a default background color for the image +const uint32_t id_tRNS = 0x74524E53; // The tRNS chunk provides transparency information +const uint32_t id_tEXt = 0x74455874; // The tEXt chunk stores metadata as text in key-value pairs +const uint32_t id_IEND = 0x49454E44; // end/footer chunk APNGFrame::APNGFrame() { @@ -198,6 +199,7 @@ PngDecoder::PngDecoder() PngDecoder::~PngDecoder() { + ClearPngPtr(); if( m_f ) { fclose( m_f ); @@ -205,6 +207,26 @@ PngDecoder::~PngDecoder() } } +bool PngDecoder::InitPngPtr() { + ClearPngPtr(); + + m_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (!m_png_ptr) + return false; + + m_info_ptr = png_create_info_struct(m_png_ptr); + m_end_info = png_create_info_struct(m_png_ptr); + return (m_info_ptr && m_end_info); +} + +void PngDecoder::ClearPngPtr() { + if (m_png_ptr) + png_destroy_read_struct(&m_png_ptr, &m_info_ptr, &m_end_info); + m_png_ptr = nullptr; + m_info_ptr = nullptr; + m_end_info = nullptr; +} + ImageDecoder PngDecoder::newDecoder() const { return makePtr(); @@ -227,167 +249,144 @@ void PngDecoder::readDataFromBuf( void* _png_ptr, unsigned char* dst, size_t si bool PngDecoder::readHeader() { - volatile bool result = false; + // Declare dynamic variables before a potential longjmp. + Chunk chunk; - PngPtrs png_ptrs; - png_structp png_ptr = png_ptrs.getPng(); - png_infop info_ptr = png_ptrs.getInfo(); - png_infop end_info = png_ptrs.getEndInfo(); + if (!InitPngPtr()) + return false; - if( png_ptr && info_ptr && end_info ) + if (setjmp(png_jmpbuf(m_png_ptr))) + return false; + + m_buf_pos = 0; + unsigned char sig[8]; + uint32_t id = 0; + + if( !m_buf.empty() ) + png_set_read_fn(m_png_ptr, this, (png_rw_ptr)readDataFromBuf ); + else { - m_buf_pos = 0; - if( setjmp( png_jmpbuf( png_ptr ) ) == 0 ) + m_f = fopen(m_filename.c_str(), "rb"); + if (!m_f) { - unsigned char sig[8]; - uint32_t id = 0; - Chunk chunk; - - if( !m_buf.empty() ) - png_set_read_fn(png_ptr, this, (png_rw_ptr)readDataFromBuf ); - else - { - m_f = fopen(m_filename.c_str(), "rb"); - if (!m_f) - { - return false; - } - png_init_io(png_ptr, m_f); - } - - // Read PNG header: 137 80 78 71 13 10 26 10 - if (!read_from_io(&sig, 8)) - return false; - - id = read_chunk(m_chunkIHDR); - // 8=HDR+size, 13=size of IHDR chunk, 4=CRC - // http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html#C.IHDR - if (!(id == id_IHDR && m_chunkIHDR.p.size() == 8 + 13 + 4)) - { - return false; - } - - while (true) - { - m_is_fcTL_loaded = false; - id = read_chunk(chunk); - - if (!id || (m_f && feof(m_f)) || (!m_buf.empty() && m_buf_pos > m_buf.total())) - { - return false; - } - - if (id == id_IDAT) - { - if (m_f) - fseek(m_f, 0, SEEK_SET); - else - m_buf_pos = 0; - break; - } - - if (id == id_acTL) - { - // 8=HDR+size, 8=size of acTL chunk, 4=CRC - // https://wiki.mozilla.org/APNG_Specification#%60acTL%60:_The_Animation_Control_Chunk - if (chunk.p.size() != 8 + 8 + 4) - return false; - m_animation.loop_count = png_get_uint_32(&chunk.p[12]); - - m_frame_count = png_get_uint_32(&chunk.p[8]); - if (m_frame_count == 0) - return false; - } - - if (id == id_fcTL) - { - // 8=HDR+size, 26=size of fcTL chunk, 4=CRC - // https://wiki.mozilla.org/APNG_Specification#%60fcTL%60:_The_Frame_Control_Chunk - if (chunk.p.size() != 8 + 26 + 4) - return false; - m_is_fcTL_loaded = true; - w0 = png_get_uint_32(&chunk.p[12]); - h0 = png_get_uint_32(&chunk.p[16]); - x0 = png_get_uint_32(&chunk.p[20]); - y0 = png_get_uint_32(&chunk.p[24]); - delay_num = png_get_uint_16(&chunk.p[28]); - delay_den = png_get_uint_16(&chunk.p[30]); - dop = chunk.p[32]; - bop = chunk.p[33]; - } - - if (id == id_bKGD) - { - // 8=HDR+size, ??=size of bKGD chunk, 4=CRC - // The spec is actually more complex: http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html#C.bKGD - // TODO: we only check that 4 bytes can be read from &chunk.p[8]. Fix. - if (chunk.p.size() < 8 + 4) - return false; - int bgcolor = png_get_uint_32(&chunk.p[8]); - m_animation.bgcolor[3] = (bgcolor >> 24) & 0xFF; - m_animation.bgcolor[2] = (bgcolor >> 16) & 0xFF; - m_animation.bgcolor[1] = (bgcolor >> 8) & 0xFF; - m_animation.bgcolor[0] = bgcolor & 0xFF; - } - - if (id == id_PLTE || id == id_tRNS) - m_chunksInfo.push_back(chunk); - } - - png_uint_32 wdth, hght; - int bit_depth, color_type, num_trans=0; - png_bytep trans; - png_color_16p trans_values; - - // Free chunk in case png_read_info uses longjmp. - chunk.p.clear(); - chunk.p.shrink_to_fit(); - - png_read_info( png_ptr, info_ptr ); - png_get_IHDR(png_ptr, info_ptr, &wdth, &hght, - &bit_depth, &color_type, 0, 0, 0); - - m_width = (int)wdth; - m_height = (int)hght; - m_color_type = color_type; - m_bit_depth = bit_depth; - - if (bit_depth <= 8 || bit_depth == 16) - { - switch (color_type) - { - case PNG_COLOR_TYPE_RGB: - case PNG_COLOR_TYPE_PALETTE: - png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values); - if (num_trans > 0) - m_type = CV_8UC4; - else - m_type = CV_8UC3; - break; - case PNG_COLOR_TYPE_GRAY_ALPHA: - case PNG_COLOR_TYPE_RGB_ALPHA: - m_type = CV_8UC4; - break; - default: - m_type = CV_8UC1; - } - if (bit_depth == 16) - m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type)); - result = true; - } + return false; } + png_init_io(m_png_ptr, m_f); } - if(result) + // Read PNG header: 137 80 78 71 13 10 26 10 + if (!readFromStreamOrBuffer(&sig, 8)) + return false; + + id = read_chunk(m_chunkIHDR); + if (id != id_IHDR) + return false; + + m_is_fcTL_loaded = false; + while (true) { - m_png_ptrs = std::move(png_ptrs); + id = read_chunk(chunk); + + if (!id || (m_f && feof(m_f)) || (!m_buf.empty() && m_buf_pos > m_buf.total())) + { + return false; + } + + if (id == id_IDAT) + { + if (m_f) + fseek(m_f, 0, SEEK_SET); + else + m_buf_pos = 0; + break; + } + + if (id == id_acTL) + { + // https://wiki.mozilla.org/APNG_Specification#%60acTL%60:_The_Animation_Control_Chunk + m_animation.loop_count = png_get_uint_32(&chunk.p[12]); + + m_frame_count = png_get_uint_32(&chunk.p[8]); + if (m_frame_count == 0) + return false; + } + + if (id == id_fcTL) + { + // https://wiki.mozilla.org/APNG_Specification#%60fcTL%60:_The_Frame_Control_Chunk + m_is_fcTL_loaded = true; + w0 = png_get_uint_32(&chunk.p[12]); + h0 = png_get_uint_32(&chunk.p[16]); + x0 = png_get_uint_32(&chunk.p[20]); + y0 = png_get_uint_32(&chunk.p[24]); + delay_num = png_get_uint_16(&chunk.p[28]); + delay_den = png_get_uint_16(&chunk.p[30]); + dop = chunk.p[32]; + bop = chunk.p[33]; + } + + if (id == id_PLTE || id == id_tRNS) + m_chunksInfo.push_back(chunk); } - return result; + png_uint_32 wdth, hght; + int bit_depth, color_type, num_trans=0; + png_bytep trans; + png_color_16p trans_values; + + // Free chunk in case png_read_info uses longjmp. + chunk.p.clear(); + chunk.p.shrink_to_fit(); + + png_read_info( m_png_ptr, m_info_ptr ); + png_get_IHDR(m_png_ptr, m_info_ptr, &wdth, &hght, + &bit_depth, &color_type, 0, 0, 0); + + m_width = (int)wdth; + m_height = (int)hght; + m_color_type = color_type; + m_bit_depth = bit_depth; + + if (m_is_fcTL_loaded && ((long long int)x0 + w0 > m_width || (long long int)y0 + h0 > m_height || dop > 2 || bop > 1)) + return false; + + png_color_16p background_color; + if (png_get_bKGD(m_png_ptr, m_info_ptr, &background_color)) + m_animation.bgcolor = Scalar(background_color->blue, background_color->green, background_color->red); + + if (bit_depth <= 8 || bit_depth == 16) + { + switch (color_type) + { + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_PALETTE: + png_get_tRNS(m_png_ptr, m_info_ptr, &trans, &num_trans, &trans_values); + if (num_trans > 0) + m_type = CV_8UC4; + else + m_type = CV_8UC3; + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + case PNG_COLOR_TYPE_RGB_ALPHA: + m_type = CV_8UC4; + break; + default: + m_type = CV_8UC1; + } + if (bit_depth == 16) + m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type)); + } + + return true; } bool PngDecoder::readData( Mat& img ) { + // Declare dynamic variables before a potential longjmp. + AutoBuffer _buffer(m_height); + unsigned char** buffer = _buffer.data(); + Chunk chunk; + if (m_frame_count > 1) { Mat mat_cur = Mat::zeros(img.rows, img.cols, m_type); @@ -412,13 +411,14 @@ bool PngDecoder::readData( Mat& img ) frameCur.setMat(mat_cur); - processing_start((void*)&frameRaw, mat_cur); - png_structp png_ptr = m_png_ptrs.getPng(); - png_infop info_ptr = m_png_ptrs.getInfo(); + if (!processing_start((void*)&frameRaw, mat_cur)) + return false; + + if(setjmp(png_jmpbuf(m_png_ptr))) + return false; while (true) { - Chunk chunk; id = read_chunk(chunk); if (!id) return false; @@ -482,14 +482,14 @@ bool PngDecoder::readData( Mat& img ) else if (id == id_IDAT) { m_is_IDAT_loaded = true; - png_process_data(png_ptr, info_ptr, chunk.p.data(), chunk.p.size()); + png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size()); } else if (id == id_fdAT && m_is_fcTL_loaded) { m_is_IDAT_loaded = true; png_save_uint_32(&chunk.p[4], static_cast(chunk.p.size() - 16)); memcpy(&chunk.p[8], "IDAT", 4); - png_process_data(png_ptr, info_ptr, &chunk.p[4], chunk.p.size() - 4); + png_process_data(m_png_ptr, m_info_ptr, &chunk.p[4], chunk.p.size() - 4); } else if (id == id_IEND) { @@ -513,30 +513,24 @@ bool PngDecoder::readData( Mat& img ) return true; } else - png_process_data(png_ptr, info_ptr, chunk.p.data(), chunk.p.size()); + png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size()); } return false; } volatile bool result = false; - AutoBuffer _buffer(m_height); - unsigned char** buffer = _buffer.data(); bool color = img.channels() > 1; - png_structp png_ptr = m_png_ptrs.getPng(); - png_infop info_ptr = m_png_ptrs.getInfo(); - png_infop end_info = m_png_ptrs.getEndInfo(); - - if( png_ptr && info_ptr && end_info && m_width && m_height ) + if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height ) { - if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 ) + if( setjmp( png_jmpbuf ( m_png_ptr ) ) == 0 ) { int y; if( img.depth() == CV_8U && m_bit_depth == 16 ) - png_set_strip_16( png_ptr ); + png_set_strip_16( m_png_ptr ); else if( !isBigEndian() ) - png_set_swap( png_ptr ); + png_set_swap( m_png_ptr ); if(img.channels() < 4) { @@ -548,46 +542,46 @@ bool PngDecoder::readData( Mat& img ) * indicate that it is a good idea to always ask for * stripping alpha.. 18.11.2004 Axel Walthelm */ - png_set_strip_alpha( png_ptr ); + png_set_strip_alpha( m_png_ptr ); } else - png_set_tRNS_to_alpha( png_ptr ); + png_set_tRNS_to_alpha( m_png_ptr ); if( m_color_type == PNG_COLOR_TYPE_PALETTE ) - png_set_palette_to_rgb( png_ptr ); + png_set_palette_to_rgb( m_png_ptr ); if( (m_color_type & PNG_COLOR_MASK_COLOR) == 0 && m_bit_depth < 8 ) #if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \ (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18) - png_set_expand_gray_1_2_4_to_8( png_ptr ); + png_set_expand_gray_1_2_4_to_8( m_png_ptr ); #else png_set_gray_1_2_4_to_8( png_ptr ); #endif if( (m_color_type & PNG_COLOR_MASK_COLOR) && color && !m_use_rgb) - png_set_bgr( png_ptr ); // convert RGB to BGR + png_set_bgr( m_png_ptr ); // convert RGB to BGR else if( color ) - png_set_gray_to_rgb( png_ptr ); // Gray->RGB + png_set_gray_to_rgb( m_png_ptr ); // Gray->RGB else - png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray + png_set_rgb_to_gray( m_png_ptr, 1, 0.299, 0.587 ); // RGB->Gray - png_set_interlace_handling( png_ptr ); - png_read_update_info( png_ptr, info_ptr ); + png_set_interlace_handling( m_png_ptr ); + png_read_update_info( m_png_ptr, m_info_ptr ); for( y = 0; y < m_height; y++ ) buffer[y] = img.data + y*img.step; - png_read_image( png_ptr, buffer ); - png_read_end( png_ptr, end_info ); + png_read_image( m_png_ptr, buffer ); + png_read_end( m_png_ptr, m_end_info ); #ifdef PNG_eXIf_SUPPORTED png_uint_32 num_exif = 0; png_bytep exif = 0; // Exif info could be in info_ptr (intro_info) or end_info per specification - if( png_get_valid(png_ptr, info_ptr, PNG_INFO_eXIf) ) - png_get_eXIf_1(png_ptr, info_ptr, &num_exif, &exif); - else if( png_get_valid(png_ptr, end_info, PNG_INFO_eXIf) ) - png_get_eXIf_1(png_ptr, end_info, &num_exif, &exif); + if( png_get_valid(m_png_ptr, m_info_ptr, PNG_INFO_eXIf) ) + png_get_eXIf_1(m_png_ptr, m_info_ptr, &num_exif, &exif); + else if( png_get_valid(m_png_ptr, m_end_info, PNG_INFO_eXIf) ) + png_get_eXIf_1(m_png_ptr, m_end_info, &num_exif, &exif); if( exif && num_exif > 0 ) { @@ -683,7 +677,7 @@ void PngDecoder::compose_frame(std::vector& rows_dst, const std::vect }); } -bool PngDecoder::read_from_io(void* buffer, size_t num_bytes) +bool PngDecoder::readFromStreamOrBuffer(void* buffer, size_t num_bytes) { if (m_f) return fread(buffer, 1, num_bytes, m_f) == num_bytes; @@ -700,61 +694,78 @@ bool PngDecoder::read_from_io(void* buffer, size_t num_bytes) uint32_t PngDecoder::read_chunk(Chunk& chunk) { - unsigned char len[4]; - if (read_from_io(&len, 4)) - { - const size_t size = static_cast(png_get_uint_32(len)) + 12; + unsigned char size_id[8]; + if (!readFromStreamOrBuffer(&size_id, 8)) + return 0; + const size_t size = static_cast(png_get_uint_32(size_id)) + 12; + + const uint32_t id = png_get_uint_32(size_id + 4); + if (id == id_IHDR) { + // 8=HDR+size, 13=size of IHDR chunk, 4=CRC + // http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html#C.IHDR + if (size != 8 + 13 + 4) + return 0; + } else if (id == id_acTL) { + // 8=HDR+size, 8=size of acTL chunk, 4=CRC + // https://wiki.mozilla.org/APNG_Specification#%60acTL%60:_The_Animation_Control_Chunk + if (size != 8 + 8 + 4) + return 0; + } else if (id == id_fcTL) { + // 8=HDR+size, 26=size of fcTL chunk, 4=CRC + // https://wiki.mozilla.org/APNG_Specification#%60fcTL%60:_The_Frame_Control_Chunk + if (size != 8 + 26 + 4) + return 0; + } else if (id == id_bKGD) { + // 8=HDR+size, (1, 2 or 6)=size of bKGD chunk, 4=CRC + // The spec is actually more complex: + // http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html#C.bKGD + if (size != 8 + 1 + 4 && size != 8 + 2 + 4 && size != 8 + 6 + 4) + return 0; + } else if (id != id_fdAT && id != id_IDAT && id != id_IEND && id != id_PLTE && id != id_tEXt && id != id_tRNS) { if (size > PNG_USER_CHUNK_MALLOC_MAX) { - CV_LOG_WARNING(NULL, "chunk data is too large"); + CV_LOG_WARNING(NULL, "user chunk data is too large"); return 0; } - chunk.p.resize(size); - memcpy(chunk.p.data(), len, 4); - if (read_from_io(&chunk.p[4], chunk.p.size() - 4)) - return *(uint32_t*)(&chunk.p[4]); } + + chunk.p.resize(size); + memcpy(chunk.p.data(), size_id, 8); + if (readFromStreamOrBuffer(&chunk.p[8], chunk.p.size() - 8)) + return id; return 0; } bool PngDecoder::processing_start(void* frame_ptr, const Mat& img) { + if (!InitPngPtr()) + return false; + + if (setjmp(png_jmpbuf(m_png_ptr))) + return false; + static uint8_t header[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; - PngPtrs png_ptrs; - png_structp png_ptr = png_ptrs.getPng(); - png_infop info_ptr = png_ptrs.getInfo(); - - if (!png_ptr || !info_ptr) { - return false; - } - - if (setjmp(png_jmpbuf(png_ptr))) - { - return false; - } - - m_png_ptrs = std::move(png_ptrs); - png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); - png_set_progressive_read_fn(png_ptr, frame_ptr, (png_progressive_info_ptr)info_fn, row_fn, NULL); + png_set_crc_action(m_png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); + png_set_progressive_read_fn(m_png_ptr, frame_ptr, (png_progressive_info_ptr)info_fn, row_fn, NULL); if (img.channels() < 4) - png_set_strip_alpha(png_ptr); + png_set_strip_alpha(m_png_ptr); else - png_set_tRNS_to_alpha(png_ptr); + png_set_tRNS_to_alpha(m_png_ptr); - png_process_data(png_ptr, info_ptr, header, 8); - png_process_data(png_ptr, info_ptr, m_chunkIHDR.p.data(), m_chunkIHDR.p.size()); + png_process_data(m_png_ptr, m_info_ptr, header, 8); + png_process_data(m_png_ptr, m_info_ptr, m_chunkIHDR.p.data(), m_chunkIHDR.p.size()); if ((m_color_type & PNG_COLOR_MASK_COLOR) && img.channels() > 1 && !m_use_rgb) - png_set_bgr(png_ptr); // convert RGB to BGR + png_set_bgr(m_png_ptr); // convert RGB to BGR else if (img.channels() > 1) - png_set_gray_to_rgb(png_ptr); // Gray->RGB + png_set_gray_to_rgb(m_png_ptr); // Gray->RGB else - png_set_rgb_to_gray(png_ptr, 1, 0.299, 0.587); // RGB->Gray + png_set_rgb_to_gray(m_png_ptr, 1, 0.299, 0.587); // RGB->Gray for (size_t i = 0; i < m_chunksInfo.size(); i++) - png_process_data(png_ptr, info_ptr, m_chunksInfo[i].p.data(), m_chunksInfo[i].p.size()); + png_process_data(m_png_ptr, m_info_ptr, m_chunksInfo[i].p.data(), m_chunksInfo[i].p.size()); return true; } @@ -763,22 +774,17 @@ bool PngDecoder::processing_finish() { static uint8_t footer[12] = { 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130 }; - png_structp png_ptr = m_png_ptrs.getPng(); - png_infop info_ptr = m_png_ptrs.getInfo(); - - if (!png_ptr) { - m_png_ptrs.clear(); + if (!m_png_ptr) { return false; } - if (setjmp(png_jmpbuf(png_ptr))) + if (setjmp(png_jmpbuf(m_png_ptr))) { - m_png_ptrs.clear(); return false; } - png_process_data(png_ptr, info_ptr, footer, 12); - m_png_ptrs.clear(); + png_process_data(m_png_ptr, m_info_ptr, footer, 12); + ClearPngPtr(); return true; } @@ -948,15 +954,24 @@ bool PngEncoder::write( const Mat& img, const std::vector& params ) return result; } -size_t PngEncoder::write_to_io(void const* _Buffer, size_t _ElementSize, size_t _ElementCount, FILE * _Stream) +size_t PngEncoder::writeToStreamOrBuffer(void const* buffer, size_t num_bytes, FILE* stream) { - if (_Stream) - return fwrite(_Buffer, _ElementSize, _ElementCount, _Stream); + if (!buffer || !num_bytes) + return 0; // Handle null buffer or empty writes + + if (stream) + { + size_t written = fwrite(buffer, 1, num_bytes, stream); + return written; // fwrite handles the write count + } size_t cursz = m_buf->size(); - m_buf->resize(cursz + _ElementCount); - memcpy( &(*m_buf)[cursz], _Buffer, _ElementCount ); - return _ElementCount; + if (cursz + num_bytes > m_buf->max_size()) + throw std::runtime_error("Buffer size exceeds maximum capacity"); + + m_buf->resize(cursz + num_bytes); + memcpy(&(*m_buf)[cursz], buffer, num_bytes); + return num_bytes; } void PngEncoder::writeChunk(FILE* f, const char* name, unsigned char* data, uint32_t length) @@ -965,26 +980,26 @@ void PngEncoder::writeChunk(FILE* f, const char* name, unsigned char* data, uint uint32_t crc = crc32(0, Z_NULL, 0); png_save_uint_32(buf, length); - write_to_io(buf, 1, 4, f); - write_to_io(name, 1, 4, f); + writeToStreamOrBuffer(buf, 4, f); + writeToStreamOrBuffer(name, 4, f); crc = crc32(crc, (const Bytef*)name, 4); if (memcmp(name, "fdAT", 4) == 0) { png_save_uint_32(buf, next_seq_num++); - write_to_io(buf, 1, 4, f); + writeToStreamOrBuffer(buf, 4, f); crc = crc32(crc, buf, 4); length -= 4; } if (data != NULL && length > 0) { - write_to_io(data, 1, length, f); + writeToStreamOrBuffer(data, length, f); crc = crc32(crc, data, length); } png_save_uint_32(buf, crc); - write_to_io(buf, 1, 4, f); + writeToStreamOrBuffer(buf, 4, f); } void PngEncoder::writeIDATs(FILE* f, int frame, unsigned char* data, uint32_t length, uint32_t idat_size) @@ -1397,6 +1412,9 @@ void PngEncoder::deflateRectFin(unsigned char* zbuf, uint32_t* zsize, int bpp, i bool PngEncoder::writeanimation(const Animation& animation, const std::vector& params) { + int frame_type = animation.frames[0].type(); + int frame_depth = animation.frames[0].depth(); + CV_CheckType(frame_type, frame_depth == CV_8U || frame_depth == CV_16U, "APNG decoder supports only 8 or 16 bit unsigned images"); int compression_level = 6; int compression_strategy = IMWRITE_PNG_STRATEGY_RLE; // Default strategy bool isBilevel = false; @@ -1420,7 +1438,8 @@ bool PngEncoder::writeanimation(const Animation& animation, const std::vector 0) writeChunk(m_f, "PLTE", (unsigned char*)(&palette), palsize * 3); - if ((animation.bgcolor != Scalar()) && (animation.frames.size() > 1)) + if ((animation.bgcolor != Scalar()) && coltype) { - uint64_t bgvalue = (static_cast(animation.bgcolor[0]) & 0xFF) << 24 | - (static_cast(animation.bgcolor[1]) & 0xFF) << 16 | - (static_cast(animation.bgcolor[2]) & 0xFF) << 8 | - (static_cast(animation.bgcolor[3]) & 0xFF); - writeChunk(m_f, "bKGD", (unsigned char*)(&bgvalue), 6); //the bKGD chunk must precede the first IDAT chunk, and must follow the PLTE chunk. + unsigned char bgvalue[6] = {}; + bgvalue[1] = animation.bgcolor[2]; + bgvalue[3] = animation.bgcolor[1]; + bgvalue[5] = animation.bgcolor[0]; + writeChunk(m_f, "bKGD", bgvalue, 6); //the bKGD chunk must precede the first IDAT chunk, and must follow the PLTE chunk. } if (trnssize > 0) diff --git a/modules/imgcodecs/src/grfmt_png.hpp b/modules/imgcodecs/src/grfmt_png.hpp index dec2cd0b61..6e1a06473d 100644 --- a/modules/imgcodecs/src/grfmt_png.hpp +++ b/modules/imgcodecs/src/grfmt_png.hpp @@ -130,56 +130,27 @@ public: ImageDecoder newDecoder() const CV_OVERRIDE; -protected: +private: static void readDataFromBuf(void* png_ptr, uchar* dst, size_t size); static void info_fn(png_structp png_ptr, png_infop info_ptr); static void row_fn(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass); - bool processing_start(void* frame_ptr, const Mat& img); - bool processing_finish(); + CV_NODISCARD_STD bool processing_start(void* frame_ptr, const Mat& img); + CV_NODISCARD_STD bool processing_finish(); void compose_frame(std::vector& rows_dst, const std::vector& rows_src, unsigned char bop, uint32_t x, uint32_t y, uint32_t w, uint32_t h, Mat& img); - bool read_from_io(void* buffer, size_t num_bytes); + /** + * @brief Reads data from an I/O source into the provided buffer. + * @param buffer Pointer to the buffer where the data will be stored. + * @param num_bytes Number of bytes to read into the buffer. + * @return true if the operation is successful, false otherwise. + */ + CV_NODISCARD_STD bool readFromStreamOrBuffer(void* buffer, size_t num_bytes); uint32_t read_chunk(Chunk& chunk); + CV_NODISCARD_STD bool InitPngPtr(); + void ClearPngPtr(); - struct PngPtrs { - public: - PngPtrs() { - png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); - if (png_ptr) { - info_ptr = png_create_info_struct( png_ptr ); - end_info = png_create_info_struct( png_ptr ); - } else { - info_ptr = end_info = nullptr; - } - } - ~PngPtrs() { - clear(); - } - PngPtrs& operator=(PngPtrs&& other) { - clear(); - png_ptr = other.png_ptr; - info_ptr = other.info_ptr; - end_info = other.end_info; - other.png_ptr = nullptr; - other.info_ptr = other.end_info = nullptr; - return *this; - } - void clear() { - if (png_ptr) { - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - png_ptr = nullptr; - info_ptr = end_info = nullptr; - } - } - png_structp getPng() const { return png_ptr; } - png_infop getInfo() const { return info_ptr; } - png_infop getEndInfo() const { return end_info; } - private: - png_structp png_ptr; // pointer to decompression structure - png_infop info_ptr; // pointer to image information structure - png_infop end_info; // pointer to one more image information structure - }; - - PngPtrs m_png_ptrs; + png_structp m_png_ptr = nullptr; // pointer to decompression structure + png_infop m_info_ptr = nullptr; // pointer to image information structure + png_infop m_end_info = nullptr; // pointer to one more image information structure int m_bit_depth; FILE* m_f; int m_color_type; @@ -220,7 +191,24 @@ public: protected: static void writeDataToBuf(void* png_ptr, unsigned char* src, size_t size); static void flushBuf(void* png_ptr); - size_t write_to_io(void const* _Buffer, size_t _ElementSize, size_t _ElementCount, FILE* _Stream); + /** + * @brief Writes data to an output destination, either a file stream or an in-memory buffer. + * + * This function handles two output scenarios: + * 1. If a file stream is provided, the data is written to the stream using `fwrite`. + * 2. If `stream` is null, the data is written to an in-memory buffer (`m_buf`), which is resized as needed. + * + * @param buffer Pointer to the data to be written. + * @param num_bytes The number of bytes to be written. + * @param stream Pointer to the file stream for writing. If null, the data is written to the in-memory buffer. + * @return The number of bytes successfully written. + * - For file-based writes, this is the number of bytes written to the stream. + * - For buffer-based writes, this is the total number of bytes added to the buffer. + * + * @throws std::runtime_error If the in-memory buffer (`m_buf`) exceeds its maximum capacity. + * @note If `num_bytes` is 0 or `buffer` is null, the function returns 0. + */ + size_t writeToStreamOrBuffer(void const* buffer, size_t num_bytes, FILE* stream); private: void writeChunk(FILE* f, const char* name, unsigned char* data, uint32_t length); diff --git a/modules/imgcodecs/src/loadsave.cpp b/modules/imgcodecs/src/loadsave.cpp index 6b110303b8..6094f0fbc8 100644 --- a/modules/imgcodecs/src/loadsave.cpp +++ b/modules/imgcodecs/src/loadsave.cpp @@ -83,6 +83,13 @@ static Size validateInputImageSize(const Size& size) static inline int calcType(int type, int flags) { + if(flags != IMREAD_UNCHANGED) + { + CV_CheckNE(flags & (IMREAD_COLOR_BGR | IMREAD_COLOR_RGB), + IMREAD_COLOR_BGR | IMREAD_COLOR_RGB, + "IMREAD_COLOR_BGR (IMREAD_COLOR) and IMREAD_COLOR_RGB can not be set at the same time."); + } + if ( (flags & (IMREAD_COLOR | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH)) == (IMREAD_COLOR | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH)) return type; @@ -1335,7 +1342,7 @@ bool imencode( const String& ext, InputArray _img, else code = encoder->writemulti(write_vec, params); - encoder->throwOnEror(); + encoder->throwOnError(); CV_Assert( code ); } catch (const cv::Exception& e) diff --git a/modules/imgcodecs/test/test_animation.cpp b/modules/imgcodecs/test/test_animation.cpp index e8c42cbcc0..df0a00a8b1 100644 --- a/modules/imgcodecs/test/test_animation.cpp +++ b/modules/imgcodecs/test/test_animation.cpp @@ -425,6 +425,39 @@ TEST(Imgcodecs_APNG, imwriteanimation_rgb) EXPECT_EQ(0, remove(output.c_str())); } +TEST(Imgcodecs_APNG, imwriteanimation_gray) +{ + Animation s_animation, l_animation; + EXPECT_TRUE(fillFrames(s_animation, false)); + + for (size_t i = 0; i < s_animation.frames.size(); i++) + { + cvtColor(s_animation.frames[i], s_animation.frames[i], COLOR_BGR2GRAY); + } + + s_animation.bgcolor = Scalar(50, 100, 150); + string output = cv::tempfile(".png"); + // Write the animation to a .png file and verify success. + EXPECT_TRUE(imwriteanimation(output, s_animation)); + + // Read the animation back and compare with the original. + EXPECT_TRUE(imreadanimation(output, l_animation)); + + EXPECT_EQ(Scalar(), l_animation.bgcolor); + size_t expected_frame_count = s_animation.frames.size() - 2; + + // Verify that the number of frames matches the expected count. + EXPECT_EQ(expected_frame_count, imcount(output)); + EXPECT_EQ(expected_frame_count, l_animation.frames.size()); + + EXPECT_EQ(0, remove(output.c_str())); + + for (size_t i = 0; i < l_animation.frames.size(); i++) + { + EXPECT_EQ(0, cvtest::norm(s_animation.frames[i], l_animation.frames[i], NORM_INF)); + } +} + TEST(Imgcodecs_APNG, imwritemulti_rgba) { Animation s_animation; @@ -492,7 +525,7 @@ TEST(Imgcodecs_APNG, imwriteanimation_bgcolor) { Animation s_animation, l_animation; EXPECT_TRUE(fillFrames(s_animation, true, 2)); - s_animation.bgcolor = Scalar(50, 100, 150, 128); // different values for test purpose. + s_animation.bgcolor = Scalar(50, 100, 150); // will be written in bKGD chunk as RGB. // Create a temporary output filename for saving the animation. string output = cv::tempfile(".png"); diff --git a/modules/imgcodecs/test/test_gif.cpp b/modules/imgcodecs/test/test_gif.cpp index b9c49c0bdb..50d0be6c3a 100644 --- a/modules/imgcodecs/test/test_gif.cpp +++ b/modules/imgcodecs/test/test_gif.cpp @@ -241,17 +241,17 @@ TEST(Imgcodecs_Gif, read_gif_special){ const string gif_filename2 = root + "gifsuite/special2.gif"; const string png_filename2 = root + "gifsuite/special2.png"; cv::Mat gif_img1; - ASSERT_NO_THROW(gif_img1 = cv::imread(gif_filename1,IMREAD_UNCHANGED)); + ASSERT_NO_THROW(gif_img1 = cv::imread(gif_filename1,IMREAD_COLOR)); ASSERT_FALSE(gif_img1.empty()); cv::Mat png_img1; - ASSERT_NO_THROW(png_img1 = cv::imread(png_filename1,IMREAD_UNCHANGED)); + ASSERT_NO_THROW(png_img1 = cv::imread(png_filename1,IMREAD_COLOR)); ASSERT_FALSE(png_img1.empty()); EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), gif_img1, png_img1); cv::Mat gif_img2; - ASSERT_NO_THROW(gif_img2 = cv::imread(gif_filename2,IMREAD_UNCHANGED)); + ASSERT_NO_THROW(gif_img2 = cv::imread(gif_filename2,IMREAD_COLOR)); ASSERT_FALSE(gif_img2.empty()); cv::Mat png_img2; - ASSERT_NO_THROW(png_img2 = cv::imread(png_filename2,IMREAD_UNCHANGED)); + ASSERT_NO_THROW(png_img2 = cv::imread(png_filename2,IMREAD_COLOR)); ASSERT_FALSE(png_img2.empty()); EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), gif_img2, png_img2); } @@ -351,6 +351,21 @@ TEST(Imgcodecs_Gif, write_gif_multi) { EXPECT_EQ(0, remove(gif_filename.c_str())); } +TEST(Imgcodecs_Gif, encode_IMREAD_GRAYSCALE) { + cv::Mat src; + cv::Mat decoded; + vector buf; + vector param; + bool ret = false; + + src = cv::Mat(240,240,CV_8UC3,cv::Scalar(128,64,32)); + EXPECT_NO_THROW(ret = imencode(".gif", src, buf, param)); + EXPECT_TRUE(ret); + EXPECT_NO_THROW(decoded = imdecode(buf, cv::IMREAD_GRAYSCALE)); + EXPECT_FALSE(decoded.empty()); + EXPECT_EQ(decoded.channels(), 1); +} + }//opencv_test }//namespace diff --git a/modules/imgcodecs/test/test_grfmt.cpp b/modules/imgcodecs/test/test_grfmt.cpp index 996ad4a6be..201dac2414 100644 --- a/modules/imgcodecs/test/test_grfmt.cpp +++ b/modules/imgcodecs/test/test_grfmt.cpp @@ -164,6 +164,8 @@ TEST_P(Imgcodecs_ExtSize, write_imageseq) continue; if (cn != 3 && ext == ".ppm") continue; + if (cn == 1 && ext == ".gif") + continue; string filename = cv::tempfile(format("%d%s", cn, ext.c_str()).c_str()); Mat img_gt(size, CV_MAKETYPE(CV_8U, cn), Scalar::all(0)); @@ -179,8 +181,14 @@ TEST_P(Imgcodecs_ExtSize, write_imageseq) ASSERT_TRUE(imwrite(filename, img_gt, parameters)); Mat img = imread(filename, IMREAD_UNCHANGED); ASSERT_FALSE(img.empty()); - EXPECT_EQ(img.size(), img.size()); - EXPECT_EQ(img.type(), img.type()); + EXPECT_EQ(img_gt.size(), img.size()); + EXPECT_EQ(img_gt.channels(), img.channels()); + if (ext == ".pfm") { + EXPECT_EQ(img_gt.depth(), CV_8U); + EXPECT_EQ(img.depth(), CV_32F); + } else { + EXPECT_EQ(img_gt.depth(), img.depth()); + } EXPECT_EQ(cn, img.channels()); @@ -200,6 +208,14 @@ TEST_P(Imgcodecs_ExtSize, write_imageseq) EXPECT_LT(n, 1.); EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), img, img_gt); } + else if (ext == ".gif") + { + // GIF encoder will reduce the number of colors to 256. + // It is hard to compare image comparison by pixel unit. + double n = cvtest::norm(img, img_gt, NORM_L1); + double expected = 0.03 * img.size().area(); + EXPECT_LT(n, expected); + } else { double n = cvtest::norm(img, img_gt, NORM_L2); @@ -238,6 +254,9 @@ const string all_exts[] = #ifdef HAVE_IMGCODEC_PFM ".pfm", #endif +#ifdef HAVE_IMGCODEC_GIF + ".gif", +#endif }; vector all_sizes() diff --git a/modules/imgcodecs/test/test_jpegxl.cpp b/modules/imgcodecs/test/test_jpegxl.cpp index 6c5aad181f..d43b625364 100644 --- a/modules/imgcodecs/test/test_jpegxl.cpp +++ b/modules/imgcodecs/test/test_jpegxl.cpp @@ -180,6 +180,132 @@ TEST(Imgcodecs_JpegXL, encode_from_uncontinued_image) EXPECT_TRUE(ret); } +// See https://github.com/opencv/opencv/issues/26767 + +typedef tuple MatType_and_ImreadFlag; +typedef testing::TestWithParam Imgcodecs_JpegXL_MatType_ImreadFlag; + +TEST_P(Imgcodecs_JpegXL_MatType_ImreadFlag, all_imreadFlags) +{ + string tmp_fname = cv::tempfile(".jxl"); + const int matType = get<0>(GetParam()); + const int imreadFlag = get<1>(GetParam()); + + Mat img(240, 320, matType); + randu(img, Scalar(0, 0, 0, 255), Scalar(255, 255, 255, 255)); + + vector param; + param.push_back(IMWRITE_JPEGXL_DISTANCE); + param.push_back(0 /* Lossless */); + EXPECT_NO_THROW(imwrite(tmp_fname, img, param)); + + Mat img_decoded; + EXPECT_NO_THROW(img_decoded = imread(tmp_fname, imreadFlag)); + EXPECT_FALSE(img_decoded.empty()); + + switch( imreadFlag ) + { + case IMREAD_UNCHANGED: + EXPECT_EQ( img.type(), img_decoded.type() ); + break; + case IMREAD_GRAYSCALE: + EXPECT_EQ( img_decoded.depth(), CV_8U ); + EXPECT_EQ( img_decoded.channels(), 1 ); + break; + case IMREAD_COLOR: + case IMREAD_COLOR_RGB: + EXPECT_EQ( img_decoded.depth(), CV_8U ); + EXPECT_EQ( img_decoded.channels(), 3 ); + break; + case IMREAD_ANYDEPTH: + EXPECT_EQ( img_decoded.depth(), img.depth() ); + EXPECT_EQ( img_decoded.channels(), 1 ); + break; + case IMREAD_ANYCOLOR: + EXPECT_EQ( img_decoded.depth(), CV_8U ) ; + EXPECT_EQ( img_decoded.channels(), img.channels() == 1 ? 1 : 3 ); // Alpha channel will be dropped. + break; + } + remove(tmp_fname.c_str()); +} + +INSTANTIATE_TEST_CASE_P( + /**/, + Imgcodecs_JpegXL_MatType_ImreadFlag, + testing::Combine( + testing::Values( + CV_8UC1, CV_8UC3, CV_8UC4, + CV_16UC1, CV_16UC3, CV_16UC4, + CV_32FC1, CV_32FC3, CV_32FC4 + ), + testing::Values( + IMREAD_UNCHANGED, + IMREAD_GRAYSCALE, + IMREAD_COLOR, + IMREAD_COLOR_RGB, + IMREAD_ANYDEPTH, + IMREAD_ANYCOLOR + ) +) ); + +TEST(Imgcodecs_JpegXL, imdecode_truncated_stream) +{ + cv::Mat src(100, 100, CV_8UC1, Scalar(40,50,10)); + vector buff; + vector param; + + bool ret = false; + EXPECT_NO_THROW(ret = cv::imencode(".jxl", src, buff, param)); + EXPECT_TRUE(ret); + + // Try to decode non-truncated image. + cv::Mat decoded; + EXPECT_NO_THROW(decoded = cv::imdecode(buff, cv::IMREAD_COLOR)); + EXPECT_FALSE(decoded.empty()); + + // Try to decode truncated image. + buff.resize(buff.size() - 1 ); + EXPECT_NO_THROW(decoded = cv::imdecode(buff, cv::IMREAD_COLOR)); + EXPECT_TRUE(decoded.empty()); +} + +TEST(Imgcodecs_JpegXL, imread_truncated_stream) +{ + string tmp_fname = cv::tempfile(".jxl"); + cv::Mat src(100, 100, CV_8UC1, Scalar(40,50,10)); + vector buff; + vector param; + + bool ret = false; + EXPECT_NO_THROW(ret = cv::imencode(".jxl", src, buff, param)); + EXPECT_TRUE(ret); + + // Try to decode non-truncated image. + FILE *fp = nullptr; + + fp = fopen(tmp_fname.c_str(), "wb"); + EXPECT_TRUE(fp != nullptr); + fwrite(&buff[0], sizeof(uint8_t), buff.size(), fp); + fclose(fp); + + cv::Mat decoded; + EXPECT_NO_THROW(decoded = cv::imread(tmp_fname, cv::IMREAD_COLOR)); + EXPECT_FALSE(decoded.empty()); + + // Try to decode truncated image. + fp = fopen(tmp_fname.c_str(), "wb"); + EXPECT_TRUE(fp != nullptr); + fwrite(&buff[0], sizeof(uint8_t), buff.size() - 1, fp); + fclose(fp); + + EXPECT_NO_THROW(decoded = cv::imread(tmp_fname, cv::IMREAD_COLOR)); + EXPECT_TRUE(decoded.empty()); + + // Delete temporary file + remove(tmp_fname.c_str()); +} + + #endif // HAVE_JPEGXL } // namespace diff --git a/modules/imgcodecs/test/test_precomp.hpp b/modules/imgcodecs/test/test_precomp.hpp index f5fb5c82e4..d2095932e8 100644 --- a/modules/imgcodecs/test/test_precomp.hpp +++ b/modules/imgcodecs/test/test_precomp.hpp @@ -25,6 +25,16 @@ void PrintTo(const ImreadModes& val, std::ostream* os) v &= ~IMREAD_COLOR; *os << "IMREAD_COLOR" << (v == 0 ? "" : " | "); } + else if ((v & IMREAD_COLOR_RGB) != 0) + { + CV_Assert(IMREAD_COLOR_RGB == 256); + v &= ~IMREAD_COLOR_RGB; + *os << "IMREAD_COLOR_RGB" << (v == 0 ? "" : " | "); + } + else if ((v & IMREAD_ANYCOLOR) != 0) + { + // Do nothing + } else { CV_Assert(IMREAD_GRAYSCALE == 0); @@ -50,11 +60,6 @@ void PrintTo(const ImreadModes& val, std::ostream* os) v &= ~IMREAD_IGNORE_ORIENTATION; *os << "IMREAD_IGNORE_ORIENTATION" << (v == 0 ? "" : " | "); } - if ((v & IMREAD_COLOR_RGB) != 0) - { - v &= ~IMREAD_COLOR_RGB; - *os << "IMREAD_COLOR_RGB" << (v == 0 ? "" : " | "); - } switch (v) { case IMREAD_UNCHANGED: return; diff --git a/modules/imgcodecs/test/test_tiff.cpp b/modules/imgcodecs/test/test_tiff.cpp index 81832d0170..aae7ecf684 100644 --- a/modules/imgcodecs/test/test_tiff.cpp +++ b/modules/imgcodecs/test/test_tiff.cpp @@ -46,41 +46,18 @@ TEST(Imgcodecs_Tiff, decode_tile16384x16384) //================================================================================================== // See https://github.com/opencv/opencv/issues/22388 -/** - * Dummy enum to show combination of IMREAD_*. - */ -enum ImreadMixModes -{ - IMREAD_MIX_UNCHANGED = IMREAD_UNCHANGED , - IMREAD_MIX_GRAYSCALE = IMREAD_GRAYSCALE , - IMREAD_MIX_COLOR = IMREAD_COLOR | IMREAD_COLOR_RGB , - IMREAD_MIX_GRAYSCALE_ANYDEPTH = IMREAD_GRAYSCALE | IMREAD_ANYDEPTH , - IMREAD_MIX_GRAYSCALE_ANYCOLOR = IMREAD_GRAYSCALE | IMREAD_ANYCOLOR, - IMREAD_MIX_GRAYSCALE_ANYDEPTH_ANYCOLOR = IMREAD_GRAYSCALE | IMREAD_ANYDEPTH | IMREAD_ANYCOLOR, - IMREAD_MIX_COLOR_ANYDEPTH = IMREAD_COLOR | IMREAD_ANYDEPTH , - IMREAD_MIX_COLOR_ANYCOLOR = IMREAD_COLOR | IMREAD_ANYCOLOR, - IMREAD_MIX_COLOR_ANYDEPTH_ANYCOLOR = IMREAD_COLOR | IMREAD_ANYDEPTH | IMREAD_ANYCOLOR -}; - -typedef tuple< uint64_t, tuple, ImreadMixModes > Bufsize_and_Type; +typedef tuple< uint64_t, perf::MatType, ImreadModes > Bufsize_and_Type; typedef testing::TestWithParam Imgcodecs_Tiff_decode_Huge; -static inline -void PrintTo(const ImreadMixModes& val, std::ostream* os) -{ - PrintTo( static_cast(val), os ); -} - TEST_P(Imgcodecs_Tiff_decode_Huge, regression) { // Get test parameters const uint64_t buffer_size = get<0>(GetParam()); - const string mat_type_string = get<0>(get<1>(GetParam())); - const int mat_type = get<1>(get<1>(GetParam())); + const perf::MatType mat_type = get<1>(GetParam()); const int imread_mode = get<2>(GetParam()); // Detect data file - const string req_filename = cv::format("readwrite/huge-tiff/%s_%zu.tif", mat_type_string.c_str(), (size_t)buffer_size); + const string req_filename = cv::format("readwrite/huge-tiff/%s_%zu.tif", typeToString(mat_type).c_str(), (size_t)buffer_size); const string filename = findDataFile( req_filename ); // Preparation process for test @@ -125,7 +102,7 @@ TEST_P(Imgcodecs_Tiff_decode_Huge, regression) case IMREAD_GRAYSCALE | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH: ncn = (ncn == 1)?1:3; break; - case IMREAD_COLOR | IMREAD_COLOR_RGB: + case IMREAD_COLOR: ncn = 3; depth = 1; break; @@ -402,9 +379,9 @@ TEST_P(Imgcodecs_Tiff_decode_Huge, regression) case MAKE_FLAG(CV_16UC1, CV_16UC4): case MAKE_FLAG(CV_16UC3, CV_16UC4): default: - FAIL() << cv::format("Unknown test pattern: from = %d ( %d, %d) to = %d ( %d, %d )", - mat_type, (int)CV_MAT_CN(mat_type ), ( CV_MAT_DEPTH(mat_type )==CV_16U)?16:8, - img.type(), (int)CV_MAT_CN(img.type() ), ( CV_MAT_DEPTH(img.type() )==CV_16U)?16:8); + FAIL() << cv::format("Unknown test pattern: from = ( %d, %d) to = ( %d, %d )", + (int)CV_MAT_CN(mat_type ), ( CV_MAT_DEPTH(mat_type )==CV_16U)?16:8, + (int)CV_MAT_CN(img.type() ), ( CV_MAT_DEPTH(img.type() )==CV_16U)?16:8); break; } @@ -414,8 +391,8 @@ TEST_P(Imgcodecs_Tiff_decode_Huge, regression) // Basic Test const Bufsize_and_Type Imgcodecs_Tiff_decode_Huge_list_basic[] = { - make_tuple,ImreadMixModes>( 1073479680ull, make_tuple("CV_8UC1", CV_8UC1), IMREAD_MIX_COLOR ), - make_tuple,ImreadMixModes>( 2147483648ull, make_tuple("CV_16UC4", CV_16UC4), IMREAD_MIX_COLOR ), + make_tuple( 1073479680ull, CV_8UC1, IMREAD_COLOR ), + make_tuple( 2147483648ull, CV_16UC4, IMREAD_COLOR ), }; INSTANTIATE_TEST_CASE_P(Imgcodecs_Tiff, Imgcodecs_Tiff_decode_Huge, @@ -423,21 +400,25 @@ INSTANTIATE_TEST_CASE_P(Imgcodecs_Tiff, Imgcodecs_Tiff_decode_Huge, ); // Full Test +// This full test is disabled in default, following steps are required to run. +// (1) replace "DISABLED_Imgcodecs_Tiff_Full" to "Imgcodecs_Tiff_Full" and rebuild opencv_test_imgcodecs. +// (2) set "OPENCV_IO_MAX_IMAGE_PIXELS=2147483648" in environment variable. +// (3) run "./bin/opencv_test_imgcodecs --test_tag_enable=mem_6gb,verylong,debug_verylong" . /** * Test lists for combination of IMREAD_*. */ -const ImreadMixModes all_modes_Huge_Full[] = +const ImreadModes all_modes_Huge_Full[] = { - IMREAD_MIX_UNCHANGED, - IMREAD_MIX_GRAYSCALE, - IMREAD_MIX_GRAYSCALE_ANYDEPTH, - IMREAD_MIX_GRAYSCALE_ANYCOLOR, - IMREAD_MIX_GRAYSCALE_ANYDEPTH_ANYCOLOR, - IMREAD_MIX_COLOR, - IMREAD_MIX_COLOR_ANYDEPTH, - IMREAD_MIX_COLOR_ANYCOLOR, - IMREAD_MIX_COLOR_ANYDEPTH_ANYCOLOR, + static_cast(IMREAD_UNCHANGED ) , + static_cast(IMREAD_GRAYSCALE ) , + static_cast(IMREAD_COLOR ) , + static_cast(IMREAD_GRAYSCALE | IMREAD_ANYDEPTH ) , + static_cast(IMREAD_GRAYSCALE | IMREAD_ANYCOLOR) , + static_cast(IMREAD_GRAYSCALE | IMREAD_ANYDEPTH | IMREAD_ANYCOLOR) , + static_cast(IMREAD_COLOR | IMREAD_ANYDEPTH ) , + static_cast(IMREAD_COLOR | IMREAD_ANYCOLOR) , + static_cast(IMREAD_COLOR | IMREAD_ANYDEPTH | IMREAD_ANYCOLOR) }; const uint64_t huge_buffer_sizes_decode_Full[] = @@ -448,16 +429,17 @@ const uint64_t huge_buffer_sizes_decode_Full[] = 2147483648ull, // 2048 * 1024 * 1024 }; -const tuple mat_types_Full[] = +const perf::MatType mat_types_Full[] = { - make_tuple("CV_8UC1", CV_8UC1), // 8bit GRAY - make_tuple("CV_8UC3", CV_8UC3), // 24bit RGB - make_tuple("CV_8UC4", CV_8UC4), // 32bit RGBA - make_tuple("CV_16UC1", CV_16UC1), // 16bit GRAY - make_tuple("CV_16UC3", CV_16UC3), // 48bit RGB - make_tuple("CV_16UC4", CV_16UC4), // 64bit RGBA + CV_8UC1, // 8bit GRAY + CV_8UC3, // 24bit RGB + CV_8UC4, // 32bit RGBA + CV_16UC1, // 16bit GRAY + CV_16UC3, // 48bit RGB + CV_16UC4, // 64bit RGBA }; +// INSTANTIATE_TEST_CASE_P(Imgcodecs_Tiff_Full, Imgcodecs_Tiff_decode_Huge, INSTANTIATE_TEST_CASE_P(DISABLED_Imgcodecs_Tiff_Full, Imgcodecs_Tiff_decode_Huge, testing::Combine( testing::ValuesIn(huge_buffer_sizes_decode_Full), diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index efb5dea7cf..8289863971 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -324,7 +324,8 @@ enum ThresholdTypes { THRESH_TOZERO_INV = 4, //!< \f[\texttt{dst} (x,y) = \fork{0}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{src}(x,y)}{otherwise}\f] THRESH_MASK = 7, THRESH_OTSU = 8, //!< flag, use Otsu algorithm to choose the optimal threshold value - THRESH_TRIANGLE = 16 //!< flag, use Triangle algorithm to choose the optimal threshold value + THRESH_TRIANGLE = 16, //!< flag, use Triangle algorithm to choose the optimal threshold value + THRESH_DRYRUN = 128 //!< flag, compute threshold only (useful for OTSU/TRIANGLE) but does not actually run thresholding }; //! adaptive threshold algorithm @@ -3870,7 +3871,7 @@ is \f$W \times H\f$ and templ is \f$w \times h\f$ , then result is \f$(W-w+1) \t of channels as template or only one channel, which is then used for all template and image channels. If the data type is #CV_8U, the mask is interpreted as a binary mask, meaning only elements where mask is nonzero are used and are kept unchanged independent - of the actual mask value (weight equals 1). For data tpye #CV_32F, the mask values are + of the actual mask value (weight equals 1). For data type #CV_32F, the mask values are used as weights. The exact formulas are documented in #TemplateMatchModes. */ CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ, @@ -4813,6 +4814,11 @@ The function cv::putText renders the specified text string in the image. Symbols using the specified font are replaced by question marks. See #getTextSize for a text rendering code example. +The `fontScale` parameter is a scale factor that is multiplied by the base font size: +- When scale > 1, the text is magnified. +- When 0 < scale < 1, the text is minimized. +- When scale < 0, the text is mirrored or reversed. + @param img Image. @param text Text string to be drawn. @param org Bottom-left corner of the text string in the image. diff --git a/modules/imgproc/src/box_filter.dispatch.cpp b/modules/imgproc/src/box_filter.dispatch.cpp index 55ac5c65bd..ba90adee1d 100644 --- a/modules/imgproc/src/box_filter.dispatch.cpp +++ b/modules/imgproc/src/box_filter.dispatch.cpp @@ -313,7 +313,6 @@ Ptr createBoxFilter(int srcType, int dstType, Size ksize, CV_CPU_DISPATCH_MODES_ALL); } - #if 0 //defined(HAVE_IPP) static bool ipp_boxfilter(Mat &src, Mat &dst, Size ksize, Point anchor, bool normalize, int borderType) { diff --git a/modules/imgproc/src/deriv.cpp b/modules/imgproc/src/deriv.cpp index dbc2c0815a..0760d224ab 100644 --- a/modules/imgproc/src/deriv.cpp +++ b/modules/imgproc/src/deriv.cpp @@ -378,7 +378,6 @@ void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, CALL_HAL(sobel, cv_hal_sobel, src.ptr(), src.step, dst.ptr(), dst.step, src.cols, src.rows, sdepth, ddepth, cn, ofs.x, ofs.y, wsz.width - src.cols - ofs.x, wsz.height - src.rows - ofs.y, dx, dy, ksize, scale, delta, borderType&~BORDER_ISOLATED); - //CV_IPP_RUN_FAST(ipp_Deriv(src, dst, dx, dy, ksize, scale, delta, borderType)); sepFilter2D(src, dst, ddepth, kx, ky, Point(-1, -1), delta, borderType ); diff --git a/modules/imgproc/src/filter.dispatch.cpp b/modules/imgproc/src/filter.dispatch.cpp index 15bf9682fc..f6cc2a674c 100644 --- a/modules/imgproc/src/filter.dispatch.cpp +++ b/modules/imgproc/src/filter.dispatch.cpp @@ -592,7 +592,6 @@ static bool ocl_filter2D( InputArray _src, OutputArray _dst, int ddepth, // For smaller filter kernels, there is a special kernel that is more // efficient than the general one. - UMat kernalDataUMat; if (device.isIntel() && (device.type() & ocl::Device::TYPE_GPU) && ((ksize.width < 5 && ksize.height < 5) || (ksize.width == 5 && ksize.height == 5 && cn == 1))) diff --git a/modules/imgproc/src/filter.hpp b/modules/imgproc/src/filter.hpp index 570fecec17..b4782bd162 100644 --- a/modules/imgproc/src/filter.hpp +++ b/modules/imgproc/src/filter.hpp @@ -43,6 +43,9 @@ #ifndef OPENCV_IMGPROC_FILTER_HPP #define OPENCV_IMGPROC_FILTER_HPP +#include +#include + namespace cv { #ifdef HAVE_OPENCL diff --git a/modules/imgproc/src/floodfill.cpp b/modules/imgproc/src/floodfill.cpp index 3e2f2fcad0..620830e9d8 100644 --- a/modules/imgproc/src/floodfill.cpp +++ b/modules/imgproc/src/floodfill.cpp @@ -283,7 +283,7 @@ floodFillGrad_CnIR( Mat& image, Mat& msk, Diff diff, ConnectedComp* region, int flags, std::vector* buffer ) { - size_t step = image.step, maskStep = msk.step; + auto step = static_cast(image.step), maskStep = static_cast(msk.step); uchar* pImage = image.ptr(); _Tp* img = (_Tp*)(pImage + step*seed.y); uchar* pMask = msk.ptr() + maskStep + sizeof(_MTp); diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index 9d44f1e103..606efa97b4 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -957,7 +957,7 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy, sum += S[0]*w[8] + S[cn]*w[9] + S[cn*2]*w[10] + S[cn*3]*w[11]; S += sstep; sum += S[0]*w[12] + S[cn]*w[13] + S[cn*2]*w[14] + S[cn*3]*w[15]; - S += 1 - sstep*3; + S -= sstep * 3 - 1; D[k] = castOp(sum); } } @@ -990,9 +990,9 @@ static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy, for(int i = 0; i < 4; i++, w += 4 ) { int yi = y[i]; - const T* S = S0 + yi*sstep; if( yi < 0 ) continue; + const T* S = S0 + yi*sstep; if( x[0] >= 0 ) sum += (S[x[0]] - cv)*w[0]; if( x[1] >= 0 ) @@ -1050,9 +1050,9 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy, const int off_x = isRelative ? (_offset.x+dx) : 0; int sx = XY[dx*2]-3+off_x, sy = XY[dx*2+1]-3+off_y; const AT* w = wtab + FXY[dx]*64; - const T* S = S0 + sy*sstep + sx*cn; if( (unsigned)sx < width1 && (unsigned)sy < height1 ) { + const T* S = S0 + sy*sstep + sx*cn; for(int k = 0; k < cn; k++ ) { WT sum = 0; @@ -1093,9 +1093,9 @@ static void remapLanczos4( const Mat& _src, Mat& _dst, const Mat& _xy, for(int i = 0; i < 8; i++, w += 8 ) { int yi = y[i]; - const T* S1 = S0 + yi*sstep; if( yi < 0 ) continue; + const T* S1 = S0 + yi*sstep; if( x[0] >= 0 ) sum += (S1[x[0]] - cv)*w[0]; if( x[1] >= 0 ) diff --git a/modules/imgproc/src/pyramids.cpp b/modules/imgproc/src/pyramids.cpp index a1c9e7e14c..bfead998aa 100644 --- a/modules/imgproc/src/pyramids.cpp +++ b/modules/imgproc/src/pyramids.cpp @@ -45,7 +45,6 @@ #include "opencl_kernels_imgproc.hpp" #include "opencv2/core/hal/intrin.hpp" - namespace cv { diff --git a/modules/imgproc/src/shapedescr.cpp b/modules/imgproc/src/shapedescr.cpp index f1df8df27b..8ec073d386 100644 --- a/modules/imgproc/src/shapedescr.cpp +++ b/modules/imgproc/src/shapedescr.cpp @@ -340,9 +340,10 @@ double cv::contourArea( InputArray _contour, bool oriented ) namespace cv { -static inline Point2f getOfs(int i, float eps) +static inline Point2f getOfs(float eps) { - return Point2f(((i & 1)*2 - 1)*eps, ((i & 2) - 1)*eps); + RNG& rng = theRNG(); + return Point2f(rng.uniform(-eps, eps), rng.uniform(-eps, eps)); } static RotatedRect fitEllipseNoDirect( InputArray _points ) @@ -419,7 +420,7 @@ static RotatedRect fitEllipseNoDirect( InputArray _points ) float eps = (float)(s/(n*2)*1e-3); for( i = 0; i < n; i++ ) { - Point2f p = ptsf_copy[i] + getOfs(i, eps); + const Point2f p = ptsf_copy[i] + getOfs(eps); ptsf_copy[i] = p; } @@ -515,6 +516,7 @@ cv::RotatedRect cv::fitEllipseAMS( InputArray _points ) Mat points = _points.getMat(); int i, n = points.checkVector(2); int depth = points.depth(); + float eps = 0; CV_Assert( n >= 0 && (depth == CV_32F || depth == CV_32S)); RotatedRect box; @@ -552,57 +554,70 @@ cv::RotatedRect cv::fitEllipseAMS( InputArray _points ) } double scale = 100./(s > FLT_EPSILON ? s : (double)FLT_EPSILON); - for( i = 0; i < n; i++ ) + // first, try the original pointset. + // if it's singular, try to shift the points a bit + int iter = 0; + for( iter = 0; iter < 2; iter++ ) { - Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y); - double px = (p.x - c.x)*scale, py = (p.y - c.y)*scale; + for( i = 0; i < n; i++ ) + { + Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y); + const Point2f delta = getOfs(eps); + const double px = (p.x + delta.x - c.x)*scale, py = (p.y + delta.y - c.y)*scale; - A.at(i,0) = px*px; - A.at(i,1) = px*py; - A.at(i,2) = py*py; - A.at(i,3) = px; - A.at(i,4) = py; - A.at(i,5) = 1.0; + A.at(i,0) = px*px; + A.at(i,1) = px*py; + A.at(i,2) = py*py; + A.at(i,3) = px; + A.at(i,4) = py; + A.at(i,5) = 1.0; + } + cv::mulTransposed( A, DM, true, noArray(), 1.0, -1 ); + DM *= (1.0/n); + double dnm = ( DM(2,5)*(DM(0,5) + DM(2,5)) - (DM(1,5)*DM(1,5)) ); + double ddm = (4.*(DM(0,5) + DM(2,5))*( (DM(0,5)*DM(2,5)) - (DM(1,5)*DM(1,5)))); + double ddmm = (2.*(DM(0,5) + DM(2,5))*( (DM(0,5)*DM(2,5)) - (DM(1,5)*DM(1,5)))); + + M(0,0)=((-DM(0,0) + DM(0,2) + DM(0,5)*DM(0,5))*(DM(1,5)*DM(1,5)) + (-2*DM(0,1)*DM(1,5) + DM(0,5)*(DM(0,0) \ + - (DM(0,5)*DM(0,5)) + (DM(1,5)*DM(1,5))))*DM(2,5) + (DM(0,0) - (DM(0,5)*DM(0,5)))*(DM(2,5)*DM(2,5))) / ddm; + M(0,1)=((DM(1,5)*DM(1,5))*(-DM(0,1) + DM(1,2) + DM(0,5)*DM(1,5)) + (DM(0,1)*DM(0,5) - ((DM(0,5)*DM(0,5)) + 2*DM(1,1))*DM(1,5) + \ + (DM(1,5)*DM(1,5)*DM(1,5)))*DM(2,5) + (DM(0,1) - DM(0,5)*DM(1,5))*(DM(2,5)*DM(2,5))) / ddm; + M(0,2)=(-2*DM(1,2)*DM(1,5)*DM(2,5) - DM(0,5)*(DM(2,5)*DM(2,5))*(DM(0,5) + DM(2,5)) + DM(0,2)*dnm + \ + (DM(1,5)*DM(1,5))*(DM(2,2) + DM(2,5)*(DM(0,5) + DM(2,5))))/ddm; + M(0,3)=(DM(1,5)*(DM(1,5)*DM(2,3) - 2*DM(1,3)*DM(2,5)) + DM(0,3)*dnm) / ddm; + M(0,4)=(DM(1,5)*(DM(1,5)*DM(2,4) - 2*DM(1,4)*DM(2,5)) + DM(0,4)*dnm) / ddm; + M(1,0)=(-(DM(0,2)*DM(0,5)*DM(1,5)) + (2*DM(0,1)*DM(0,5) - DM(0,0)*DM(1,5))*DM(2,5))/ddmm; + M(1,1)=(-(DM(0,1)*DM(1,5)*DM(2,5)) + DM(0,5)*(-(DM(1,2)*DM(1,5)) + 2*DM(1,1)*DM(2,5)))/ddmm; + M(1,2)=(-(DM(0,2)*DM(1,5)*DM(2,5)) + DM(0,5)*(-(DM(1,5)*DM(2,2)) + 2*DM(1,2)*DM(2,5)))/ddmm; + M(1,3)=(-(DM(0,3)*DM(1,5)*DM(2,5)) + DM(0,5)*(-(DM(1,5)*DM(2,3)) + 2*DM(1,3)*DM(2,5)))/ddmm; + M(1,4)=(-(DM(0,4)*DM(1,5)*DM(2,5)) + DM(0,5)*(-(DM(1,5)*DM(2,4)) + 2*DM(1,4)*DM(2,5)))/ddmm; + M(2,0)=(-2*DM(0,1)*DM(0,5)*DM(1,5) + (DM(0,0) + (DM(0,5)*DM(0,5)))*(DM(1,5)*DM(1,5)) + DM(0,5)*(-(DM(0,5)*DM(0,5)) \ + + (DM(1,5)*DM(1,5)))*DM(2,5) - (DM(0,5)*DM(0,5))*(DM(2,5)*DM(2,5)) + DM(0,2)*(-(DM(1,5)*DM(1,5)) + DM(0,5)*(DM(0,5) + DM(2,5)))) / ddm; + M(2,1)=((DM(0,5)*DM(0,5))*(DM(1,2) - DM(1,5)*DM(2,5)) + (DM(1,5)*DM(1,5))*(DM(0,1) - DM(1,2) + DM(1,5)*DM(2,5)) \ + + DM(0,5)*(DM(1,2)*DM(2,5) + DM(1,5)*(-2*DM(1,1) + (DM(1,5)*DM(1,5)) - (DM(2,5)*DM(2,5))))) / ddm; + M(2,2)=((DM(0,5)*DM(0,5))*(DM(2,2) - (DM(2,5)*DM(2,5))) + (DM(1,5)*DM(1,5))*(DM(0,2) - DM(2,2) + (DM(2,5)*DM(2,5))) + \ + DM(0,5)*(-2*DM(1,2)*DM(1,5) + DM(2,5)*((DM(1,5)*DM(1,5)) + DM(2,2) - (DM(2,5)*DM(2,5))))) / ddm; + M(2,3)=((DM(1,5)*DM(1,5))*(DM(0,3) - DM(2,3)) + (DM(0,5)*DM(0,5))*DM(2,3) + DM(0,5)*(-2*DM(1,3)*DM(1,5) + DM(2,3)*DM(2,5))) / ddm; + M(2,4)=((DM(1,5)*DM(1,5))*(DM(0,4) - DM(2,4)) + (DM(0,5)*DM(0,5))*DM(2,4) + DM(0,5)*(-2*DM(1,4)*DM(1,5) + DM(2,4)*DM(2,5))) / ddm; + M(3,0)=DM(0,3); + M(3,1)=DM(1,3); + M(3,2)=DM(2,3); + M(3,3)=DM(3,3); + M(3,4)=DM(3,4); + M(4,0)=DM(0,4); + M(4,1)=DM(1,4); + M(4,2)=DM(2,4); + M(4,3)=DM(3,4); + M(4,4)=DM(4,4); + + if (fabs(cv::determinant(M)) > 1.0e-10) { + break; + } + + eps = (float)(s/(n*2)*1e-2); } - cv::mulTransposed( A, DM, true, noArray(), 1.0, -1 ); - DM *= (1.0/n); - double dnm = ( DM(2,5)*(DM(0,5) + DM(2,5)) - (DM(1,5)*DM(1,5)) ); - double ddm = (4.*(DM(0,5) + DM(2,5))*( (DM(0,5)*DM(2,5)) - (DM(1,5)*DM(1,5)))); - double ddmm = (2.*(DM(0,5) + DM(2,5))*( (DM(0,5)*DM(2,5)) - (DM(1,5)*DM(1,5)))); - M(0,0)=((-DM(0,0) + DM(0,2) + DM(0,5)*DM(0,5))*(DM(1,5)*DM(1,5)) + (-2*DM(0,1)*DM(1,5) + DM(0,5)*(DM(0,0) \ - - (DM(0,5)*DM(0,5)) + (DM(1,5)*DM(1,5))))*DM(2,5) + (DM(0,0) - (DM(0,5)*DM(0,5)))*(DM(2,5)*DM(2,5))) / ddm; - M(0,1)=((DM(1,5)*DM(1,5))*(-DM(0,1) + DM(1,2) + DM(0,5)*DM(1,5)) + (DM(0,1)*DM(0,5) - ((DM(0,5)*DM(0,5)) + 2*DM(1,1))*DM(1,5) + \ - (DM(1,5)*DM(1,5)*DM(1,5)))*DM(2,5) + (DM(0,1) - DM(0,5)*DM(1,5))*(DM(2,5)*DM(2,5))) / ddm; - M(0,2)=(-2*DM(1,2)*DM(1,5)*DM(2,5) - DM(0,5)*(DM(2,5)*DM(2,5))*(DM(0,5) + DM(2,5)) + DM(0,2)*dnm + \ - (DM(1,5)*DM(1,5))*(DM(2,2) + DM(2,5)*(DM(0,5) + DM(2,5))))/ddm; - M(0,3)=(DM(1,5)*(DM(1,5)*DM(2,3) - 2*DM(1,3)*DM(2,5)) + DM(0,3)*dnm) / ddm; - M(0,4)=(DM(1,5)*(DM(1,5)*DM(2,4) - 2*DM(1,4)*DM(2,5)) + DM(0,4)*dnm) / ddm; - M(1,0)=(-(DM(0,2)*DM(0,5)*DM(1,5)) + (2*DM(0,1)*DM(0,5) - DM(0,0)*DM(1,5))*DM(2,5))/ddmm; - M(1,1)=(-(DM(0,1)*DM(1,5)*DM(2,5)) + DM(0,5)*(-(DM(1,2)*DM(1,5)) + 2*DM(1,1)*DM(2,5)))/ddmm; - M(1,2)=(-(DM(0,2)*DM(1,5)*DM(2,5)) + DM(0,5)*(-(DM(1,5)*DM(2,2)) + 2*DM(1,2)*DM(2,5)))/ddmm; - M(1,3)=(-(DM(0,3)*DM(1,5)*DM(2,5)) + DM(0,5)*(-(DM(1,5)*DM(2,3)) + 2*DM(1,3)*DM(2,5)))/ddmm; - M(1,4)=(-(DM(0,4)*DM(1,5)*DM(2,5)) + DM(0,5)*(-(DM(1,5)*DM(2,4)) + 2*DM(1,4)*DM(2,5)))/ddmm; - M(2,0)=(-2*DM(0,1)*DM(0,5)*DM(1,5) + (DM(0,0) + (DM(0,5)*DM(0,5)))*(DM(1,5)*DM(1,5)) + DM(0,5)*(-(DM(0,5)*DM(0,5)) \ - + (DM(1,5)*DM(1,5)))*DM(2,5) - (DM(0,5)*DM(0,5))*(DM(2,5)*DM(2,5)) + DM(0,2)*(-(DM(1,5)*DM(1,5)) + DM(0,5)*(DM(0,5) + DM(2,5)))) / ddm; - M(2,1)=((DM(0,5)*DM(0,5))*(DM(1,2) - DM(1,5)*DM(2,5)) + (DM(1,5)*DM(1,5))*(DM(0,1) - DM(1,2) + DM(1,5)*DM(2,5)) \ - + DM(0,5)*(DM(1,2)*DM(2,5) + DM(1,5)*(-2*DM(1,1) + (DM(1,5)*DM(1,5)) - (DM(2,5)*DM(2,5))))) / ddm; - M(2,2)=((DM(0,5)*DM(0,5))*(DM(2,2) - (DM(2,5)*DM(2,5))) + (DM(1,5)*DM(1,5))*(DM(0,2) - DM(2,2) + (DM(2,5)*DM(2,5))) + \ - DM(0,5)*(-2*DM(1,2)*DM(1,5) + DM(2,5)*((DM(1,5)*DM(1,5)) + DM(2,2) - (DM(2,5)*DM(2,5))))) / ddm; - M(2,3)=((DM(1,5)*DM(1,5))*(DM(0,3) - DM(2,3)) + (DM(0,5)*DM(0,5))*DM(2,3) + DM(0,5)*(-2*DM(1,3)*DM(1,5) + DM(2,3)*DM(2,5))) / ddm; - M(2,4)=((DM(1,5)*DM(1,5))*(DM(0,4) - DM(2,4)) + (DM(0,5)*DM(0,5))*DM(2,4) + DM(0,5)*(-2*DM(1,4)*DM(1,5) + DM(2,4)*DM(2,5))) / ddm; - M(3,0)=DM(0,3); - M(3,1)=DM(1,3); - M(3,2)=DM(2,3); - M(3,3)=DM(3,3); - M(3,4)=DM(3,4); - M(4,0)=DM(0,4); - M(4,1)=DM(1,4); - M(4,2)=DM(2,4); - M(4,3)=DM(3,4); - M(4,4)=DM(4,4); - - if (fabs(cv::determinant(M)) > 1.0e-10) { + if (iter < 2) { Mat eVal, eVec; eigenNonSymmetric(M, eVal, eVec); @@ -744,7 +759,7 @@ cv::RotatedRect cv::fitEllipseDirect( InputArray _points ) for( i = 0; i < n; i++ ) { Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y); - Point2f delta = getOfs(i, eps); + const Point2f delta = getOfs(eps); double px = (p.x + delta.x - c.x)*scale, py = (p.y + delta.y - c.y)*scale; A.at(i,0) = px*px; diff --git a/modules/imgproc/src/sumpixels.avx512_skx.hpp b/modules/imgproc/src/sumpixels.avx512_skx.hpp index 09b777b268..263f89660c 100644 --- a/modules/imgproc/src/sumpixels.avx512_skx.hpp +++ b/modules/imgproc/src/sumpixels.avx512_skx.hpp @@ -385,7 +385,7 @@ __m512d IntegralCalculator < 3 > ::calculate_integral(const __m512i src_longs, c // shifts data left by 3 and 6 qwords(lanes) and gets rolling sum in all lanes // Vertical LANES: 76543210 // src_longs : HGFEDCBA - // shit3lanes : + EDCBA + // shift3lanes : + EDCBA // shift6lanes : + BA // carry_over_idxs : + 65765765 (index position of result from previous iteration) // = integral @@ -418,7 +418,7 @@ __m512d IntegralCalculator < 4 > ::calculate_integral(const __m512i src_longs, c // shifts data left by 3 and 6 qwords(lanes) and gets rolling sum in all lanes // Vertical LANES: 76543210 // src_longs : HGFEDCBA - // shit4lanes : + DCBA + // shift4lanes : + DCBA // carry_over_idxs : + 76547654 (index position of result from previous iteration) // = integral __m512i shifted4lanes = _mm512_maskz_expand_epi64(0xF0, src_longs); @@ -464,6 +464,7 @@ void calculate_integral_avx512(const uchar *src, size_t _srcstep, case 4: { IntegralCalculator< 4 > calculator; calculator.calculate_integral_avx512(src, _srcstep, sum, _sumstep, sqsum, _sqsumstep, width, height); + break; } } } diff --git a/modules/imgproc/src/thresh.cpp b/modules/imgproc/src/thresh.cpp index eb385f896d..3d7adc390f 100644 --- a/modules/imgproc/src/thresh.cpp +++ b/modules/imgproc/src/thresh.cpp @@ -1402,10 +1402,13 @@ static bool ocl_threshold( InputArray _src, OutputArray _dst, double & thresh, d int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type), kercn = ocl::predictOptimalVectorWidth(_src, _dst), ktype = CV_MAKE_TYPE(depth, kercn); bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0; + const bool isDisabled = ((thresh_type & THRESH_DRYRUN) != 0); + thresh_type &= ~THRESH_DRYRUN; - if ( !(thresh_type == THRESH_BINARY || thresh_type == THRESH_BINARY_INV || thresh_type == THRESH_TRUNC || - thresh_type == THRESH_TOZERO || thresh_type == THRESH_TOZERO_INV) || - (!doubleSupport && depth == CV_64F)) + if ( isDisabled || + !(thresh_type == THRESH_BINARY || thresh_type == THRESH_BINARY_INV || thresh_type == THRESH_TRUNC || + thresh_type == THRESH_TOZERO || thresh_type == THRESH_TOZERO_INV) || + (!doubleSupport && depth == CV_64F)) return false; const char * const thresholdMap[] = { "THRESH_BINARY", "THRESH_BINARY_INV", "THRESH_TRUNC", @@ -1450,10 +1453,14 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m CV_OCL_RUN_(_src.dims() <= 2 && _dst.isUMat(), ocl_threshold(_src, _dst, thresh, maxval, type), thresh) + const bool isDisabled = ((type & THRESH_DRYRUN) != 0); + type &= ~THRESH_DRYRUN; + Mat src = _src.getMat(); - _dst.create( src.size(), src.type() ); - Mat dst = _dst.getMat(); + if (!isDisabled) + _dst.create( src.size(), src.type() ); + Mat dst = isDisabled ? cv::Mat() : _dst.getMat(); int automatic_thresh = (type & ~cv::THRESH_MASK); type &= THRESH_MASK; @@ -1480,6 +1487,9 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m { int ithresh = cvFloor(thresh); thresh = ithresh; + if (isDisabled) + return thresh; + int imaxval = cvRound(maxval); if( type == THRESH_TRUNC ) imaxval = ithresh; @@ -1501,7 +1511,6 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m return thresh; } - thresh = ithresh; maxval = imaxval; } @@ -1509,6 +1518,9 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m { int ithresh = cvFloor(thresh); thresh = ithresh; + if (isDisabled) + return thresh; + int imaxval = cvRound(maxval); if( type == THRESH_TRUNC ) imaxval = ithresh; @@ -1536,6 +1548,9 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m { int ithresh = cvFloor(thresh); thresh = ithresh; + if (isDisabled) + return thresh; + int imaxval = cvRound(maxval); if (type == THRESH_TRUNC) imaxval = ithresh; @@ -1567,6 +1582,9 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m else CV_Error( cv::Error::StsUnsupportedFormat, "" ); + if (isDisabled) + return thresh; + parallel_for_(Range(0, dst.rows), ThresholdRunner(src, dst, thresh, maxval, type), dst.total()/(double)(1<<16)); diff --git a/modules/imgproc/test/ocl/test_imgproc.cpp b/modules/imgproc/test/ocl/test_imgproc.cpp index f3e9f4bb20..d72000884a 100644 --- a/modules/imgproc/test/ocl/test_imgproc.cpp +++ b/modules/imgproc/test/ocl/test_imgproc.cpp @@ -386,6 +386,40 @@ OCL_TEST_P(Threshold, Mat) } } +struct Threshold_Dryrun : + public ImgprocTestBase +{ + int thresholdType; + + virtual void SetUp() + { + type = GET_PARAM(0); + thresholdType = GET_PARAM(2); + useRoi = GET_PARAM(3); + } +}; + +OCL_TEST_P(Threshold_Dryrun, Mat) +{ + for (int j = 0; j < test_loop_times; j++) + { + random_roi(); + + double maxVal = randomDouble(20.0, 127.0); + double thresh = randomDouble(0.0, maxVal); + + const int _thresholdType = thresholdType | THRESH_DRYRUN; + + src_roi.copyTo(dst_roi); + usrc_roi.copyTo(udst_roi); + + OCL_OFF(cv::threshold(src_roi, dst_roi, thresh, maxVal, _thresholdType)); + OCL_ON(cv::threshold(usrc_roi, udst_roi, thresh, maxVal, _thresholdType)); + + OCL_EXPECT_MATS_NEAR(dst, 0); + } +} + /////////////////////////////////////////// CLAHE ////////////////////////////////////////////////// PARAM_TEST_CASE(CLAHETest, Size, double, bool) @@ -483,6 +517,16 @@ OCL_INSTANTIATE_TEST_CASE_P(Imgproc, Threshold, Combine( ThreshOp(THRESH_TOZERO), ThreshOp(THRESH_TOZERO_INV)), Bool())); +OCL_INSTANTIATE_TEST_CASE_P(Imgproc, Threshold_Dryrun, Combine( + Values(CV_8UC1, CV_8UC2, CV_8UC3, CV_8UC4, + CV_16SC1, CV_16SC2, CV_16SC3, CV_16SC4, + CV_32FC1, CV_32FC2, CV_32FC3, CV_32FC4), + Values(0), + Values(ThreshOp(THRESH_BINARY), + ThreshOp(THRESH_BINARY_INV), ThreshOp(THRESH_TRUNC), + ThreshOp(THRESH_TOZERO), ThreshOp(THRESH_TOZERO_INV)), + Bool())); + OCL_INSTANTIATE_TEST_CASE_P(Imgproc, CLAHETest, Combine( Values(Size(4, 4), Size(32, 8), Size(8, 64)), Values(0.0, 10.0, 62.0, 300.0), diff --git a/modules/imgproc/test/test_color.cpp b/modules/imgproc/test/test_color.cpp index a1f70103be..d97c0ab706 100644 --- a/modules/imgproc/test/test_color.cpp +++ b/modules/imgproc/test/test_color.cpp @@ -1485,9 +1485,6 @@ double CV_ColorRGBTest::get_success_error_level( int /*test_case_idx*/, int /*i* void CV_ColorRGBTest::convert_forward( const Mat& src, Mat& dst ) { int depth = src.depth(), cn = src.channels(); -/*#if defined _DEBUG || defined DEBUG - int dst_cn = CV_MAT_CN(dst->type); -#endif*/ int i, j, cols = src.cols; int g_rshift = dst_bits == 16 ? 2 : 3; int r_lshift = dst_bits == 16 ? 11 : 10; @@ -1571,9 +1568,6 @@ void CV_ColorRGBTest::convert_forward( const Mat& src, Mat& dst ) void CV_ColorRGBTest::convert_backward( const Mat& /*src*/, const Mat& src, Mat& dst ) { int depth = src.depth(), cn = dst.channels(); -/*#if defined _DEBUG || defined DEBUG - int src_cn = CV_MAT_CN(src->type); -#endif*/ int i, j, cols = src.cols; int g_lshift = dst_bits == 16 ? 2 : 3; int r_rshift = dst_bits == 16 ? 11 : 10; diff --git a/modules/imgproc/test/test_fitellipse.cpp b/modules/imgproc/test/test_fitellipse.cpp index 3e6d0478ca..169751acab 100644 --- a/modules/imgproc/test/test_fitellipse.cpp +++ b/modules/imgproc/test/test_fitellipse.cpp @@ -102,4 +102,15 @@ TEST(Imgproc_FitEllipse_JavaCase, accuracy) { EXPECT_NEAR(e.size.height, sqrt(2.)*2, 0.4); } +TEST(Imgproc_FitEllipse_HorizontalLine, accuracy) { + vector pts({{-300, 100}, {-200, 100}, {-100, 100}, {0, 100}, {100, 100}, {200, 100}, {300, 100}}); + const RotatedRect el = fitEllipse(pts); + + EXPECT_NEAR(el.center.x, -100, 100); + EXPECT_NEAR(el.center.y, 100, 1); + EXPECT_NEAR(el.size.width, 1, 1); + EXPECT_GE(el.size.height, 150); + EXPECT_NEAR(el.angle, 90, 0.1); +} + }} // namespace diff --git a/modules/imgproc/test/test_fitellipse_ams.cpp b/modules/imgproc/test/test_fitellipse_ams.cpp index 92e7f2e7a2..f2c9d1f793 100644 --- a/modules/imgproc/test/test_fitellipse_ams.cpp +++ b/modules/imgproc/test/test_fitellipse_ams.cpp @@ -337,4 +337,15 @@ TEST(Imgproc_FitEllipseAMS_Issue_7, accuracy) { EXPECT_TRUE(checkEllipse(ellipseAMSTest, ellipseAMSTrue, tol)); } +TEST(Imgproc_FitEllipseAMS_HorizontalLine, accuracy) { + vector pts({{-300, 100}, {-200, 100}, {-100, 100}, {0, 100}, {100, 100}, {200, 100}, {300, 100}}); + const RotatedRect el = fitEllipseAMS(pts); + + EXPECT_NEAR(el.center.x, 0, 200); + EXPECT_NEAR(el.center.y, 100, 1); + EXPECT_NEAR(el.size.width, 1, 1); + EXPECT_NEAR(el.size.height, 600, 100); + EXPECT_NEAR(el.angle, 90, 0.1); +} + }} // namespace diff --git a/modules/imgproc/test/test_fitellipse_direct.cpp b/modules/imgproc/test/test_fitellipse_direct.cpp index 4ae8c4dc76..e41c52764d 100644 --- a/modules/imgproc/test/test_fitellipse_direct.cpp +++ b/modules/imgproc/test/test_fitellipse_direct.cpp @@ -337,4 +337,15 @@ TEST(Imgproc_FitEllipseDirect_Issue_7, accuracy) { EXPECT_TRUE(checkEllipse(ellipseDirectTest, ellipseDirectTrue, tol)); } +TEST(Imgproc_FitEllipseDirect_HorizontalLine, accuracy) { + vector pts({{-300, 100}, {-200, 100}, {-100, 100}, {0, 100}, {100, 100}, {200, 100}, {300, 100}}); + const RotatedRect el = fitEllipseDirect(pts); + + EXPECT_NEAR(el.center.x, 0, 100); + EXPECT_NEAR(el.center.y, 100, 1); + EXPECT_NEAR(el.size.width, 2, 2); + EXPECT_NEAR(el.size.height, 600, 100); + EXPECT_NEAR(el.angle, 90, 0.1); +} + }} // namespace diff --git a/modules/imgproc/test/test_thresh.cpp b/modules/imgproc/test/test_thresh.cpp index d1c0fe551f..68b24e5663 100644 --- a/modules/imgproc/test/test_thresh.cpp +++ b/modules/imgproc/test/test_thresh.cpp @@ -57,6 +57,25 @@ BIGDATA_TEST(Imgproc_Threshold, huge) ASSERT_EQ((uint64)nz, n / 2); } +TEST(Imgproc_Threshold, threshold_dryrun) +{ + Size sz(16, 16); + Mat input_original(sz, CV_8U, Scalar::all(2)); + Mat input = input_original.clone(); + std::vector threshTypes = {THRESH_BINARY, THRESH_BINARY_INV, THRESH_TRUNC, THRESH_TOZERO, THRESH_TOZERO_INV}; + std::vector threshFlags = {0, THRESH_OTSU, THRESH_TRIANGLE}; + for(int threshType : threshTypes) + { + for(int threshFlag : threshFlags) + { + const int _threshType = threshType | threshFlag | THRESH_DRYRUN; + cv::threshold(input, input, 2.0, 0.0, _threshType); + EXPECT_MAT_NEAR(input, input_original, 0); + } + } +} + + TEST(Imgproc_Threshold, regression_THRESH_TOZERO_IPP_16085) { Size sz(16, 16); diff --git a/modules/java/generator/gen_java.py b/modules/java/generator/gen_java.py index 16b020465a..b69841c35a 100755 --- a/modules/java/generator/gen_java.py +++ b/modules/java/generator/gen_java.py @@ -437,6 +437,8 @@ class FuncInfo(GeneralInfo): arg_fix_map = func_fix_map.get(arg[1], {}) arg[0] = arg_fix_map.get('ctype', arg[0]) #fixing arg type arg[3] = arg_fix_map.get('attrib', arg[3]) #fixing arg attrib + if arg[0] == 'dnn_Net': + arg[0] = 'Net' self.args.append(ArgInfo(arg)) def fullClassJAVA(self): @@ -486,7 +488,7 @@ class JavaWrapperGenerator(object): jni_name = "(*("+classinfo.fullNameCPP()+"*)%(n)s_nativeObj)" type_dict.setdefault(name, {}).update( { "j_type" : classinfo.jname, - "jn_type" : "long", "jn_args" : (("__int64", ".nativeObj"),), + "jn_type" : "long", "jn_args" : (("__int64", ".getNativeObjAddr()"),), "jni_name" : jni_name, "jni_type" : "jlong", "suffix" : "J", @@ -495,7 +497,7 @@ class JavaWrapperGenerator(object): ) type_dict.setdefault(name+'*', {}).update( { "j_type" : classinfo.jname, - "jn_type" : "long", "jn_args" : (("__int64", ".nativeObj"),), + "jn_type" : "long", "jn_args" : (("__int64", ".getNativeObjAddr()"),), "jni_name" : "&("+jni_name+")", "jni_type" : "jlong", "suffix" : "J", diff --git a/modules/photo/src/denoising.cpp b/modules/photo/src/denoising.cpp index d81795e42b..df7794ce2d 100644 --- a/modules/photo/src/denoising.cpp +++ b/modules/photo/src/denoising.cpp @@ -249,16 +249,15 @@ static void fastNlMeansDenoisingMulti_( const std::vector& srcImgs, Mat& ds int hn = (int)h.size(); double granularity = (double)std::max(1., (double)dst.total()/(1 << 16)); - switch (srcImgs[0].type()) - { - case CV_8U: + switch (CV_MAT_CN(srcImgs[0].type())) { + case 1: parallel_for_(cv::Range(0, srcImgs[0].rows), - FastNlMeansMultiDenoisingInvoker( + FastNlMeansMultiDenoisingInvoker( srcImgs, imgToDenoiseIndex, temporalWindowSize, dst, templateWindowSize, searchWindowSize, &h[0]), granularity); break; - case CV_8UC2: + case 2: if (hn == 1) parallel_for_(cv::Range(0, srcImgs[0].rows), FastNlMeansMultiDenoisingInvoker, IT, UIT, D, int>( @@ -272,7 +271,7 @@ static void fastNlMeansDenoisingMulti_( const std::vector& srcImgs, Mat& ds dst, templateWindowSize, searchWindowSize, &h[0]), granularity); break; - case CV_8UC3: + case 3: if (hn == 1) parallel_for_(cv::Range(0, srcImgs[0].rows), FastNlMeansMultiDenoisingInvoker, IT, UIT, D, int>( @@ -286,7 +285,7 @@ static void fastNlMeansDenoisingMulti_( const std::vector& srcImgs, Mat& ds dst, templateWindowSize, searchWindowSize, &h[0]), granularity); break; - case CV_8UC4: + case 4: if (hn == 1) parallel_for_(cv::Range(0, srcImgs[0].rows), FastNlMeansMultiDenoisingInvoker, IT, UIT, D, int>( @@ -300,9 +299,9 @@ static void fastNlMeansDenoisingMulti_( const std::vector& srcImgs, Mat& ds dst, templateWindowSize, searchWindowSize, &h[0]), granularity); break; - default: + default: CV_Error(Error::StsBadArg, - "Unsupported image format! Only CV_8U, CV_8UC2, CV_8UC3 and CV_8UC4 are supported"); + "Unsupported number of channels! Only 1, 2, 3, and 4 are supported"); } } diff --git a/modules/photo/test/test_denoising.cpp b/modules/photo/test/test_denoising.cpp index fa330b85a0..2e57369171 100644 --- a/modules/photo/test/test_denoising.cpp +++ b/modules/photo/test/test_denoising.cpp @@ -165,4 +165,33 @@ TEST(Photo_Denoising, speed) printf("execution time: %gms\n", t*1000./getTickFrequency()); } +// Related issue : https://github.com/opencv/opencv/issues/26582 +TEST(Photo_DenoisingGrayscaleMulti16bitL1, regression) +{ + const int imgs_count = 3; + string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; + + vector original_8u(imgs_count); + vector original_16u(imgs_count); + for (int i = 0; i < imgs_count; i++) + { + string original_path = format("%slena_noised_gaussian_sigma=20_multi_%d.png", folder.c_str(), i); + original_8u[i] = imread(original_path, IMREAD_GRAYSCALE); + ASSERT_FALSE(original_8u[i].empty()) << "Could not load input image " << original_path; + original_8u[i].convertTo(original_16u[i], CV_16U); + } + + Mat result_8u, result_16u; + std::vector h = {15}; + fastNlMeansDenoisingMulti(original_8u, result_8u, /*imgToDenoiseIndex*/ imgs_count / 2, /*temporalWindowSize*/ imgs_count, h, 7, 21, NORM_L1); + fastNlMeansDenoisingMulti(original_16u, result_16u, /*imgToDenoiseIndex*/ imgs_count / 2, /*temporalWindowSize*/ imgs_count, h, 7, 21, NORM_L1); + DUMP(result_8u, "8u.res.png"); + DUMP(result_16u, "16u.res.png"); + + cv::Mat expected; + result_8u.convertTo(expected, CV_16U); + + EXPECT_MAT_NEAR(result_16u, expected, 1); +} + }} // namespace diff --git a/modules/photo/test/test_precomp.hpp b/modules/photo/test/test_precomp.hpp index 5d33a42f01..33d7e5a9b7 100644 --- a/modules/photo/test/test_precomp.hpp +++ b/modules/photo/test/test_precomp.hpp @@ -5,6 +5,7 @@ #define __OPENCV_TEST_PRECOMP_HPP__ #include "opencv2/ts.hpp" +#include "opencv2/ts/ocl_test.hpp" #include "opencv2/photo.hpp" #endif diff --git a/modules/python/src2/typing_stubs_generation/api_refinement.py b/modules/python/src2/typing_stubs_generation/api_refinement.py index d3950e0686..909ee9061e 100644 --- a/modules/python/src2/typing_stubs_generation/api_refinement.py +++ b/modules/python/src2/typing_stubs_generation/api_refinement.py @@ -52,6 +52,20 @@ def apply_manual_api_refinement(root: NamespaceNode) -> None: ]) +def make_optional_none_return(root_node: NamespaceNode, + function_symbol_name: SymbolName) -> None: + """ + Make return type Optional[MatLike], + for the functions that may return None. + """ + function = find_function_node(root_node, function_symbol_name) + for overload in function.overloads: + if overload.return_type is not None: + if not isinstance(overload.return_type.type_node, OptionalTypeNode): + overload.return_type.type_node = OptionalTypeNode( + overload.return_type.type_node + ) + def export_matrix_type_constants(root: NamespaceNode) -> None: MAX_PREDEFINED_CHANNELS = 4 @@ -326,6 +340,8 @@ NODES_TO_REFINE = { SymbolName(("cv", ), (), "resize"): make_optional_arg("dsize"), SymbolName(("cv", ), (), "calcHist"): make_optional_arg("mask"), SymbolName(("cv", ), (), "floodFill"): make_optional_arg("mask"), + SymbolName(("cv", ), (), "imread"): make_optional_none_return, + SymbolName(("cv", ), (), "imdecode"): make_optional_none_return, } ERROR_CLASS_PROPERTIES = ( diff --git a/modules/python/src2/typing_stubs_generation/predefined_types.py b/modules/python/src2/typing_stubs_generation/predefined_types.py index 5a15fafe61..7be97218cf 100644 --- a/modules/python/src2/typing_stubs_generation/predefined_types.py +++ b/modules/python/src2/typing_stubs_generation/predefined_types.py @@ -54,8 +54,12 @@ _PREDEFINED_TYPES = ( doc="Required length is 2"), AliasTypeNode.sequence_("Size2f", PrimitiveTypeNode.float_(), doc="Required length is 2"), - AliasTypeNode.sequence_("Scalar", PrimitiveTypeNode.float_(), - doc="Required length is at most 4"), + AliasTypeNode.union_( + "Scalar", + items=(SequenceTypeNode("Scalar", PrimitiveTypeNode.float_()), + PrimitiveTypeNode.float_()), + doc="Max sequence length is at most 4" + ), AliasTypeNode.sequence_("Point", PrimitiveTypeNode.int_(), doc="Required length is 2"), AliasTypeNode.ref_("Point2i", "Point"), diff --git a/modules/python/test/tests_common.py b/modules/python/test/tests_common.py index 00f80175ce..a204550b5f 100644 --- a/modules/python/test/tests_common.py +++ b/modules/python/test/tests_common.py @@ -24,11 +24,12 @@ class NewOpenCVTests(unittest.TestCase): # path to local repository folder containing 'samples' folder repoPath = None extraTestDataPath = None + extraDnnTestDataPath = None # github repository url repoUrl = 'https://raw.github.com/opencv/opencv/5.x' def find_file(self, filename, searchPaths=[], required=True): - searchPaths = searchPaths if searchPaths else [self.repoPath, self.extraTestDataPath] + searchPaths = searchPaths if searchPaths else [self.repoPath, self.extraTestDataPath, self.extraDnnTestDataPath] for path in searchPaths: if path is not None: candidate = path + '/' + filename @@ -57,7 +58,7 @@ class NewOpenCVTests(unittest.TestCase): def hashimg(self, im): """ Compute a hash for an image, useful for image comparisons """ - return hashlib.md5(im.tostring()).hexdigest() + return hashlib.md5(im.tobytes()).hexdigest() if sys.version_info[:2] == (2, 6): def assertLess(self, a, b, msg=None): @@ -83,10 +84,17 @@ class NewOpenCVTests(unittest.TestCase): print("Testing OpenCV", cv.__version__) print("Local repo path:", args.repo) NewOpenCVTests.repoPath = args.repo + try: NewOpenCVTests.extraTestDataPath = os.environ['OPENCV_TEST_DATA_PATH'] except KeyError: print('Missing opencv extra repository. Some of tests may fail.') + + try: + NewOpenCVTests.extraDnnTestDataPath = os.environ['OPENCV_DNN_TEST_DATA_PATH'] + except KeyError: + pass + random.seed(0) unit_argv = [sys.argv[0]] + other unittest.main(argv=unit_argv) diff --git a/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp b/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp index 9ccfd14424..bae7aa0135 100644 --- a/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp @@ -235,7 +235,7 @@ public: enum CostType { COST_COLOR, COST_COLOR_GRAD }; }; -/** @brief Minimum graph cut-based seam estimator. See details in @cite V03 . +/** @brief Minimum graph cut-based seam estimator. See details in @cite Kwatra03 . */ class CV_EXPORTS_W GraphCutSeamFinder : public GraphCutSeamFinderBase, public SeamFinder { diff --git a/modules/video/include/opencv2/video/tracking.hpp b/modules/video/include/opencv2/video/tracking.hpp index 2f2baa5760..2c76ab7046 100644 --- a/modules/video/include/opencv2/video/tracking.hpp +++ b/modules/video/include/opencv2/video/tracking.hpp @@ -46,6 +46,9 @@ #include "opencv2/core.hpp" #include "opencv2/imgproc.hpp" +#ifdef HAVE_OPENCV_DNN +# include "opencv2/dnn.hpp" +#endif namespace cv { @@ -839,6 +842,16 @@ public: static CV_WRAP Ptr create(const TrackerDaSiamRPN::Params& parameters = TrackerDaSiamRPN::Params()); +#ifdef HAVE_OPENCV_DNN + /** @brief Constructor + * @param siam_rpn pre-loaded SiamRPN model + * @param kernel_cls1 pre-loaded CLS model + * @param kernel_r1 pre-loaded R1 model + */ + static CV_WRAP + Ptr create(const dnn::Net& siam_rpn, const dnn::Net& kernel_cls1, const dnn::Net& kernel_r1); +#endif + //void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE; //bool update(InputArray image, CV_OUT Rect& boundingBox) CV_OVERRIDE; }; @@ -873,6 +886,15 @@ public: static CV_WRAP Ptr create(const TrackerNano::Params& parameters = TrackerNano::Params()); +#ifdef HAVE_OPENCV_DNN + /** @brief Constructor + * @param backbone pre-loaded backbone model + * @param neckhead pre-loaded neckhead model + */ + static CV_WRAP + Ptr create(const dnn::Net& backbone, const dnn::Net& neckhead); +#endif + //void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE; //bool update(InputArray image, CV_OUT Rect& boundingBox) CV_OVERRIDE; }; @@ -907,6 +929,18 @@ public: static CV_WRAP Ptr create(const TrackerVit::Params& parameters = TrackerVit::Params()); +#ifdef HAVE_OPENCV_DNN + /** @brief Constructor + * @param model pre-loaded DNN model + * @param meanvalue mean value for image preprocessing + * @param stdvalue std value for image preprocessing + * @param tracking_score_threshold threshold for tracking score + */ + static CV_WRAP + Ptr create(const dnn::Net& model, Scalar meanvalue = Scalar(0.485, 0.456, 0.406), + Scalar stdvalue = Scalar(0.229, 0.224, 0.225), float tracking_score_threshold = 0.20f); +#endif + // void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE; // bool update(InputArray image, CV_OUT Rect& boundingBox) CV_OVERRIDE; }; diff --git a/modules/video/misc/java/test/TrackerCreateTest.java b/modules/video/misc/java/test/TrackerCreateTest.java index 22bde9ff81..ec7c1329a6 100644 --- a/modules/video/misc/java/test/TrackerCreateTest.java +++ b/modules/video/misc/java/test/TrackerCreateTest.java @@ -1,31 +1,83 @@ package org.opencv.test.video; +import java.io.File; import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.CvException; import org.opencv.core.Mat; import org.opencv.core.Rect; +import org.opencv.dnn.Dnn; +import org.opencv.dnn.Net; import org.opencv.test.OpenCVTestCase; import org.opencv.video.Tracker; +import org.opencv.video.TrackerNano; +import org.opencv.video.TrackerNano_Params; import org.opencv.video.TrackerVit; +import org.opencv.video.TrackerVit_Params; import org.opencv.video.TrackerMIL; public class TrackerCreateTest extends OpenCVTestCase { + private final static String ENV_OPENCV_DNN_TEST_DATA_PATH = "OPENCV_DNN_TEST_DATA_PATH"; + private final static String ENV_OPENCV_TEST_DATA_PATH = "OPENCV_TEST_DATA_PATH"; + private String testDataPath; + private String modelsDataPath; + @Override protected void setUp() throws Exception { super.setUp(); + + // relys on https://developer.android.com/reference/java/lang/System + isTestCaseEnabled = System.getProperties().getProperty("java.vm.name") != "Dalvik"; + if (!isTestCaseEnabled) { + return; + } + + testDataPath = System.getenv(ENV_OPENCV_TEST_DATA_PATH); + if (testDataPath == null) { + throw new Exception(ENV_OPENCV_TEST_DATA_PATH + " has to be defined!"); + } + + modelsDataPath = System.getenv(ENV_OPENCV_DNN_TEST_DATA_PATH); + if (modelsDataPath == null) { + modelsDataPath = testDataPath; + } + + if (isTestCaseEnabled) { + testDataPath = System.getenv(ENV_OPENCV_DNN_TEST_DATA_PATH); + if (testDataPath == null) + testDataPath = System.getenv(ENV_OPENCV_TEST_DATA_PATH); + if (testDataPath == null) + throw new Exception(ENV_OPENCV_TEST_DATA_PATH + " has to be defined!"); + } } + public void testCreateTrackerNano() { + Net backbone; + Net neckhead; + try { + String backboneFile = new File(modelsDataPath, "dnn/onnx/models/nanotrack_backbone_sim_v2.onnx").toString(); + String neckheadFile = new File(modelsDataPath, "dnn/onnx/models/nanotrack_head_sim_v2.onnx").toString(); + backbone = Dnn.readNet(backboneFile); + neckhead = Dnn.readNet(neckheadFile); + } catch (CvException e) { + return; + } + Tracker tracker = TrackerNano.create(backbone, neckhead); + assert(tracker != null); + } public void testCreateTrackerVit() { + Net net; try { - Tracker tracker = TrackerVit.create(); - assert(tracker != null); + String backboneFile = new File(modelsDataPath, "dnn/onnx/models/vitTracker.onnx").toString(); + net = Dnn.readNet(backboneFile); } catch (CvException e) { - // expected, model files may be missing + return; } + Tracker tracker = TrackerVit.create(net); + assert(tracker != null); } public void testCreateTrackerMIL() { @@ -35,5 +87,4 @@ public class TrackerCreateTest extends OpenCVTestCase { Rect rect = new Rect(10, 10, 30, 30); tracker.init(mat, rect); // should not crash (https://github.com/opencv/opencv/issues/19915) } - } diff --git a/modules/video/misc/python/test/test_tracking.py b/modules/video/misc/python/test/test_tracking.py new file mode 100644 index 0000000000..211d991182 --- /dev/null +++ b/modules/video/misc/python/test/test_tracking.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +import os +import numpy as np +import cv2 as cv + +from tests_common import NewOpenCVTests, unittest + +class tracking_test(NewOpenCVTests): + + def test_createMILTracker(self): + t = cv.TrackerMIL.create() + self.assertTrue(t is not None) + + def test_createNanoTracker(self): + backbone_path = self.find_file("dnn/onnx/models/nanotrack_backbone_sim_v2.onnx", required=False); + neckhead_path = self.find_file("dnn/onnx/models/nanotrack_head_sim_v2.onnx", required=False); + backbone = cv.dnn.readNet(backbone_path) + neckhead = cv.dnn.readNet(neckhead_path) + t = cv.TrackerNano.create(backbone, neckhead) + self.assertTrue(t is not None) + + def test_createVitTracker(self): + model_path = self.find_file("dnn/onnx/models/vitTracker.onnx", required=False); + model = cv.dnn.readNet(model_path) + t = cv.TrackerVit.create(model) + self.assertTrue(t is not None) + + +if __name__ == '__main__': + NewOpenCVTests.bootstrap() diff --git a/modules/video/src/tracking/tracker_dasiamrpn.cpp b/modules/video/src/tracking/tracker_dasiamrpn.cpp index be98f7f767..4cffcc1b24 100644 --- a/modules/video/src/tracking/tracker_dasiamrpn.cpp +++ b/modules/video/src/tracking/tracker_dasiamrpn.cpp @@ -58,34 +58,42 @@ class TrackerDaSiamRPNImpl : public TrackerDaSiamRPN { public: TrackerDaSiamRPNImpl(const TrackerDaSiamRPN::Params& parameters) - : params(parameters) { // the tracker uses DNN models in quite sophisticated way, // so it's not supported yet by the new engine. // BUG: https://github.com/opencv/opencv/issues/26201 dnn::EngineType engine = dnn::ENGINE_CLASSIC; - siamRPN = dnn::readNet(params.model, "", "", engine); - siamKernelCL1 = dnn::readNet(params.kernel_cls1, "", "", engine); - siamKernelR1 = dnn::readNet(params.kernel_r1, "", "", engine); + siamRPN = dnn::readNet(parameters.model, "", "", engine); + siamKernelCL1 = dnn::readNet(parameters.kernel_cls1, "", "", engine); + siamKernelR1 = dnn::readNet(parameters.kernel_r1, "", "", engine); CV_Assert(!siamRPN.empty()); CV_Assert(!siamKernelCL1.empty()); CV_Assert(!siamKernelR1.empty()); - siamRPN.setPreferableBackend(params.backend); - siamRPN.setPreferableTarget(params.target); - siamKernelR1.setPreferableBackend(params.backend); - siamKernelR1.setPreferableTarget(params.target); - siamKernelCL1.setPreferableBackend(params.backend); - siamKernelCL1.setPreferableTarget(params.target); + siamRPN.setPreferableBackend(parameters.backend); + siamRPN.setPreferableTarget(parameters.target); + siamKernelR1.setPreferableBackend(parameters.backend); + siamKernelR1.setPreferableTarget(parameters.target); + siamKernelCL1.setPreferableBackend(parameters.backend); + siamKernelCL1.setPreferableTarget(parameters.target); + } + + TrackerDaSiamRPNImpl(const dnn::Net& siam_rpn, const dnn::Net& kernel_cls1, const dnn::Net& kernel_r1) + { + CV_Assert(!siam_rpn.empty()); + CV_Assert(!kernel_cls1.empty()); + CV_Assert(!kernel_r1.empty()); + + siamRPN = siam_rpn; + siamKernelCL1 = kernel_cls1; + siamKernelR1 = kernel_r1; } void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE; bool update(InputArray image, Rect& boundingBox) CV_OVERRIDE; float getTrackingScore() CV_OVERRIDE; - TrackerDaSiamRPN::Params params; - protected: dnn::Net siamRPN, siamKernelR1, siamKernelCL1; Rect boundingBox_; @@ -428,16 +436,22 @@ Mat TrackerDaSiamRPNImpl::getSubwindow(Mat& img, const Rect2f& targetBox, float return zCrop; } + Ptr TrackerDaSiamRPN::create(const TrackerDaSiamRPN::Params& parameters) { return makePtr(parameters); } +Ptr TrackerDaSiamRPN::create(const dnn::Net& siam_rpn, const dnn::Net& kernel_cls1, const dnn::Net& kernel_r1) +{ + return makePtr(siam_rpn, kernel_cls1, kernel_r1); +} + #else // OPENCV_HAVE_DNN Ptr TrackerDaSiamRPN::create(const TrackerDaSiamRPN::Params& parameters) { (void)(parameters); - CV_Error(cv::Error::StsNotImplemented, "to use DaSimRPN, the tracking module needs to be built with opencv_dnn !"); + CV_Error(cv::Error::StsNotImplemented, "to use DaSiamRPN, the tracking module needs to be built with opencv_dnn !"); } #endif // OPENCV_HAVE_DNN } diff --git a/modules/video/src/tracking/tracker_nano.cpp b/modules/video/src/tracking/tracker_nano.cpp index 240d7579e5..643a3ed571 100644 --- a/modules/video/src/tracking/tracker_nano.cpp +++ b/modules/video/src/tracking/tracker_nano.cpp @@ -87,22 +87,30 @@ class TrackerNanoImpl : public TrackerNano { public: TrackerNanoImpl(const TrackerNano::Params& parameters) - : params(parameters) { dnn::EngineType engine = dnn::ENGINE_AUTO; - if (params.backend != 0 || params.target != 0){ + if (parameters.backend != 0 || parameters.target != 0){ engine = dnn::ENGINE_CLASSIC; } - backbone = dnn::readNet(params.backbone, "", "", engine); - neckhead = dnn::readNet(params.neckhead, "", "", engine); + backbone = dnn::readNet(parameters.backbone, "", "", engine); + neckhead = dnn::readNet(parameters.neckhead, "", "", engine); CV_Assert(!backbone.empty()); CV_Assert(!neckhead.empty()); - backbone.setPreferableBackend(params.backend); - backbone.setPreferableTarget(params.target); - neckhead.setPreferableBackend(params.backend); - neckhead.setPreferableTarget(params.target); + backbone.setPreferableBackend(parameters.backend); + backbone.setPreferableTarget(parameters.target); + neckhead.setPreferableBackend(parameters.backend); + neckhead.setPreferableTarget(parameters.target); + } + + TrackerNanoImpl(const dnn::Net& _backbone, const dnn::Net& _neckhead) + { + CV_Assert(!_backbone.empty()); + CV_Assert(!_neckhead.empty()); + + backbone = _backbone; + neckhead = _neckhead; } void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE; @@ -114,8 +122,6 @@ public: std::vector targetPos = {0, 0}; // center point of bounding box (x, y) float tracking_score; - TrackerNano::Params params; - struct trackerConfig { float windowInfluence = 0.455f; @@ -353,6 +359,11 @@ Ptr TrackerNano::create(const TrackerNano::Params& parameters) return makePtr(parameters); } +Ptr TrackerNano::create(const dnn::Net& backbone, const dnn::Net& neckhead) +{ + return makePtr(backbone, neckhead); +} + #else // OPENCV_HAVE_DNN Ptr TrackerNano::create(const TrackerNano::Params& parameters) { diff --git a/modules/video/src/tracking/tracker_vit.cpp b/modules/video/src/tracking/tracker_vit.cpp index ee7206fb05..53797e3391 100644 --- a/modules/video/src/tracking/tracker_vit.cpp +++ b/modules/video/src/tracking/tracker_vit.cpp @@ -42,20 +42,30 @@ class TrackerVitImpl : public TrackerVit { public: TrackerVitImpl(const TrackerVit::Params& parameters) - : params(parameters) { dnn::EngineType engine = dnn::ENGINE_AUTO; - if (params.backend != 0 || params.target != 0){ + if (parameters.backend != 0 || parameters.target != 0){ engine = dnn::ENGINE_CLASSIC; } - net = dnn::readNet(params.net, "", "", engine); + net = dnn::readNet(parameters.net, "", "", engine); CV_Assert(!net.empty()); - net.setPreferableBackend(params.backend); - net.setPreferableTarget(params.target); + net.setPreferableBackend(parameters.backend); + net.setPreferableTarget(parameters.target); - i2bp.mean = params.meanvalue * 255.0; - i2bp.scalefactor = (1.0 / params.stdvalue) * (1 / 255.0); + i2bp.mean = parameters.meanvalue * 255.0; + i2bp.scalefactor = (1.0 / parameters.stdvalue) * (1 / 255.0); + tracking_score_threshold = parameters.tracking_score_threshold; + } + + TrackerVitImpl(const dnn::Net& model, Scalar meanvalue, Scalar stdvalue, float _tracking_score_threshold) + { + CV_Assert(!model.empty()); + + net = model; + i2bp.mean = meanvalue * 255.0; + i2bp.scalefactor = (1.0 / stdvalue) * (1 / 255.0); + tracking_score_threshold = _tracking_score_threshold; } void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE; @@ -65,7 +75,7 @@ public: Rect rect_last; float tracking_score; - TrackerVit::Params params; + float tracking_score_threshold; dnn::Image2BlobParams i2bp; @@ -193,7 +203,7 @@ bool TrackerVitImpl::update(InputArray image_, Rect &boundingBoxRes) minMaxLoc(conf_map, nullptr, &maxVal, nullptr, &maxLoc); tracking_score = static_cast(maxVal); - if (tracking_score >= params.tracking_score_threshold) { + if (tracking_score >= tracking_score_threshold) { float cx = (maxLoc.x + offset_map.at(0, maxLoc.y, maxLoc.x)) / 16; float cy = (maxLoc.y + offset_map.at(1, maxLoc.y, maxLoc.x)) / 16; float w = size_map.at(0, maxLoc.y, maxLoc.x); @@ -217,6 +227,11 @@ Ptr TrackerVit::create(const TrackerVit::Params& parameters) return makePtr(parameters); } +Ptr TrackerVit::create(const dnn::Net& model, Scalar meanvalue, Scalar stdvalue, float tracking_score_threshold) +{ + return makePtr(model, meanvalue, stdvalue, tracking_score_threshold); +} + #else // OPENCV_HAVE_DNN Ptr TrackerVit::create(const TrackerVit::Params& parameters) { diff --git a/modules/videoio/include/opencv2/videoio.hpp b/modules/videoio/include/opencv2/videoio.hpp index 877c0dc10e..304390b0f2 100644 --- a/modules/videoio/include/opencv2/videoio.hpp +++ b/modules/videoio/include/opencv2/videoio.hpp @@ -161,7 +161,7 @@ enum VideoCaptureProperties { CAP_PROP_TRIGGER =24, CAP_PROP_TRIGGER_DELAY =25, CAP_PROP_WHITE_BALANCE_RED_V =26, - CAP_PROP_ZOOM =27, + CAP_PROP_ZOOM =27, //!< Android: May switch physical cameras/lenses. Factor and range are hardware-dependent. CAP_PROP_FOCUS =28, CAP_PROP_GUID =29, CAP_PROP_ISO_SPEED =30, diff --git a/modules/videoio/src/cap_android_camera.cpp b/modules/videoio/src/cap_android_camera.cpp index d0bcfb367b..df3d92d7d4 100644 --- a/modules/videoio/src/cap_android_camera.cpp +++ b/modules/videoio/src/cap_android_camera.cpp @@ -42,100 +42,19 @@ using namespace cv; template struct RangeValue { T min, max; - /** - * return absolute value from relative value - * * value: in percent (50 for 50%) - * */ - T value(int percent) { + + RangeValue(T minv = 0, T maxv = 0) : min(minv), max(maxv) {} + bool isValid() const { return (min != max); } + T percentage(int percent) const { return static_cast(min + ((max - min) * percent) / 100); } - RangeValue(T minv = 0, T maxv = 0) : min(minv), max(maxv) {} - bool Supported() const { return (min != max); } T clamp( T value ) const { return (value > max) ? max : ((value < min) ? min : value); } }; -static inline void deleter_ACameraManager(ACameraManager *cameraManager) { - ACameraManager_delete(cameraManager); -} - -static inline void deleter_ACameraIdList(ACameraIdList *cameraIdList) { - ACameraManager_deleteCameraIdList(cameraIdList); -} - -static inline void deleter_ACameraDevice(ACameraDevice *cameraDevice) { - ACameraDevice_close(cameraDevice); -} - -static inline void deleter_ACameraMetadata(ACameraMetadata *cameraMetadata) { - ACameraMetadata_free(cameraMetadata); -} - -static inline void deleter_AImageReader(AImageReader *imageReader) { - AImageReader_delete(imageReader); -} - -static inline void deleter_ACaptureSessionOutputContainer(ACaptureSessionOutputContainer *outputContainer) { - ACaptureSessionOutputContainer_free(outputContainer); -} - -static inline void deleter_ACameraCaptureSession(ACameraCaptureSession *captureSession) { - ACameraCaptureSession_close(captureSession); -} - -static inline void deleter_AImage(AImage *image) { - AImage_delete(image); -} - -static inline void deleter_ANativeWindow(ANativeWindow *nativeWindow) { - ANativeWindow_release(nativeWindow); -} - -static inline void deleter_ACaptureSessionOutput(ACaptureSessionOutput *sessionOutput) { - ACaptureSessionOutput_free(sessionOutput); -} - -static inline void deleter_ACameraOutputTarget(ACameraOutputTarget *outputTarget) { - ACameraOutputTarget_free(outputTarget); -} - -static inline void deleter_ACaptureRequest(ACaptureRequest *captureRequest) { - ACaptureRequest_free(captureRequest); -} - -/* - * CameraDevice callbacks - */ -static void OnDeviceDisconnect(void* /* ctx */, ACameraDevice* dev) { - std::string id(ACameraDevice_getId(dev)); - LOGW("Device %s disconnected", id.c_str()); -} - -static void OnDeviceError(void* /* ctx */, ACameraDevice* dev, int err) { - std::string id(ACameraDevice_getId(dev)); - LOGI("Camera Device Error: %#x, Device %s", err, id.c_str()); - - switch (err) { - case ERROR_CAMERA_IN_USE: - LOGI("Camera in use"); - break; - case ERROR_CAMERA_SERVICE: - LOGI("Fatal Error occurred in Camera Service"); - break; - case ERROR_CAMERA_DEVICE: - LOGI("Fatal Error occurred in Camera Device"); - break; - case ERROR_CAMERA_DISABLED: - LOGI("Camera disabled"); - break; - case ERROR_MAX_CAMERAS_IN_USE: - LOGI("System limit for maximum concurrent cameras used was exceeded"); - break; - default: - LOGI("Unknown Camera Device Error: %#x", err); - } -} +template +using AObjPtr = std::unique_ptr>; enum class CaptureSessionState { INITIALIZING, // session is ready @@ -144,22 +63,6 @@ enum class CaptureSessionState { CLOSED // session was closed }; -void OnSessionClosed(void* context, ACameraCaptureSession* session); - -void OnSessionReady(void* context, ACameraCaptureSession* session); - -void OnSessionActive(void* context, ACameraCaptureSession* session); - -void OnCaptureCompleted(void* context, - ACameraCaptureSession* session, - ACaptureRequest* request, - const ACameraMetadata* result); - -void OnCaptureFailed(void* context, - ACameraCaptureSession* session, - ACaptureRequest* request, - ACameraCaptureFailure* failure); - #define CAPTURE_TIMEOUT_SECONDS 2 #define CAPTURE_POLL_INTERVAL_MS 5 @@ -177,16 +80,16 @@ static double elapsedTimeFrom(std::chrono::time_point class AndroidCameraCapture : public IVideoCapture { - int cachedIndex; - std::shared_ptr cameraManager; - std::shared_ptr cameraDevice; - std::shared_ptr imageReader; - std::shared_ptr outputContainer; - std::shared_ptr sessionOutput; - std::shared_ptr nativeWindow; - std::shared_ptr outputTarget; - std::shared_ptr captureRequest; - std::shared_ptr captureSession; + int deviceIndex; + AObjPtr cameraManager { nullptr, ACameraManager_delete }; + AObjPtr cameraDevice { nullptr, ACameraDevice_close }; + AObjPtr imageReader { nullptr, AImageReader_delete }; + AObjPtr outputContainer { nullptr, ACaptureSessionOutputContainer_free }; + AObjPtr sessionOutput { nullptr, ACaptureSessionOutput_free }; + AObjPtr nativeWindow { nullptr, ANativeWindow_release }; + AObjPtr outputTarget { nullptr, ACameraOutputTarget_free }; + AObjPtr captureRequest { nullptr, ACaptureRequest_free }; + AObjPtr captureSession { nullptr, ACameraCaptureSession_close }; CaptureSessionState sessionState = CaptureSessionState::INITIALIZING; int32_t frameWidth = 0; int32_t frameStride = 0; @@ -197,18 +100,36 @@ class AndroidCameraCapture : public IVideoCapture bool targetAdded = false; // properties uint32_t fourCC = FOURCC_UNKNOWN; - bool settingWidth = false; - bool settingHeight = false; - int desiredWidth = 640; - int desiredHeight = 480; + int32_t desiredWidth = 640; + int32_t desiredHeight = 480; + enum SetupState { setupDone = 0, setupWidth = 0x01, setupHeight = 0x02 } widthHeightState = setupDone; uint8_t flashMode = ACAMERA_FLASH_MODE_OFF; uint8_t aeMode = ACAMERA_CONTROL_AE_MODE_ON; int64_t exposureTime = 0; RangeValue exposureRange; int32_t sensitivity = 0; RangeValue sensitivityRange; + float zoomRatio = 1.0f; + RangeValue zoomRange; + + ACameraDevice_stateCallbacks deviceCallbacks = {}; + ACameraCaptureSession_stateCallbacks sessionCallbacks = {}; + ACameraCaptureSession_captureCallbacks captureCallbacks = {}; + + static void OnDeviceDisconnect(void* ctx, ACameraDevice* dev); + static void OnDeviceError(void* ctx, ACameraDevice* dev, int err); + static void OnSessionClosed(void* context, ACameraCaptureSession* session); + static void OnSessionReady(void* context, ACameraCaptureSession* session); + static void OnSessionActive(void* context, ACameraCaptureSession* session); + static void OnCaptureCompleted(void* context, + ACameraCaptureSession* session, + ACaptureRequest* request, + const ACameraMetadata* result); + static void OnCaptureFailed(void* context, + ACameraCaptureSession* session, + ACaptureRequest* request, + ACameraCaptureFailure* failure); -public: // for synchronization with NDK capture callback bool waitingCapture = false; bool captureSuccess = false; @@ -216,10 +137,24 @@ public: std::condition_variable condition; public: - AndroidCameraCapture(const VideoCaptureParameters& params) + AndroidCameraCapture(int index, const VideoCaptureParameters& params) + : deviceIndex(index) { - desiredWidth = params.get(CAP_PROP_FRAME_WIDTH, desiredWidth); - desiredHeight = params.get(CAP_PROP_FRAME_HEIGHT, desiredHeight); + deviceCallbacks.context = this; + deviceCallbacks.onError = OnDeviceError; + deviceCallbacks.onDisconnected = OnDeviceDisconnect, + + sessionCallbacks.context = this; + sessionCallbacks.onReady = OnSessionReady; + sessionCallbacks.onActive = OnSessionActive; + sessionCallbacks.onClosed = OnSessionClosed; + + captureCallbacks.context = this; + captureCallbacks.onCaptureCompleted = OnCaptureCompleted; + captureCallbacks.onCaptureFailed = OnCaptureFailed; + + desiredWidth = params.get(CAP_PROP_FRAME_WIDTH, desiredWidth); + desiredHeight = params.get(CAP_PROP_FRAME_HEIGHT, desiredHeight); static const struct { int propId; @@ -237,47 +172,7 @@ public: ~AndroidCameraCapture() { cleanUp(); } - ACameraDevice_stateCallbacks* GetDeviceListener() { - static ACameraDevice_stateCallbacks cameraDeviceListener = { - .onDisconnected = ::OnDeviceDisconnect, - .onError = ::OnDeviceError, - }; - return &cameraDeviceListener; - } - - ACameraCaptureSession_stateCallbacks sessionListener; - - ACameraCaptureSession_stateCallbacks* GetSessionListener() { - sessionListener = { - .context = this, - .onClosed = ::OnSessionClosed, - .onReady = ::OnSessionReady, - .onActive = ::OnSessionActive, - }; - return &sessionListener; - } - - ACameraCaptureSession_captureCallbacks captureListener; - - ACameraCaptureSession_captureCallbacks* GetCaptureCallback() { - captureListener = { - .context = this, - .onCaptureStarted = nullptr, - .onCaptureProgressed = nullptr, - .onCaptureCompleted = ::OnCaptureCompleted, - .onCaptureFailed = ::OnCaptureFailed, - .onCaptureSequenceCompleted = nullptr, - .onCaptureSequenceAborted = nullptr, - .onCaptureBufferLost = nullptr, - }; - return &captureListener; - } - - void setSessionState(CaptureSessionState newSessionState) { - this->sessionState = newSessionState; - } - - bool isOpened() const CV_OVERRIDE { return imageReader.get() != nullptr && captureSession.get() != nullptr; } + bool isOpened() const CV_OVERRIDE { return imageReader && captureSession; } int getCaptureDomain() CV_OVERRIDE { return CAP_ANDROID; } @@ -294,12 +189,15 @@ public: waitingCapture = true; captureSuccess = false; auto start = std::chrono::system_clock::now(); - bool captured = condition.wait_for(lock, std::chrono::seconds(CAPTURE_TIMEOUT_SECONDS), [this]{ return captureSuccess; }); + bool captured = condition.wait_for(lock, std::chrono::seconds( + CAPTURE_TIMEOUT_SECONDS), [this]{ return captureSuccess; }); waitingCapture = false; if (captured) { mStatus = AImageReader_acquireLatestImage(imageReader.get(), &img); - // even though an image has been captured we may not be able to acquire it straight away so we poll every 10ms - while (mStatus == AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE && elapsedTimeFrom(start) < CAPTURE_TIMEOUT_SECONDS) { + // even though an image has been captured we may not be able to acquire it + // straight away so we poll every 10ms + while (mStatus == AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE && + elapsedTimeFrom(start) < CAPTURE_TIMEOUT_SECONDS) { std::this_thread::sleep_for(std::chrono::milliseconds(CAPTURE_POLL_INTERVAL_MS)); mStatus = AImageReader_acquireLatestImage(imageReader.get(), &img); } @@ -320,7 +218,7 @@ public: } } } - std::shared_ptr image = std::shared_ptr(img, deleter_AImage); + AObjPtr image(img, AImage_delete); int32_t srcFormat = -1; AImage_getFormat(image.get(), &srcFormat); if (srcFormat != AIMAGE_FORMAT_YUV_420_888) { @@ -345,14 +243,19 @@ public: AImage_getPlanePixelStride(image.get(), 1, &uvPixelStride); int32_t yBufferLen = yLen; - if ( (uvPixelStride == 2) && (uPixel == vPixel + 1) && (yLen == (yStride * (frameHeight - 1)) + frameWidth) && (uLen == (uvStride * ((frameHeight / 2) - 1)) + frameWidth - 1) && (uvStride == yStride) && (vLen == uLen) ) { + if ( (uvPixelStride == 2) && (uPixel == vPixel + 1) && + (yLen == (yStride * (frameHeight - 1)) + frameWidth) && + (uLen == (uvStride * ((frameHeight / 2) - 1)) + frameWidth - 1) && + (uvStride == yStride) && (vLen == uLen) ) { frameStride = yStride; yBufferLen = frameStride * frameHeight; colorFormat = COLOR_FormatYUV420SemiPlanar; if (fourCC == FOURCC_UNKNOWN) { fourCC = FOURCC_NV21; } - } else if ( (uvPixelStride == 1) && (uPixel == vPixel + vLen) && (yLen == frameWidth * frameHeight) && (uLen == yLen / 4) && (vLen == uLen) ) { + } else if ( (uvPixelStride == 1) && (uPixel == vPixel + vLen) && + (yLen == frameWidth * frameHeight) && + (uLen == yLen / 4) && (vLen == uLen) ) { colorFormat = COLOR_FormatYUV420Planar; if (fourCC == FOURCC_UNKNOWN) { fourCC = FOURCC_YV12; @@ -376,7 +279,7 @@ public: return false; } if (colorFormat == COLOR_FormatYUV420Planar) { - Mat yuv(frameHeight + frameHeight/2, frameWidth, CV_8UC1, buffer.data()); + const Mat yuv(frameHeight + frameHeight/2, frameWidth, CV_8UC1, buffer.data()); switch (fourCC) { case FOURCC_BGRA: cvtColor(yuv, out, COLOR_YUV2BGRA_YV12); @@ -398,33 +301,32 @@ public: break; default: LOGE("Unexpected FOURCC value: %d", fourCC); - break; + return false; } } else if (colorFormat == COLOR_FormatYUV420SemiPlanar) { - Mat yuv(frameHeight + frameHeight/2, frameStride, CV_8UC1, buffer.data()); - Mat tmp = (frameWidth == frameStride) ? yuv : yuv(Rect(0, 0, frameWidth, frameHeight + frameHeight / 2)); + const Mat yuv(frameHeight + frameHeight/2, frameWidth, CV_8UC1, buffer.data(), frameStride); switch (fourCC) { case FOURCC_BGRA: - cvtColor(tmp, out, COLOR_YUV2BGRA_NV21); + cvtColor(yuv, out, COLOR_YUV2BGRA_NV21); break; case FOURCC_RGBA: - cvtColor(tmp, out, COLOR_YUV2RGBA_NV21); + cvtColor(yuv, out, COLOR_YUV2RGBA_NV21); break; case FOURCC_BGR: - cvtColor(tmp, out, COLOR_YUV2BGR_NV21); + cvtColor(yuv, out, COLOR_YUV2BGR_NV21); break; case FOURCC_RGB: - cvtColor(tmp, out, COLOR_YUV2RGB_NV21); + cvtColor(yuv, out, COLOR_YUV2RGB_NV21); break; case FOURCC_GRAY: - cvtColor(tmp, out, COLOR_YUV2GRAY_NV21); + cvtColor(yuv, out, COLOR_YUV2GRAY_NV21); break; case FOURCC_NV21: - tmp.copyTo(out); + yuv.copyTo(out); break; default: LOGE("Unexpected FOURCC value: %d", fourCC); - break; + return false; } } else { LOGE("Unsupported video format: %d", colorFormat); @@ -450,6 +352,8 @@ public: return fourCC; case CAP_PROP_ANDROID_DEVICE_TORCH: return (flashMode == ACAMERA_FLASH_MODE_TORCH) ? 1 : 0; + case CAP_PROP_ZOOM: + return zoomRange.isValid() ? zoomRatio : -1; default: break; } @@ -461,22 +365,12 @@ public: { switch (property_id) { case CAP_PROP_FRAME_WIDTH: - desiredWidth = value; - settingWidth = true; - if (settingWidth && settingHeight) { - setWidthHeight(); - settingWidth = false; - settingHeight = false; - } + desiredWidth = static_cast(value); + setWidthHeight(setupWidth); return true; case CAP_PROP_FRAME_HEIGHT: - desiredHeight = value; - settingHeight = true; - if (settingWidth && settingHeight) { - setWidthHeight(); - settingWidth = false; - settingHeight = false; - } + desiredHeight = static_cast(value); + setWidthHeight(setupHeight); return true; case CAP_PROP_FOURCC: { @@ -497,7 +391,8 @@ public: fourCC = newFourCC; return true; } else { - LOGE("Unsupported FOURCC conversion COLOR_FormatYUV420SemiPlanar -> COLOR_FormatYUV420Planar"); + LOGE("Unsupported FOURCC conversion COLOR_FormatYUV420SemiPlanar" + " -> COLOR_FormatYUV420Planar"); return false; } case FOURCC_NV21: @@ -505,7 +400,8 @@ public: fourCC = newFourCC; return true; } else { - LOGE("Unsupported FOURCC conversion COLOR_FormatYUV420Planar -> COLOR_FormatYUV420SemiPlanar"); + LOGE("Unsupported FOURCC conversion COLOR_FormatYUV420Planar" + " -> COLOR_FormatYUV420SemiPlanar"); return false; } default: @@ -521,19 +417,25 @@ public: } return true; case CAP_PROP_EXPOSURE: - if (isOpened() && exposureRange.Supported()) { + if (isOpened() && exposureRange.isValid()) { exposureTime = exposureRange.clamp(static_cast(value)); LOGI("Setting CAP_PROP_EXPOSURE will have no effect unless CAP_PROP_AUTO_EXPOSURE is off"); return submitRequest(ACaptureRequest_setEntry_i64, ACAMERA_SENSOR_EXPOSURE_TIME, exposureTime); } return false; case CAP_PROP_ISO_SPEED: - if (isOpened() && sensitivityRange.Supported()) { + if (isOpened() && sensitivityRange.isValid()) { sensitivity = sensitivityRange.clamp(static_cast(value)); LOGI("Setting CAP_PROP_ISO_SPEED will have no effect unless CAP_PROP_AUTO_EXPOSURE is off"); return submitRequest(ACaptureRequest_setEntry_i32, ACAMERA_SENSOR_SENSITIVITY, sensitivity); } return false; + case CAP_PROP_ZOOM: + if (isOpened() && zoomRange.isValid()) { + zoomRatio = zoomRange.clamp(static_cast(value)); + return submitRequest(ACaptureRequest_setEntry_float, ACAMERA_CONTROL_ZOOM_RATIO, zoomRatio); + } + return true; case CAP_PROP_ANDROID_DEVICE_TORCH: flashMode = (value != 0) ? ACAMERA_FLASH_MODE_TORCH : ACAMERA_FLASH_MODE_OFF; if (isOpened()) { @@ -546,132 +448,67 @@ public: return false; } - void setWidthHeight() { - cleanUp(); - initCapture(cachedIndex); - } - - // calculate a score based on how well the width and height match the desired width and height - // basically draw the 2 rectangle on top of each other and take the ratio of the non-overlapping - // area to the overlapping area - double getScore(int32_t width, int32_t height) { - double area1 = width * height; - double area2 = desiredWidth * desiredHeight; - if ((width < desiredWidth) == (height < desiredHeight)) { - return (width < desiredWidth) ? (area2 - area1)/area1 : (area1 - area2)/area2; - } else { - int32_t overlappedWidth = std::min(width, desiredWidth); - int32_t overlappedHeight = std::min(height, desiredHeight); - double overlappedArea = overlappedWidth * overlappedHeight; - return (area1 + area2 - overlappedArea)/overlappedArea; - } - } - - bool initCapture(int index) + bool initCapture() { - cachedIndex = index; - cameraManager = std::shared_ptr(ACameraManager_create(), deleter_ACameraManager); + cameraManager.reset(ACameraManager_create()); if (!cameraManager) { LOGE("Cannot create camera manager!"); return false; } - ACameraIdList* cameraIds = nullptr; + ACameraIdList* cameraIds; camera_status_t cStatus = ACameraManager_getCameraIdList(cameraManager.get(), &cameraIds); if (cStatus != ACAMERA_OK) { LOGE("Get camera list failed with error code: %d", cStatus); return false; } - std::shared_ptr cameraIdList = std::shared_ptr(cameraIds, deleter_ACameraIdList); - if (index < 0 || index >= cameraIds->numCameras) { - LOGE("Camera index out of range %d (Number of cameras: %d)", index, cameraIds->numCameras); + AObjPtr cameraIdList(cameraIds, ACameraManager_deleteCameraIdList); + if (deviceIndex < 0 || deviceIndex >= cameraIds->numCameras) { + LOGE("Camera index out of range %d (Number of cameras: %d)", deviceIndex, cameraIds->numCameras); return false; } - ACameraDevice* camera = nullptr; - cStatus = ACameraManager_openCamera(cameraManager.get(), cameraIdList.get()->cameraIds[index], GetDeviceListener(), &camera); + const char *cameraId = cameraIdList.get()->cameraIds[deviceIndex]; + + ACameraDevice* camera; + cStatus = ACameraManager_openCamera(cameraManager.get(), cameraId, &deviceCallbacks, &camera); if (cStatus != ACAMERA_OK) { LOGE("Open camera failed with error code: %d", cStatus); return false; } - cameraDevice = std::shared_ptr(camera, deleter_ACameraDevice); + cameraDevice.reset(camera); + ACameraMetadata* metadata; - cStatus = ACameraManager_getCameraCharacteristics(cameraManager.get(), cameraIdList.get()->cameraIds[index], &metadata); + cStatus = ACameraManager_getCameraCharacteristics(cameraManager.get(), cameraId, &metadata); if (cStatus != ACAMERA_OK) { LOGE("Get camera characteristics failed with error code: %d", cStatus); return false; } - std::shared_ptr cameraMetadata = std::shared_ptr(metadata, deleter_ACameraMetadata); - ACameraMetadata_const_entry entry = {}; - ACameraMetadata_getConstEntry(cameraMetadata.get(), ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry); + AObjPtr cameraMetadata(metadata, ACameraMetadata_free); - double bestScore = std::numeric_limits::max(); - int32_t bestMatchWidth = 0; - int32_t bestMatchHeight = 0; + getPropertyRanges(cameraMetadata.get()); - for (uint32_t i = 0; i < entry.count; i += 4) { - int32_t input = entry.data.i32[i + 3]; - int32_t format = entry.data.i32[i + 0]; - if (input) { - continue; - } - if (format == AIMAGE_FORMAT_YUV_420_888) { - int32_t width = entry.data.i32[i + 1]; - int32_t height = entry.data.i32[i + 2]; - if (width == desiredWidth && height == desiredHeight) { - bestMatchWidth = width; - bestMatchHeight = height; - bestScore = 0; - break; - } else { - double score = getScore(width, height); - if (score < bestScore) { - bestMatchWidth = width; - bestMatchHeight = height; - bestScore = score; - } - } - } - } + int32_t bestMatchWidth = 0, bestMatchHeight = 0; + findResolutionMatch(cameraMetadata.get(), bestMatchWidth, bestMatchHeight); LOGI("Best resolution match: %dx%d", bestMatchWidth, bestMatchHeight); - ACameraMetadata_const_entry val; - cStatus = ACameraMetadata_getConstEntry(cameraMetadata.get(), ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE, &val); - if (cStatus == ACAMERA_OK) { - exposureRange.min = exposureTimeLimits.clamp(val.data.i64[0]); - exposureRange.max = exposureTimeLimits.clamp(val.data.i64[1]); - exposureTime = exposureRange.value(2); - } else { - LOGW("Unsupported ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE"); - exposureRange.min = exposureRange.max = 0; - exposureTime = 0; - } - cStatus = ACameraMetadata_getConstEntry(cameraMetadata.get(), ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE, &val); - if (cStatus == ACAMERA_OK){ - sensitivityRange.min = val.data.i32[0]; - sensitivityRange.max = val.data.i32[1]; - sensitivity = sensitivityRange.value(2); - } else { - LOGW("Unsupported ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE"); - sensitivityRange.min = sensitivityRange.max = 0; - sensitivity = 0; - } - AImageReader* reader; - media_status_t mStatus = AImageReader_new(bestMatchWidth, bestMatchHeight, AIMAGE_FORMAT_YUV_420_888, MAX_BUF_COUNT, &reader); + media_status_t mStatus = AImageReader_new(bestMatchWidth, bestMatchHeight, + AIMAGE_FORMAT_YUV_420_888, MAX_BUF_COUNT, &reader); if (mStatus != AMEDIA_OK) { LOGE("ImageReader creation failed with error code: %d", mStatus); return false; } frameWidth = bestMatchWidth; frameHeight = bestMatchHeight; - imageReader = std::shared_ptr(reader, deleter_AImageReader); + imageReader.reset(reader); - ANativeWindow *window; + ANativeWindow* window; mStatus = AImageReader_getWindow(imageReader.get(), &window); if (mStatus != AMEDIA_OK) { LOGE("Could not get ANativeWindow: %d", mStatus); return false; } - nativeWindow = std::shared_ptr(window, deleter_ANativeWindow); + nativeWindow.reset(window); + ANativeWindow_acquire(nativeWindow.get()); ACaptureSessionOutputContainer* container; cStatus = ACaptureSessionOutputContainer_create(&container); @@ -679,16 +516,16 @@ public: LOGE("CaptureSessionOutputContainer creation failed with error code: %d", cStatus); return false; } - outputContainer = std::shared_ptr(container, deleter_ACaptureSessionOutputContainer); + outputContainer.reset(container); - ANativeWindow_acquire(nativeWindow.get()); ACaptureSessionOutput* output; cStatus = ACaptureSessionOutput_create(nativeWindow.get(), &output); if (cStatus != ACAMERA_OK) { LOGE("CaptureSessionOutput creation failed with error code: %d", cStatus); return false; } - sessionOutput = std::shared_ptr(output, deleter_ACaptureSessionOutput); + sessionOutput.reset(output); + cStatus = ACaptureSessionOutputContainer_add(outputContainer.get(), sessionOutput.get()); if (cStatus != ACAMERA_OK) { LOGE("CaptureSessionOutput Container add failed with error code: %d", cStatus); @@ -702,15 +539,15 @@ public: LOGE("CameraOutputTarget creation failed with error code: %d", cStatus); return false; } - outputTarget = std::shared_ptr(target, deleter_ACameraOutputTarget); + outputTarget.reset(target); - ACaptureRequest * request; + ACaptureRequest* request; cStatus = ACameraDevice_createCaptureRequest(cameraDevice.get(), TEMPLATE_PREVIEW, &request); if (cStatus != ACAMERA_OK) { LOGE("CaptureRequest creation failed with error code: %d", cStatus); return false; } - captureRequest = std::shared_ptr(request, deleter_ACaptureRequest); + captureRequest.reset(request); cStatus = ACaptureRequest_addTarget(captureRequest.get(), outputTarget.get()); if (cStatus != ACAMERA_OK) { @@ -719,22 +556,27 @@ public: } targetAdded = true; - ACameraCaptureSession *session; - cStatus = ACameraDevice_createCaptureSession(cameraDevice.get(), outputContainer.get(), GetSessionListener(), &session); + ACameraCaptureSession* session; + cStatus = ACameraDevice_createCaptureSession(cameraDevice.get(), + outputContainer.get(), &sessionCallbacks, &session); if (cStatus != ACAMERA_OK) { LOGE("CaptureSession creation failed with error code: %d", cStatus); return false; } - captureSession = std::shared_ptr(session, deleter_ACameraCaptureSession); + captureSession.reset(session); ACaptureRequest_setEntry_u8(captureRequest.get(), ACAMERA_CONTROL_AE_MODE, 1, &aeMode); - ACaptureRequest_setEntry_i32(captureRequest.get(), ACAMERA_SENSOR_SENSITIVITY, 1, &sensitivity); if (aeMode != ACAMERA_CONTROL_AE_MODE_ON) { + ACaptureRequest_setEntry_i32(captureRequest.get(), ACAMERA_SENSOR_SENSITIVITY, 1, &sensitivity); ACaptureRequest_setEntry_i64(captureRequest.get(), ACAMERA_SENSOR_EXPOSURE_TIME, 1, &exposureTime); } + if (zoomRange.isValid()) { + ACaptureRequest_setEntry_float(captureRequest.get(), ACAMERA_CONTROL_ZOOM_RATIO, 1, &zoomRatio); + } ACaptureRequest_setEntry_u8(captureRequest.get(), ACAMERA_FLASH_MODE, 1, &flashMode); - cStatus = ACameraCaptureSession_setRepeatingRequest(captureSession.get(), GetCaptureCallback(), 1, &request, nullptr); + cStatus = ACameraCaptureSession_setRepeatingRequest(captureSession.get(), + &captureCallbacks, 1, &request, nullptr); if (cStatus != ACAMERA_OK) { LOGE("CameraCaptureSession set repeating request failed with error code: %d", cStatus); return false; @@ -742,29 +584,122 @@ public: return true; } +private: + void getPropertyRanges(const ACameraMetadata* metadata) + { + camera_status_t cStatus; + ACameraMetadata_const_entry val; + + cStatus = ACameraMetadata_getConstEntry(metadata, ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE, &val); + if (cStatus == ACAMERA_OK) { + exposureRange.min = exposureTimeLimits.clamp(val.data.i64[0]); + exposureRange.max = exposureTimeLimits.clamp(val.data.i64[1]); + exposureTime = exposureRange.percentage(2); + } else { + LOGW("Unsupported ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE"); + exposureRange.min = exposureRange.max = 0; + exposureTime = 0; + } + + cStatus = ACameraMetadata_getConstEntry(metadata, ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE, &val); + if (cStatus == ACAMERA_OK){ + sensitivityRange.min = val.data.i32[0]; + sensitivityRange.max = val.data.i32[1]; + sensitivity = sensitivityRange.percentage(2); + } else { + LOGW("Unsupported ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE"); + sensitivityRange.min = sensitivityRange.max = 0; + sensitivity = 0; + } + + cStatus = ACameraMetadata_getConstEntry(metadata, ACAMERA_CONTROL_ZOOM_RATIO_RANGE, &val); + if (cStatus == ACAMERA_OK){ + zoomRange.min = val.data.f[0]; + zoomRange.max = val.data.f[1]; + zoomRatio = zoomRange.clamp(zoomRatio); + } else { + LOGW("Unsupported ACAMERA_CONTROL_ZOOM_RATIO_RANGE"); + zoomRange.min = zoomRange.max = 0; + zoomRatio = 1.0f; + } + } + + // calculate a score based on how well the width and height match the desired width and height + // basically draw the 2 rectangle on top of each other and take the ratio of the non-overlapping + // area to the overlapping area + double getScore(int32_t width, int32_t height) const { + double area1 = width * height; + double area2 = desiredWidth * desiredHeight; + if ((width < desiredWidth) == (height < desiredHeight)) { + return (width < desiredWidth) ? (area2 - area1)/area1 : (area1 - area2)/area2; + } else { + int32_t overlappedWidth = std::min(width, desiredWidth); + int32_t overlappedHeight = std::min(height, desiredHeight); + double overlappedArea = overlappedWidth * overlappedHeight; + return (area1 + area2 - overlappedArea)/overlappedArea; + } + } + + void findResolutionMatch(const ACameraMetadata* metadata, + int32_t &bestMatchWidth, int32_t &bestMatchHeight) const { + ACameraMetadata_const_entry entry = {}; + ACameraMetadata_getConstEntry(metadata, ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry); + + double bestScore = std::numeric_limits::max(); + for (uint32_t i = 0; i < entry.count; i += 4) { + int32_t input = entry.data.i32[i + 3]; + int32_t format = entry.data.i32[i + 0]; + + if (!input && format == AIMAGE_FORMAT_YUV_420_888) { + int32_t width = entry.data.i32[i + 1]; + int32_t height = entry.data.i32[i + 2]; + + if (width == desiredWidth && height == desiredHeight) { + bestMatchWidth = width; + bestMatchHeight = height; + return; + } + + double score = getScore(width, height); + if (score < bestScore) { + bestMatchWidth = width; + bestMatchHeight = height; + bestScore = score; + } + } + } + } + + void setWidthHeight(SetupState newState) { + if ((widthHeightState | newState) == (setupWidth | setupHeight)) { + cleanUp(); + initCapture(); + newState = setupDone; + } + widthHeightState = newState; + } + void cleanUp() { - captureListener.context = nullptr; - sessionListener.context = nullptr; if (sessionState == CaptureSessionState::ACTIVE) { ACameraCaptureSession_stopRepeating(captureSession.get()); } - captureSession = nullptr; + captureSession.reset(); if (targetAdded) { ACaptureRequest_removeTarget(captureRequest.get(), outputTarget.get()); targetAdded = false; } - captureRequest = nullptr; - outputTarget = nullptr; + captureRequest.reset(); + outputTarget.reset(); if (sessionOutputAdded) { ACaptureSessionOutputContainer_remove(outputContainer.get(), sessionOutput.get()); sessionOutputAdded = false; } - sessionOutput = nullptr; - nativeWindow = nullptr; - outputContainer = nullptr; - cameraDevice = nullptr; - cameraManager = nullptr; - imageReader = nullptr; + sessionOutput.reset(); + nativeWindow.reset(); + outputContainer.reset(); + cameraDevice.reset(); + cameraManager.reset(); + imageReader.reset(); } template @@ -775,38 +710,70 @@ public: return request && setFn(request, tag, 1, &data) == ACAMERA_OK && ACameraCaptureSession_setRepeatingRequest(captureSession.get(), - GetCaptureCallback(), + &captureCallbacks, 1, &request, nullptr) == ACAMERA_OK; } }; +/******************************** Device management *******************************/ + +void AndroidCameraCapture::OnDeviceDisconnect(void* /* ctx */, ACameraDevice* dev) { + const char *id = ACameraDevice_getId(dev); + LOGW("Device %s disconnected", id ? id : ""); +} + +void AndroidCameraCapture::OnDeviceError(void* /* ctx */, ACameraDevice* dev, int err) { + const char *id = ACameraDevice_getId(dev); + LOGI("Camera Device Error: %#x, Device %s", err, id ? id : ""); + + switch (err) { + case ERROR_CAMERA_IN_USE: + LOGI("Camera in use"); + break; + case ERROR_CAMERA_SERVICE: + LOGI("Fatal Error occurred in Camera Service"); + break; + case ERROR_CAMERA_DEVICE: + LOGI("Fatal Error occurred in Camera Device"); + break; + case ERROR_CAMERA_DISABLED: + LOGI("Camera disabled"); + break; + case ERROR_MAX_CAMERAS_IN_USE: + LOGI("System limit for maximum concurrent cameras used was exceeded"); + break; + default: + LOGI("Unknown Camera Device Error: %#x", err); + } +} + /******************************** Session management *******************************/ -void OnSessionClosed(void* context, ACameraCaptureSession* session) { +void AndroidCameraCapture::OnSessionClosed(void* context, ACameraCaptureSession* session) { if (context == nullptr) return; LOGW("session %p closed", session); - reinterpret_cast(context)->setSessionState(CaptureSessionState::CLOSED); + static_cast(context)->sessionState = CaptureSessionState::CLOSED; } -void OnSessionReady(void* context, ACameraCaptureSession* session) { +void AndroidCameraCapture::OnSessionReady(void* context, ACameraCaptureSession* session) { if (context == nullptr) return; LOGW("session %p ready", session); - reinterpret_cast(context)->setSessionState(CaptureSessionState::READY); + static_cast(context)->sessionState = CaptureSessionState::READY; } -void OnSessionActive(void* context, ACameraCaptureSession* session) { +void AndroidCameraCapture::OnSessionActive(void* context, ACameraCaptureSession* session) { if (context == nullptr) return; LOGW("session %p active", session); - reinterpret_cast(context)->setSessionState(CaptureSessionState::ACTIVE); + static_cast(context)->sessionState = CaptureSessionState::ACTIVE; } -void OnCaptureCompleted(void* context, - ACameraCaptureSession* session, - ACaptureRequest* /* request */, - const ACameraMetadata* /* result */) { +void AndroidCameraCapture::OnCaptureCompleted(void* context, + ACameraCaptureSession* session, + ACaptureRequest* /* request */, + const ACameraMetadata* /* result */) { if (context == nullptr) return; LOGV("session %p capture completed", session); - AndroidCameraCapture* cameraCapture = reinterpret_cast(context); + AndroidCameraCapture* cameraCapture = static_cast(context); std::unique_lock lock(cameraCapture->mtx); if (cameraCapture->waitingCapture) { @@ -816,13 +783,13 @@ void OnCaptureCompleted(void* context, } } -void OnCaptureFailed(void* context, - ACameraCaptureSession* session, - ACaptureRequest* /* request */, - ACameraCaptureFailure* /* failure */) { +void AndroidCameraCapture::OnCaptureFailed(void* context, + ACameraCaptureSession* session, + ACaptureRequest* /* request */, + ACameraCaptureFailure* /* failure */) { if (context == nullptr) return; LOGV("session %p capture failed", session); - AndroidCameraCapture* cameraCapture = reinterpret_cast(context); + AndroidCameraCapture* cameraCapture = static_cast(context); std::unique_lock lock(cameraCapture->mtx); if (cameraCapture->waitingCapture) { @@ -835,8 +802,8 @@ void OnCaptureFailed(void* context, /****************** Implementation of interface functions ********************/ Ptr cv::createAndroidCapture_cam(int index, const VideoCaptureParameters& params) { - Ptr res = makePtr(params); - if (res && res->initCapture(index)) + Ptr res = makePtr(index, params); + if (res && res->initCapture()) return res; return Ptr(); } diff --git a/modules/videoio/src/cap_dshow.cpp b/modules/videoio/src/cap_dshow.cpp index d46bb08a0d..5cb8232fa8 100644 --- a/modules/videoio/src/cap_dshow.cpp +++ b/modules/videoio/src/cap_dshow.cpp @@ -3360,7 +3360,7 @@ namespace cv { videoInput VideoCapture_DShow::g_VI; -VideoCapture_DShow::VideoCapture_DShow(int index) +VideoCapture_DShow::VideoCapture_DShow(int index, const VideoCaptureParameters& params) : m_index(-1) , m_width(-1) , m_height(-1) @@ -3370,6 +3370,16 @@ VideoCapture_DShow::VideoCapture_DShow(int index) , m_convertRGBSet(true) { CoInitialize(0); + + if (!params.empty()) { + int tmpW = params.get(CAP_PROP_FRAME_WIDTH, -1); + int tmpH = params.get(CAP_PROP_FRAME_HEIGHT, -1); + int tmpFOURCC = params.get(CAP_PROP_FOURCC, -1); + if (tmpW != -1 && tmpH != -1) { + g_VI.setupDeviceFourcc(index, tmpW, tmpH, tmpFOURCC); + } + } + open(index); } VideoCapture_DShow::~VideoCapture_DShow() @@ -3675,9 +3685,9 @@ void VideoCapture_DShow::close() m_convertRGBSet = true; } -Ptr create_DShow_capture(int index) +Ptr create_DShow_capture(int index, const VideoCaptureParameters& params) { - return makePtr(index); + return makePtr(index, params); } diff --git a/modules/videoio/src/cap_dshow.hpp b/modules/videoio/src/cap_dshow.hpp index 9a3b9da3bd..732ba81d8d 100644 --- a/modules/videoio/src/cap_dshow.hpp +++ b/modules/videoio/src/cap_dshow.hpp @@ -21,7 +21,7 @@ namespace cv class VideoCapture_DShow : public IVideoCapture { public: - VideoCapture_DShow(int index); + VideoCapture_DShow(int index, const VideoCaptureParameters& params); virtual ~VideoCapture_DShow(); virtual double getProperty(int propIdx) const CV_OVERRIDE; diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp index d2359b066e..4ec2137a39 100644 --- a/modules/videoio/src/cap_ffmpeg_impl.hpp +++ b/modules/videoio/src/cap_ffmpeg_impl.hpp @@ -1137,7 +1137,7 @@ bool CvCapture_FFMPEG::open(const char* _filename, const Ptr& str #endif std::string options = utils::getConfigurationParameterString("OPENCV_FFMPEG_CAPTURE_OPTIONS"); - if(!options.empty()) + if (options.empty()) { #if LIBAVFORMAT_VERSION_MICRO >= 100 && LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(55, 48, 100) av_dict_set(&dict, "rtsp_flags", "prefer_tcp", 0); diff --git a/modules/videoio/src/cap_interface.hpp b/modules/videoio/src/cap_interface.hpp index d26c089777..77e3eedb9e 100644 --- a/modules/videoio/src/cap_interface.hpp +++ b/modules/videoio/src/cap_interface.hpp @@ -223,7 +223,7 @@ public: class VideoCaptureBase : public IVideoCapture { public: - VideoCaptureBase() : autorotate(false) {} + VideoCaptureBase() : autorotate(true) {} double getProperty(int propId) const CV_OVERRIDE { switch(propId) @@ -334,7 +334,7 @@ Ptr cvCreateVideoWriter_MSMF(const std::string& filename, int four double fps, const Size& frameSize, const VideoWriterParameters& params); -Ptr create_DShow_capture(int index); +Ptr create_DShow_capture(int index, const VideoCaptureParameters& params); Ptr create_V4L_capture_cam(int index); Ptr create_V4L_capture_file(const std::string &filename); diff --git a/modules/videoio/test/test_orientation.cpp b/modules/videoio/test/test_orientation.cpp index 96530e2a03..ccff7391b0 100644 --- a/modules/videoio/test/test_orientation.cpp +++ b/modules/videoio/test/test_orientation.cpp @@ -8,69 +8,80 @@ using namespace std; namespace opencv_test { namespace { -typedef TestWithParam VideoCaptureAPITests; +// PR: https://github.com/opencv/opencv/pull/26800 +// TODO: Enable the tests back on Windows after FFmpeg plugin rebuild +#ifndef _WIN32 -// related issue: https://github.com/opencv/opencv/issues/15499 -TEST_P(VideoCaptureAPITests, mp4_orientation_meta_auto) +struct VideoCaptureAPITests: TestWithParam { - cv::VideoCaptureAPIs api = GetParam(); - if (!videoio_registry::hasBackend(api)) - throw SkipTestException("backend " + std::to_string(int(api)) + " was not found"); + void SetUp() + { + cv::VideoCaptureAPIs api = GetParam(); + if (!videoio_registry::hasBackend(api)) + throw SkipTestException("backend " + std::to_string(int(api)) + " was not found"); - string video_file = string(cvtest::TS::ptr()->get_data_path()) + "video/rotated_metadata.mp4"; + string video_file = string(cvtest::TS::ptr()->get_data_path()) + "video/rotated_metadata.mp4"; + + EXPECT_NO_THROW(cap.open(video_file, api)); + ASSERT_TRUE(cap.isOpened()) << "Can't open the video: " << video_file << " with backend " << api << std::endl; + } + + void tearDown() + { + cap.release(); + } + + void orientationCheck(double angle, int width, int height) + { + EXPECT_EQ(angle, cap.get(CAP_PROP_ORIENTATION_META)); + EXPECT_EQ(width, (int)cap.get(CAP_PROP_FRAME_WIDTH)); + EXPECT_EQ(height, (int)cap.get(CAP_PROP_FRAME_HEIGHT)); + + Mat frame; + cap >> frame; + + ASSERT_EQ(width, frame.cols); + ASSERT_EQ(height, frame.rows); + } VideoCapture cap; - EXPECT_NO_THROW(cap.open(video_file, api)); - ASSERT_TRUE(cap.isOpened()) << "Can't open the video: " << video_file << " with backend " << api << std::endl; +}; - // related issue: https://github.com/opencv/opencv/issues/22088 - EXPECT_EQ(90, cap.get(CAP_PROP_ORIENTATION_META)); - - EXPECT_TRUE(cap.set(CAP_PROP_ORIENTATION_AUTO, true)); - - Size actual; - EXPECT_NO_THROW(actual = Size((int)cap.get(CAP_PROP_FRAME_WIDTH), - (int)cap.get(CAP_PROP_FRAME_HEIGHT))); - EXPECT_EQ(270, actual.width); - EXPECT_EQ(480, actual.height); - - Mat frame; - - cap >> frame; - - ASSERT_EQ(270, frame.cols); - ASSERT_EQ(480, frame.rows); -} - -// related issue: https://github.com/opencv/opencv/issues/15499 -TEST_P(VideoCaptureAPITests, mp4_orientation_no_rotation) +// Related issues: +// - https://github.com/opencv/opencv/issues/26795 +// - https://github.com/opencv/opencv/issues/15499 +TEST_P(VideoCaptureAPITests, mp4_orientation_default_auto) { - cv::VideoCaptureAPIs api = GetParam(); - if (!videoio_registry::hasBackend(api)) - throw SkipTestException("backend " + std::to_string(int(api)) + " was not found"); - - string video_file = string(cvtest::TS::ptr()->get_data_path()) + "video/rotated_metadata.mp4"; - - VideoCapture cap; - EXPECT_NO_THROW(cap.open(video_file, api)); - cap.set(CAP_PROP_ORIENTATION_AUTO, 0); - ASSERT_TRUE(cap.isOpened()) << "Can't open the video: " << video_file << " with backend " << api << std::endl; - ASSERT_FALSE(cap.get(CAP_PROP_ORIENTATION_AUTO)); - - Size actual; - EXPECT_NO_THROW(actual = Size((int)cap.get(CAP_PROP_FRAME_WIDTH), - (int)cap.get(CAP_PROP_FRAME_HEIGHT))); - EXPECT_EQ(480, actual.width); - EXPECT_EQ(270, actual.height); - - Mat frame; - - cap >> frame; - - ASSERT_EQ(480, frame.cols); - ASSERT_EQ(270, frame.rows); + EXPECT_TRUE(cap.get(CAP_PROP_ORIENTATION_AUTO)); + orientationCheck(90., 270, 480); } -INSTANTIATE_TEST_CASE_P(videoio, VideoCaptureAPITests, testing::Values(CAP_FFMPEG, CAP_AVFOUNDATION)); +TEST_P(VideoCaptureAPITests, mp4_orientation_forced) +{ + EXPECT_TRUE(cap.set(CAP_PROP_ORIENTATION_AUTO, false)); + orientationCheck(90., 480, 270); +} + +TEST_P(VideoCaptureAPITests, mp4_orientation_switch) +{ + SCOPED_TRACE("Initial orientation with autorotation"); + orientationCheck(90., 270, 480); + SCOPED_TRACE("Disabled autorotation"); + EXPECT_TRUE(cap.set(CAP_PROP_ORIENTATION_AUTO, false)); + EXPECT_FALSE(cap.get(CAP_PROP_ORIENTATION_AUTO)); + orientationCheck(90., 480, 270); +} + + +static cv::VideoCaptureAPIs supported_backends[] = { +#ifdef HAVE_AVFOUNDATION + CAP_AVFOUNDATION, +#endif + CAP_FFMPEG +}; + +INSTANTIATE_TEST_CASE_P(videoio, VideoCaptureAPITests, testing::ValuesIn(supported_backends)); + +#endif // WIN32 }} // namespace diff --git a/platforms/linux/riscv-gnu.toolchain.cmake b/platforms/linux/riscv-gnu.toolchain.cmake index 1657bd1681..ea4994c363 100644 --- a/platforms/linux/riscv-gnu.toolchain.cmake +++ b/platforms/linux/riscv-gnu.toolchain.cmake @@ -24,25 +24,19 @@ if(NOT DEFINED TOOLCHAIN_COMPILER_LOCATION_HINT) set(TOOLCHAIN_COMPILER_LOCATION_HINT PATHS /opt/riscv/bin ENV PATH) endif() -if(NOT DEFINED CMAKE_C_COMPILER) - find_program(CMAKE_C_COMPILER NAMES ${GNU_MACHINE}-gcc${__GCC_VER_SUFFIX} PATHS ${TOOLCHAIN_COMPILER_LOCATION_HINT}) -else() - #message(WARNING "CMAKE_C_COMPILER=${CMAKE_C_COMPILER} is defined") -endif() -if(NOT DEFINED CMAKE_CXX_COMPILER) - find_program(CMAKE_CXX_COMPILER NAMES ${GNU_MACHINE}-g++${__GCC_VER_SUFFIX} PATHS ${TOOLCHAIN_COMPILER_LOCATION_HINT}) -else() - #message(WARNING "CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} is defined") -endif() -if(NOT DEFINED CMAKE_LINKER) - find_program(CMAKE_LINKER NAMES ${GNU_MACHINE}-ld${__GCC_VER_SUFFIX} ${GNU_MACHINE}-ld PATHS ${TOOLCHAIN_COMPILER_LOCATION_HINT}) -else() - #message(WARNING "CMAKE_LINKER=${CMAKE_LINKER} is defined") -endif() -if(NOT DEFINED CMAKE_AR) - find_program(CMAKE_AR NAMES ${GNU_MACHINE}-ar${__GCC_VER_SUFFIX} ${GNU_MACHINE}-ar PATHS ${TOOLCHAIN_COMPILER_LOCATION_HINT}) -else() - #message(WARNING "CMAKE_AR=${CMAKE_AR} is defined") +find_program(CMAKE_C_COMPILER NAMES ${GNU_MACHINE}-gcc${__GCC_VER_SUFFIX} PATHS ${TOOLCHAIN_COMPILER_LOCATION_HINT}) +find_program(CMAKE_CXX_COMPILER NAMES ${GNU_MACHINE}-g++${__GCC_VER_SUFFIX} PATHS ${TOOLCHAIN_COMPILER_LOCATION_HINT}) +find_program(CMAKE_LINKER NAMES ${GNU_MACHINE}-ld${__GCC_VER_SUFFIX} ${GNU_MACHINE}-ld PATHS ${TOOLCHAIN_COMPILER_LOCATION_HINT}) +find_program(CMAKE_AR NAMES ${GNU_MACHINE}-ar${__GCC_VER_SUFFIX} ${GNU_MACHINE}-ar PATHS ${TOOLCHAIN_COMPILER_LOCATION_HINT}) + +if(NOT CMAKE_C_COMPILER OR NOT CMAKE_CXX_COMPILER OR NOT CMAKE_LINKER OR NOT CMAKE_AR) + message(FATAL_ERROR "\ + One of RISC-V toolchain components have not been found: + CMAKE_C_COMPILER=${CMAKE_C_COMPILER} + CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + CMAKE_LINKER=${CMAKE_LINKER} + CMAKE_AR=${CMAKE_AR} + Use PATH environment variable and/or GNU_MACHINE, TOOLCHAIN_COMPILER_LOCATION_HINT and others cmake variables to help CMake find them.") endif() if(NOT DEFINED RISCV_SYSROOT) diff --git a/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp b/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp index 91d4266c5a..10d7eca155 100644 --- a/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp +++ b/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp @@ -71,8 +71,7 @@ int main( int argc, char** argv ) namedWindow( probabilistic_name, WINDOW_AUTOSIZE ); createTrackbar( thresh_label, probabilistic_name, &p_trackbar, max_trackbar, Probabilistic_Hough ); - char edge_thresh_label[50]; - sprintf( edge_thresh_label, "Edge Thres: input" ); + const char* edge_thresh_label = "Edge Thres: input"; namedWindow( weighted_name, WINDOW_AUTOSIZE); createTrackbar( edge_thresh_label, weighted_name, &e_trackbar, max_trackbar, Weighted_Hough); createTrackbar( thresh_label, weighted_name, &w_trackbar, weightedhough_max_trackbar, Weighted_Hough); diff --git a/samples/cpp/tutorial_code/objectDetection/aruco_samples_utility.hpp b/samples/cpp/tutorial_code/objectDetection/aruco_samples_utility.hpp index 05c52e1133..efac6cd5c6 100644 --- a/samples/cpp/tutorial_code/objectDetection/aruco_samples_utility.hpp +++ b/samples/cpp/tutorial_code/objectDetection/aruco_samples_utility.hpp @@ -32,7 +32,7 @@ inline static bool saveCameraParams(const std::string &filename, cv::Size imageS if (flags & cv::CALIB_FIX_ASPECT_RATIO) fs << "aspectRatio" << aspectRatio; if (flags != 0) { - sprintf(buf, "flags: %s%s%s%s", + snprintf(buf, sizeof(buf), "flags: %s%s%s%s", flags & cv::CALIB_USE_INTRINSIC_GUESS ? "+use_intrinsic_guess" : "", flags & cv::CALIB_FIX_ASPECT_RATIO ? "+fix_aspectRatio" : "", flags & cv::CALIB_FIX_PRINCIPAL_POINT ? "+fix_principal_point" : "", diff --git a/samples/cpp/tutorial_code/video/optical_flow/optical_flow.cpp b/samples/cpp/tutorial_code/video/optical_flow/optical_flow.cpp index 0394c6abd4..eb08eee4a5 100644 --- a/samples/cpp/tutorial_code/video/optical_flow/optical_flow.cpp +++ b/samples/cpp/tutorial_code/video/optical_flow/optical_flow.cpp @@ -46,7 +46,7 @@ int main(int argc, char **argv) int r = rng.uniform(0, 256); int g = rng.uniform(0, 256); int b = rng.uniform(0, 256); - colors.push_back(Scalar(r,g,b)); + colors.emplace_back(r,g,b); } Mat old_frame, old_gray; diff --git a/samples/data/data01.xml b/samples/data/data01.xml index d17167ccae..079d2960c1 100644 --- a/samples/data/data01.xml +++ b/samples/data/data01.xml @@ -50,7 +50,7 @@ 40 1 -
d
+
f
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 diff --git a/samples/opengl/opengl_interop.cpp b/samples/opengl/opengl_interop.cpp index 8d3e0f8d47..d8b930545b 100644 --- a/samples/opengl/opengl_interop.cpp +++ b/samples/opengl/opengl_interop.cpp @@ -221,17 +221,17 @@ public: int y = 0; buf[0] = 0; - sprintf_s(buf, sizeof(buf)-1, "Mode: %s OpenGL %s", m_modeStr[mode].c_str(), use_buffer() ? "buffer" : "texture"); + snprintf(buf, sizeof(buf), "Mode: %s OpenGL %s", m_modeStr[mode].c_str(), use_buffer() ? "buffer" : "texture"); ::TextOut(hDC, 0, y, buf, (int)strlen(buf)); y += tm.tmHeight; buf[0] = 0; - sprintf_s(buf, sizeof(buf)-1, "Time, msec: %2.1f", time); + snprintf(buf, sizeof(buf), "Time, msec: %2.1f", time); ::TextOut(hDC, 0, y, buf, (int)strlen(buf)); y += tm.tmHeight; buf[0] = 0; - sprintf_s(buf, sizeof(buf)-1, "OpenCL device: %s", oclDevName.c_str()); + snprintf(buf, sizeof(buf), "OpenCL device: %s", oclDevName.c_str()); ::TextOut(hDC, 0, y, buf, (int)strlen(buf)); ::SelectObject(hDC, hOldFont);