From 48a48fe11c579720f57f72bdec3f0f12b53cc421 Mon Sep 17 00:00:00 2001 From: Suleyman TURKMEN Date: Tue, 24 Sep 2024 02:17:36 +0300 Subject: [PATCH 01/10] Enable PNG exif orientation test --- modules/imgcodecs/CMakeLists.txt | 2 +- modules/imgcodecs/src/loadsave.cpp | 3 + modules/imgcodecs/test/test_avif.cpp | 45 -------- modules/imgcodecs/test/test_exif.cpp | 151 +++++++++++++++++++++++++++ modules/imgcodecs/test/test_jpeg.cpp | 89 ---------------- modules/imgcodecs/test/test_png.cpp | 94 ----------------- 6 files changed, 155 insertions(+), 229 deletions(-) create mode 100644 modules/imgcodecs/test/test_exif.cpp diff --git a/modules/imgcodecs/CMakeLists.txt b/modules/imgcodecs/CMakeLists.txt index 1468d4d73b..45b19da643 100644 --- a/modules/imgcodecs/CMakeLists.txt +++ b/modules/imgcodecs/CMakeLists.txt @@ -190,7 +190,7 @@ endif() if(TARGET opencv_test_imgcodecs AND HAVE_OPENEXR AND "$ENV{OPENCV_IO_ENABLE_OPENEXR}") ocv_target_compile_definitions(opencv_test_imgcodecs PRIVATE OPENCV_IMGCODECS_ENABLE_OPENEXR_TESTS=1) endif() -if(TARGET opencv_test_imgcodecs AND ((HAVE_PNG AND NOT (PNG_VERSION VERSION_LESS "1.6.31")) OR HAVE_SPNG)) +if(TARGET opencv_test_imgcodecs AND ((HAVE_PNG AND NOT (PNG_VERSION_STRING VERSION_LESS "1.6.31")) OR HAVE_SPNG)) # details: https://github.com/glennrp/libpng/commit/68cb0aaee3de6371b81a4613476d9b33e43e95b1 ocv_target_compile_definitions(opencv_test_imgcodecs PRIVATE OPENCV_IMGCODECS_PNG_WITH_EXIF=1) endif() diff --git a/modules/imgcodecs/src/loadsave.cpp b/modules/imgcodecs/src/loadsave.cpp index 8eedb0d907..0538496251 100644 --- a/modules/imgcodecs/src/loadsave.cpp +++ b/modules/imgcodecs/src/loadsave.cpp @@ -83,6 +83,9 @@ static Size validateInputImageSize(const Size& size) static inline int calcType(int type, int flags) { + if ( (flags & (IMREAD_COLOR | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH)) == (IMREAD_COLOR | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH)) + return type; + if( (flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED ) { if( (flags & IMREAD_ANYDEPTH) == 0 ) diff --git a/modules/imgcodecs/test/test_avif.cpp b/modules/imgcodecs/test/test_avif.cpp index 0d8a718756..4e708a5d0e 100644 --- a/modules/imgcodecs/test/test_avif.cpp +++ b/modules/imgcodecs/test/test_avif.cpp @@ -187,51 +187,6 @@ INSTANTIATE_TEST_CASE_P( //////////////////////////////////////////////////////////////////////////////// -typedef testing::TestWithParam Imgcodecs_AVIF_Exif; - -TEST_P(Imgcodecs_AVIF_Exif, exif_orientation) { - const string root = cvtest::TS::ptr()->get_data_path(); - const string filename = root + GetParam(); - const int colorThresholdHigh = 250; - const int colorThresholdLow = 5; - - Mat m_img = imread(filename); - ASSERT_FALSE(m_img.empty()); - Vec3b vec; - - // Checking the first quadrant (with supposed red) - vec = m_img.at(2, 2); // some point inside the square - EXPECT_LE(vec.val[0], colorThresholdLow); - EXPECT_LE(vec.val[1], colorThresholdLow); - EXPECT_GE(vec.val[2], colorThresholdHigh); - - // Checking the second quadrant (with supposed green) - vec = m_img.at(2, 7); // some point inside the square - EXPECT_LE(vec.val[0], colorThresholdLow); - EXPECT_GE(vec.val[1], colorThresholdHigh); - EXPECT_LE(vec.val[2], colorThresholdLow); - - // Checking the third quadrant (with supposed blue) - vec = m_img.at(7, 2); // some point inside the square - EXPECT_GE(vec.val[0], colorThresholdHigh); - EXPECT_LE(vec.val[1], colorThresholdLow); - EXPECT_LE(vec.val[2], colorThresholdLow); -} - -const string exif_files[] = {"readwrite/testExifOrientation_1.avif", - "readwrite/testExifOrientation_2.avif", - "readwrite/testExifOrientation_3.avif", - "readwrite/testExifOrientation_4.avif", - "readwrite/testExifOrientation_5.avif", - "readwrite/testExifOrientation_6.avif", - "readwrite/testExifOrientation_7.avif", - "readwrite/testExifOrientation_8.avif"}; - -INSTANTIATE_TEST_CASE_P(ExifFiles, Imgcodecs_AVIF_Exif, - testing::ValuesIn(exif_files)); - -//////////////////////////////////////////////////////////////////////////////// - class Imgcodecs_Avif_Animation_RoundTripSuite : public Imgcodecs_Avif_RoundTripSuite { public: diff --git a/modules/imgcodecs/test/test_exif.cpp b/modules/imgcodecs/test/test_exif.cpp new file mode 100644 index 0000000000..62cd471e23 --- /dev/null +++ b/modules/imgcodecs/test/test_exif.cpp @@ -0,0 +1,151 @@ +// 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 "test_precomp.hpp" + +namespace opencv_test { namespace { + +/** + * Test to check whether the EXIF orientation tag was processed successfully or not. + * The test uses a set of 8 images named testExifOrientation_{1 to 8}.(extension). + * Each test image is a 10x10 square, divided into four smaller sub-squares: + * (R corresponds to Red, G to Green, B to Blue, W to White) + * --------- --------- + * | R | G | | G | R | + * |-------| - (tag 1) |-------| - (tag 2) + * | B | W | | W | B | + * --------- --------- + * + * --------- --------- + * | W | B | | B | W | + * |-------| - (tag 3) |-------| - (tag 4) + * | G | R | | R | G | + * --------- --------- + * + * --------- --------- + * | R | B | | G | W | + * |-------| - (tag 5) |-------| - (tag 6) + * | G | W | | R | B | + * --------- --------- + * + * --------- --------- + * | W | G | | B | R | + * |-------| - (tag 7) |-------| - (tag 8) + * | B | R | | W | G | + * --------- --------- + * + * + * Each image contains an EXIF field with an orientation tag (0x112). + * After reading each image and applying the orientation tag, + * the resulting image should be: + * --------- + * | R | G | + * |-------| + * | B | W | + * --------- + * + * Note: + * The flags parameter of the imread function is set as IMREAD_COLOR | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH. + * Using this combination is an undocumented trick to load images similarly to the IMREAD_UNCHANGED flag, + * preserving the alpha channel (if present) while also applying the orientation. + */ + +typedef testing::TestWithParam Exif; + +TEST_P(Exif, exif_orientation) +{ + const string root = cvtest::TS::ptr()->get_data_path(); + const string filename = root + GetParam(); + const int colorThresholdHigh = 250; + const int colorThresholdLow = 5; + + // Refer to the note in the explanation above. + Mat m_img = imread(filename, IMREAD_COLOR | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH); + ASSERT_FALSE(m_img.empty()); + + if (m_img.channels() == 3) + { + Vec3b vec; + + //Checking the first quadrant (with supposed red) + vec = m_img.at(2, 2); //some point inside the square + EXPECT_LE(vec.val[0], colorThresholdLow); + EXPECT_LE(vec.val[1], colorThresholdLow); + EXPECT_GE(vec.val[2], colorThresholdHigh); + + //Checking the second quadrant (with supposed green) + vec = m_img.at(2, 7); //some point inside the square + EXPECT_LE(vec.val[0], colorThresholdLow); + EXPECT_GE(vec.val[1], colorThresholdHigh); + EXPECT_LE(vec.val[2], colorThresholdLow); + + //Checking the third quadrant (with supposed blue) + vec = m_img.at(7, 2); //some point inside the square + EXPECT_GE(vec.val[0], colorThresholdHigh); + EXPECT_LE(vec.val[1], colorThresholdLow); + EXPECT_LE(vec.val[2], colorThresholdLow); + } + else + { + Vec4b vec; + + //Checking the first quadrant (with supposed red) + vec = m_img.at(2, 2); //some point inside the square + EXPECT_LE(vec.val[0], colorThresholdLow); + EXPECT_LE(vec.val[1], colorThresholdLow); + EXPECT_GE(vec.val[2], colorThresholdHigh); + + //Checking the second quadrant (with supposed green) + vec = m_img.at(2, 7); //some point inside the square + EXPECT_LE(vec.val[0], colorThresholdLow); + EXPECT_GE(vec.val[1], colorThresholdHigh); + EXPECT_LE(vec.val[2], colorThresholdLow); + + //Checking the third quadrant (with supposed blue) + vec = m_img.at(7, 2); //some point inside the square + EXPECT_GE(vec.val[0], colorThresholdHigh); + EXPECT_LE(vec.val[1], colorThresholdLow); + EXPECT_LE(vec.val[2], colorThresholdLow); + } +} + +const string exif_files[] = +{ +#ifdef HAVE_JPEG + "readwrite/testExifOrientation_1.jpg", + "readwrite/testExifOrientation_2.jpg", + "readwrite/testExifOrientation_3.jpg", + "readwrite/testExifOrientation_4.jpg", + "readwrite/testExifOrientation_5.jpg", + "readwrite/testExifOrientation_6.jpg", + "readwrite/testExifOrientation_7.jpg", + "readwrite/testExifOrientation_8.jpg", +#endif +#ifdef OPENCV_IMGCODECS_PNG_WITH_EXIF + "readwrite/testExifOrientation_1.png", + "readwrite/testExifOrientation_2.png", + "readwrite/testExifOrientation_3.png", + "readwrite/testExifOrientation_4.png", + "readwrite/testExifOrientation_5.png", + "readwrite/testExifOrientation_6.png", + "readwrite/testExifOrientation_7.png", + "readwrite/testExifOrientation_8.png", +#endif +#ifdef HAVE_AVIF + "readwrite/testExifOrientation_1.avif", + "readwrite/testExifOrientation_2.avif", + "readwrite/testExifOrientation_3.avif", + "readwrite/testExifOrientation_4.avif", + "readwrite/testExifOrientation_5.avif", + "readwrite/testExifOrientation_6.avif", + "readwrite/testExifOrientation_7.avif", + "readwrite/testExifOrientation_8.avif", +#endif +}; + +INSTANTIATE_TEST_CASE_P(Imgcodecs, Exif, + testing::ValuesIn(exif_files)); + +} +} diff --git a/modules/imgcodecs/test/test_jpeg.cpp b/modules/imgcodecs/test/test_jpeg.cpp index 503848068a..ca46ae751c 100644 --- a/modules/imgcodecs/test/test_jpeg.cpp +++ b/modules/imgcodecs/test/test_jpeg.cpp @@ -11,95 +11,6 @@ extern "C" { #include "jpeglib.h" } -/** - * Test for check whether reading exif orientation tag was processed successfully or not - * The test info is the set of 8 images named testExifRotate_{1 to 8}.jpg - * The test image is the square 10x10 points divided by four sub-squares: - * (R corresponds to Red, G to Green, B to Blue, W to white) - * --------- --------- - * | R | G | | G | R | - * |-------| - (tag 1) |-------| - (tag 2) - * | B | W | | W | B | - * --------- --------- - * - * --------- --------- - * | W | B | | B | W | - * |-------| - (tag 3) |-------| - (tag 4) - * | G | R | | R | G | - * --------- --------- - * - * --------- --------- - * | R | B | | G | W | - * |-------| - (tag 5) |-------| - (tag 6) - * | G | W | | R | B | - * --------- --------- - * - * --------- --------- - * | W | G | | B | R | - * |-------| - (tag 7) |-------| - (tag 8) - * | B | R | | W | G | - * --------- --------- - * - * - * Every image contains exif field with orientation tag (0x112) - * After reading each image the corresponding matrix must be read as - * --------- - * | R | G | - * |-------| - * | B | W | - * --------- - * - */ - -typedef testing::TestWithParam Imgcodecs_Jpeg_Exif; - -TEST_P(Imgcodecs_Jpeg_Exif, exif_orientation) -{ - const string root = cvtest::TS::ptr()->get_data_path(); - const string filename = root + GetParam(); - const int colorThresholdHigh = 250; - const int colorThresholdLow = 5; - - Mat m_img = imread(filename); - ASSERT_FALSE(m_img.empty()); - Vec3b vec; - - //Checking the first quadrant (with supposed red) - vec = m_img.at(2, 2); //some point inside the square - EXPECT_LE(vec.val[0], colorThresholdLow); - EXPECT_LE(vec.val[1], colorThresholdLow); - EXPECT_GE(vec.val[2], colorThresholdHigh); - - //Checking the second quadrant (with supposed green) - vec = m_img.at(2, 7); //some point inside the square - EXPECT_LE(vec.val[0], colorThresholdLow); - EXPECT_GE(vec.val[1], colorThresholdHigh); - EXPECT_LE(vec.val[2], colorThresholdLow); - - //Checking the third quadrant (with supposed blue) - vec = m_img.at(7, 2); //some point inside the square - EXPECT_GE(vec.val[0], colorThresholdHigh); - EXPECT_LE(vec.val[1], colorThresholdLow); - EXPECT_LE(vec.val[2], colorThresholdLow); -} - -const string exif_files[] = -{ - "readwrite/testExifOrientation_1.jpg", - "readwrite/testExifOrientation_2.jpg", - "readwrite/testExifOrientation_3.jpg", - "readwrite/testExifOrientation_4.jpg", - "readwrite/testExifOrientation_5.jpg", - "readwrite/testExifOrientation_6.jpg", - "readwrite/testExifOrientation_7.jpg", - "readwrite/testExifOrientation_8.jpg" -}; - -INSTANTIATE_TEST_CASE_P(ExifFiles, Imgcodecs_Jpeg_Exif, - testing::ValuesIn(exif_files)); - -//================================================================================================== - TEST(Imgcodecs_Jpeg, encode_empty) { cv::Mat img; diff --git a/modules/imgcodecs/test/test_png.cpp b/modules/imgcodecs/test/test_png.cpp index 13aca2e396..4cf0e0cd99 100644 --- a/modules/imgcodecs/test/test_png.cpp +++ b/modules/imgcodecs/test/test_png.cpp @@ -109,100 +109,6 @@ TEST(Imgcodecs_Png, read_color_palette_with_alpha) EXPECT_EQ(img.at(0, 1), Vec3b(255, 0, 0)); } -/** - * Test for check whether reading exif orientation tag was processed successfully or not - * The test info is the set of 8 images named testExifRotate_{1 to 8}.png - * The test image is the square 10x10 points divided by four sub-squares: - * (R corresponds to Red, G to Green, B to Blue, W to white) - * --------- --------- - * | R | G | | G | R | - * |-------| - (tag 1) |-------| - (tag 2) - * | B | W | | W | B | - * --------- --------- - * - * --------- --------- - * | W | B | | B | W | - * |-------| - (tag 3) |-------| - (tag 4) - * | G | R | | R | G | - * --------- --------- - * - * --------- --------- - * | R | B | | G | W | - * |-------| - (tag 5) |-------| - (tag 6) - * | G | W | | R | B | - * --------- --------- - * - * --------- --------- - * | W | G | | B | R | - * |-------| - (tag 7) |-------| - (tag 8) - * | B | R | | W | G | - * --------- --------- - * - * - * Every image contains exif field with orientation tag (0x112) - * After reading each image and applying the orientation tag, - * the resulting image should be: - * --------- - * | R | G | - * |-------| - * | B | W | - * --------- - * - */ - -typedef testing::TestWithParam Imgcodecs_PNG_Exif; - -// Solution to issue 16579: PNG read doesn't support Exif orientation data -#ifdef OPENCV_IMGCODECS_PNG_WITH_EXIF -TEST_P(Imgcodecs_PNG_Exif, exif_orientation) -#else -TEST_P(Imgcodecs_PNG_Exif, DISABLED_exif_orientation) -#endif -{ - const string root = cvtest::TS::ptr()->get_data_path(); - const string filename = root + GetParam(); - const int colorThresholdHigh = 250; - const int colorThresholdLow = 5; - - Mat m_img = imread(filename); - ASSERT_FALSE(m_img.empty()); - Vec3b vec; - - //Checking the first quadrant (with supposed red) - vec = m_img.at(2, 2); //some point inside the square - EXPECT_LE(vec.val[0], colorThresholdLow); - EXPECT_LE(vec.val[1], colorThresholdLow); - EXPECT_GE(vec.val[2], colorThresholdHigh); - - //Checking the second quadrant (with supposed green) - vec = m_img.at(2, 7); //some point inside the square - EXPECT_LE(vec.val[0], colorThresholdLow); - EXPECT_GE(vec.val[1], colorThresholdHigh); - EXPECT_LE(vec.val[2], colorThresholdLow); - - //Checking the third quadrant (with supposed blue) - vec = m_img.at(7, 2); //some point inside the square - EXPECT_GE(vec.val[0], colorThresholdHigh); - EXPECT_LE(vec.val[1], colorThresholdLow); - EXPECT_LE(vec.val[2], colorThresholdLow); -} - -const string exif_files[] = -{ - "readwrite/testExifOrientation_1.png", - "readwrite/testExifOrientation_2.png", - "readwrite/testExifOrientation_3.png", - "readwrite/testExifOrientation_4.png", - "readwrite/testExifOrientation_5.png", - "readwrite/testExifOrientation_6.png", - "readwrite/testExifOrientation_7.png", - "readwrite/testExifOrientation_8.png" -}; - -INSTANTIATE_TEST_CASE_P(ExifFiles, Imgcodecs_PNG_Exif, - testing::ValuesIn(exif_files)); - - typedef testing::TestWithParam Imgcodecs_Png_PngSuite; TEST_P(Imgcodecs_Png_PngSuite, decode) From 9d64e2959f41f8673720012a99de55c9e4e87537 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Tue, 17 Sep 2024 13:28:51 +0300 Subject: [PATCH 02/10] dnn: use dispatcher for Winograd --- modules/dnn/CMakeLists.txt | 2 +- .../layers/cpu_kernels/conv_winograd_f63.cpp | 608 +--------- .../conv_winograd_f63.dispatch.cpp | 22 + .../cpu_kernels/conv_winograd_f63.neon.cpp | 476 -------- .../cpu_kernels/conv_winograd_f63.simd.hpp | 1026 ++++++++++++++++- .../src/layers/cpu_kernels/convolution.hpp | 36 +- 6 files changed, 1059 insertions(+), 1111 deletions(-) create mode 100644 modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.dispatch.cpp delete mode 100644 modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.neon.cpp diff --git a/modules/dnn/CMakeLists.txt b/modules/dnn/CMakeLists.txt index bc22696671..10d8951484 100644 --- a/modules/dnn/CMakeLists.txt +++ b/modules/dnn/CMakeLists.txt @@ -8,7 +8,7 @@ ocv_add_dispatched_file_force_all("layers/layers_common" AVX AVX2 AVX512_SKX RVV ocv_add_dispatched_file_force_all("int8layers/layers_common" AVX2 AVX512_SKX RVV LASX) ocv_add_dispatched_file_force_all("layers/cpu_kernels/conv_block" AVX AVX2 NEON NEON_FP16) ocv_add_dispatched_file_force_all("layers/cpu_kernels/conv_depthwise" AVX AVX2 RVV LASX) -ocv_add_dispatched_file_force_all("layers/cpu_kernels/conv_winograd_f63" AVX AVX2 NEON_FP16) +ocv_add_dispatched_file("layers/cpu_kernels/conv_winograd_f63" AVX AVX2 NEON NEON_FP16) ocv_add_dispatched_file_force_all("layers/cpu_kernels/fast_gemm_kernels" AVX AVX2 NEON LASX) ocv_add_module(dnn opencv_core opencv_imgproc WRAP python java objc js) diff --git a/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.cpp b/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.cpp index 46e220e69f..d054dfc121 100644 --- a/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.cpp +++ b/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.cpp @@ -12,28 +12,21 @@ #include "../../precomp.hpp" #include "convolution.hpp" -#include "conv_winograd_f63.simd.hpp" -#include "layers/cpu_kernels/conv_winograd_f63.simd_declarations.hpp" // defines CV_CPU_DISPATCH_MODES_ALL=AVX2,...,BASELINE based on CMakeLists.txt content - namespace cv { namespace dnn { -#if CV_NEON || CV_SIMD128 || CV_TRY_AVX2 enum { VEC_ALIGN = 32, DFT_TYPE = CV_32F }; // Memory alignment. -void winofunc_accum_F32(const float* inwptr, const float* wptr, float* outbuf, int Cg, int iblock, - const int winoIblock, const int winoKblock, const int winoAtomF32, const int winoNatomF32); - -/*Input transform*/ -void winofunc_BtXB_8x8_F32(const float* inptr, int inpstep, - float* outptr, int Cg, const int winoIblock, const int winoAtomF32); - -/*Output transform*/ -void winofunc_AtXA_8x8_F32(const float* inptr, int inpstep, float* bpptr, int bpstep, float* outptr, int outstep, - float bias, float minval, float maxval, bool ifMinMaxAct); - int runWinograd63(InputArray _input, InputArray _fusedAddMat, OutputArray _output, const Ptr& conv, int ntasks, float minval, float maxval, ActivationLayer* activ, bool ifMinMaxAct) { + const cv::dnn::Winofunc func = + conv->useFP16 ? cv::dnn::getWinofunc_F16() + : (conv->useAVX || conv->useAVX2 || conv->useNEON || conv->useRVV || conv->useSIMD128) ? cv::dnn::getWinofunc_F32() + : cv::dnn::Winofunc::empty(); + + if (!func.isGood()) + return 0; + Mat input = _input.getMat(); Mat output = _output.getMat(); Mat fusedAddMat = _fusedAddMat.getMat(); @@ -52,42 +45,10 @@ int runWinograd63(InputArray _input, InputArray _fusedAddMat, OutputArray _outpu int ngroups = conv->ngroups, Cg = C/ngroups, Kg = K/ngroups; const int CONV_WINO_KBLOCK = 4; -#if (CV_NEON && CV_NEON_AARCH64) - const int CONV_WINO_IBLOCK = 6; -#elif CV_TRY_AVX || CV_TRY_AVX2 - const int CONV_WINO_IBLOCK = (conv->useAVX || conv->useAVX2) ? 6 : 3; -#else - const int CONV_WINO_IBLOCK = 3; -#endif - -#if CV_TRY_AVX || CV_TRY_AVX2 - const int CONV_WINO_ATOM_F32 = (conv->useAVX || conv->useAVX2) ? 8 : 4; -#else - const int CONV_WINO_ATOM_F32 = 4; -#endif - const int CONV_WINO_NATOMS_F32 = CONV_WINO_AREA / CONV_WINO_ATOM_F32; // for AVX2, it is 8, otherwise, it's 16. - - int CONV_WINO_ATOM = CONV_WINO_ATOM_F32; - int CONV_WINO_NATOMS = CONV_WINO_NATOMS_F32; - -#ifdef CONV_ARM_FP16 - // FP 16 - const int CONV_WINO_ATOM_F16 = CONV_WINO_ATOM_F32 * 2; - const int CONV_WINO_NATOMS_F16 = CONV_WINO_AREA / CONV_WINO_ATOM_F16; -#endif - - int esz = sizeof(float ); - -#ifdef CONV_ARM_FP16 - const bool useFP16 = conv->useFP16; - if (useFP16) - { - // works at FP 16. - CONV_WINO_ATOM = CONV_WINO_ATOM_F16; - CONV_WINO_NATOMS = CONV_WINO_NATOMS_F16; - esz = sizeof(__fp16); - } -#endif + const int CONV_WINO_IBLOCK = func.iblock; + const int CONV_WINO_ATOM = func.natom; + const int CONV_WINO_NATOMS = CONV_WINO_AREA / CONV_WINO_ATOM; + const int esz = func.esz; int Kg_nblocks = (Kg + CONV_WINO_KBLOCK - 1)/CONV_WINO_KBLOCK; const size_t inp_planesize = (size_t)Hi*Wi; @@ -175,35 +136,7 @@ int runWinograd63(InputArray _input, InputArray _fusedAddMat, OutputArray _outpu inptr = inpbuf; inpstep = CONV_WINO_SIZE; } - -#if CV_TRY_AVX2 - if (conv->useAVX2) - opt_AVX2::winofunc_BtXB_8x8_F32(inptr, inpstep, (float *)inwptr, Cg, CONV_WINO_IBLOCK, CONV_WINO_ATOM); - else -#endif -#if CV_TRY_AVX - if (conv->useAVX) - opt_AVX::winofunc_BtXB_8x8_F32(inptr, inpstep, (float *)inwptr, Cg, CONV_WINO_IBLOCK, CONV_WINO_ATOM); - else -#endif -#if CV_NEON && CV_NEON_AARCH64 - if (conv->useNEON) - { -#ifdef CONV_ARM_FP16 - if (useFP16) - { - opt_NEON_FP16::winofunc_BtXB_8x8_F16(inptr, inpstep, inwptr, Cg, CONV_WINO_IBLOCK, - CONV_WINO_ATOM); - } - else -#endif - opt_NEON::winofunc_BtXB_8x8_F32(inptr, inpstep, (float *)inwptr, Cg, CONV_WINO_IBLOCK, - CONV_WINO_ATOM); - } - else -#endif - winofunc_BtXB_8x8_F32(inptr, inpstep, (float *)inwptr, Cg, CONV_WINO_IBLOCK, CONV_WINO_ATOM); - + func.BtXB_8x8(inptr, inpstep, (uchar*)inwptr, Cg, CONV_WINO_IBLOCK, CONV_WINO_ATOM); } else { @@ -219,18 +152,20 @@ int runWinograd63(InputArray _input, InputArray _fusedAddMat, OutputArray _outpu // apply inverse Winograd transforms to the sums, // add bias, apply activation function if any and store the results. char* wptr0 = nullptr; -#ifdef CONV_ARM_FP16 - if (useFP16) + if (esz == 2) { CV_Assert(!conv->weightsWinoBuf_FP16.empty()); wptr0 = (char *)conv->getWeightsWinoFP16(); } - else -#endif + else if (esz == 4) { CV_Assert(!conv->weightsWinoBuf.empty()); wptr0 = (char *)conv->getWeightsWino(); } + else + { + CV_Error(Error::StsError, "Impossible configuration"); + } parallel_for_(Range(0, ntasks), [&](const Range& r0) { for (int task_id = r0.start; task_id < r0.end; task_id++) @@ -271,36 +206,9 @@ int runWinograd63(InputArray _input, InputArray _fusedAddMat, OutputArray _outpu char* inwptr = wbuf_all + inwofs * esz; char* wptr = wptr0 + wofs * esz; -#if CV_TRY_AVX2 - if (conv->useAVX2) - opt_AVX2::winofunc_accum_F32((float *)inwptr, (float *)wptr, (float *)out_wbuf, Cg, block_id1 - block_id0, CONV_WINO_IBLOCK, - CONV_WINO_KBLOCK, CONV_WINO_ATOM, CONV_WINO_NATOMS); - else -#endif -#if CV_TRY_AVX - if (conv->useAVX) - opt_AVX::winofunc_accum_F32((float *)inwptr, (float *)wptr, (float *)out_wbuf, Cg, block_id1 - block_id0, CONV_WINO_IBLOCK, - CONV_WINO_KBLOCK, CONV_WINO_ATOM, CONV_WINO_NATOMS); - else -#endif -#if CV_NEON && CV_NEON_AARCH64 - if (conv->useNEON) - { -#ifdef CONV_ARM_FP16 - if (useFP16) - { - opt_NEON_FP16::winofunc_accum_F16(inwptr, wptr, out_wbuf, Cg, block_id1 - block_id0, CONV_WINO_IBLOCK, - CONV_WINO_KBLOCK, CONV_WINO_ATOM, CONV_WINO_NATOMS); - } - else -#endif - opt_NEON::winofunc_accum_F32((float *)inwptr, (float *)wptr, (float *)out_wbuf, Cg, block_id1 - block_id0, CONV_WINO_IBLOCK, - CONV_WINO_KBLOCK, CONV_WINO_ATOM, CONV_WINO_NATOMS); - } - else -#endif - winofunc_accum_F32((float *)inwptr, (float *)wptr, (float *)out_wbuf, Cg, block_id1 - block_id0, CONV_WINO_IBLOCK, - CONV_WINO_KBLOCK, CONV_WINO_ATOM, CONV_WINO_NATOMS); + func.accum((uchar*)inwptr, (uchar*)wptr, (uchar*)out_wbuf, Cg, + block_id1 - block_id0, CONV_WINO_IBLOCK, + CONV_WINO_KBLOCK, CONV_WINO_ATOM, CONV_WINO_NATOMS); for (int k = k0; k < k1; k++) { @@ -336,37 +244,10 @@ int runWinograd63(InputArray _input, InputArray _fusedAddMat, OutputArray _outpu dx1*sizeof(pbptr0[0])); } } -#if CV_TRY_AVX2 - if (conv->useAVX2) - opt_AVX2::winofunc_AtXA_8x8_F32((float *)out_wbuf + ((k - k0)*CONV_WINO_IBLOCK + (block_id - block_id0))*CONV_WINO_AREA, CONV_WINO_SIZE, - bpptr, outstep, outptr, outstep, biasv, minval, maxval, ifMinMaxAct); - else -#endif -#if CV_TRY_AVX - if (conv->useAVX) - opt_AVX::winofunc_AtXA_8x8_F32((float *)out_wbuf + ((k - k0)*CONV_WINO_IBLOCK + (block_id - block_id0))*CONV_WINO_AREA, CONV_WINO_SIZE, - bpptr, outstep, outptr, outstep, biasv, minval, maxval, ifMinMaxAct); - else -#endif -#if CV_NEON && CV_NEON_AARCH64 - // NEON optimization is only for ARMv8 device, and for ARMv7 device, we use the Universal intrinsics. - if (conv->useNEON) - { -#ifdef CONV_ARM_FP16 - if (useFP16) - { - opt_NEON_FP16::winofunc_AtXA_8x8_F16(out_wbuf + ((k - k0)*CONV_WINO_IBLOCK + (block_id - block_id0))*CONV_WINO_AREA * esz, CONV_WINO_SIZE, - bpptr, outstep, outptr, outstep, biasv, minval, maxval, ifMinMaxAct); - } - else -#endif - opt_NEON::winofunc_AtXA_8x8_F32((float *)out_wbuf + ((k - k0)*CONV_WINO_IBLOCK + (block_id - block_id0))*CONV_WINO_AREA, CONV_WINO_SIZE, - bpptr, outstep, outptr, outstep, biasv, minval, maxval, ifMinMaxAct); - } - else -#endif - winofunc_AtXA_8x8_F32((float *)out_wbuf + ((k - k0)*CONV_WINO_IBLOCK + (block_id - block_id0))*CONV_WINO_AREA, CONV_WINO_SIZE, - bpptr, outstep, outptr, outstep, biasv, minval, maxval, ifMinMaxAct); + + const int count = ((k - k0)*CONV_WINO_IBLOCK + (block_id - block_id0))*CONV_WINO_AREA; + func.AtXA_8x8((uchar*)out_wbuf + count * esz, CONV_WINO_SIZE, + bpptr, outstep, outptr, outstep, biasv, minval, maxval, ifMinMaxAct); if (partial) { @@ -383,441 +264,4 @@ int runWinograd63(InputArray _input, InputArray _fusedAddMat, OutputArray _outpu return 1; } -/****************************************************************************************\ - SIMD for winograd function -\****************************************************************************************/ - -#if CV_SIMD128 - -void winofunc_accum_F32(const float* inwptr, const float* wptr, float* outbuf, int Cg, int iblock, - const int winoIblock, const int winoKblock, const int winoAtomF32, const int winoNatomF32) -{ -#if 1 - CV_Assert(winoIblock == 3 && winoKblock == 4 && winoAtomF32 == 4); - for (int atom_id = 0; atom_id < winoNatomF32; atom_id++, - outbuf += winoAtomF32) - { - v_float32x4 s00 = v_setzero_f32(), s01 = s00, s02 = s00; - v_float32x4 s10 = v_setzero_f32(), s11 = s00, s12 = s00; - v_float32x4 s20 = v_setzero_f32(), s21 = s00, s22 = s00; - v_float32x4 s30 = v_setzero_f32(), s31 = s00, s32 = s00; - - for (int c = 0; c < Cg; c++, inwptr += winoIblock*winoAtomF32, - wptr += winoKblock*winoAtomF32) - { - v_float32x4 x0, x1, x2; - x0 = v_load(inwptr); - x1 = v_load(inwptr + 4); - x2 = v_load(inwptr + 8); - - v_float32x4 w0 = v_load(wptr); - s00 = v_fma(w0, x0, s00); - s01 = v_fma(w0, x1, s01); - s02 = v_fma(w0, x2, s02); - - w0 = v_load(wptr + 4); - s10 = v_fma(w0, x0, s10); - s11 = v_fma(w0, x1, s11); - s12 = v_fma(w0, x2, s12); - - w0 = v_load(wptr + 8); - s20 = v_fma(w0, x0, s20); - s21 = v_fma(w0, x1, s21); - s22 = v_fma(w0, x2, s22); - - w0 = v_load(wptr + 12); - s30 = v_fma(w0, x0, s30); - s31 = v_fma(w0, x1, s31); - s32 = v_fma(w0, x2, s32); - } - - v_store(outbuf, s00); - v_store(outbuf + 1*64, s01); - v_store(outbuf + 2*64, s02); - v_store(outbuf + 3*64, s10); - v_store(outbuf + 4*64, s11); - v_store(outbuf + 5*64, s12); - v_store(outbuf + 6*64, s20); - v_store(outbuf + 7*64, s21); - v_store(outbuf + 8*64, s22); - v_store(outbuf + 9*64, s30); - v_store(outbuf + 10*64, s31); - v_store(outbuf + 11*64, s32); - } -#else - // Naive C++ code, the code should never be run here. - for (int atom_id = 0; atom_id < winoNatomF32; - atom_id++, outbuf += winoAtomF32) - { - float sumbuf[winoIblock*winoKblock*winoAtomF32]; - memset(sumbuf, 0, sizeof(sumbuf)); - for (int c = 0; c < Cg; c++, inwptr += winoIblock*winoAtomF32, - wptr += winoKblock*winoAtomF32) - { - for (int i = 0; i < winoKblock; i++) - { - for (int j = 0; j < winoIblock; j++) - { - int i_ = i*winoAtomF32; - int j_ = j*winoAtomF32; - int ij_ = i_*winoIblock + j_; - float s0 = inwptr[j_ + 0]*wptr[i_ + 0]; - float s1 = inwptr[j_ + 1]*wptr[i_ + 1]; - float s2 = inwptr[j_ + 2]*wptr[i_ + 2]; - float s3 = inwptr[j_ + 3]*wptr[i_ + 3]; - sumbuf[ij_ + 0] += s0; - sumbuf[ij_ + 1] += s1; - sumbuf[ij_ + 2] += s2; - sumbuf[ij_ + 3] += s3; - } - } - } - for (int ij = 0; ij < winoKblock*winoIblock; ij++) - { - int ij_ = ij*winoAtomF32; - int ij_out = ij*CONV_WINO_AREA; - outbuf[ij_out + 0] = sumbuf[ij_ + 0]; - outbuf[ij_out + 1] = sumbuf[ij_ + 1]; - outbuf[ij_out + 2] = sumbuf[ij_ + 2]; - outbuf[ij_out + 3] = sumbuf[ij_ + 3]; - } - } -#endif -} - -/*Input transform*/ -void winofunc_BtXB_8x8_F32(const float* inptr, int inpstep, - float* outptr, int Cg, const int winoIblock, const int winoAtomF32) -{ - CV_Assert(winoIblock == 3 && winoAtomF32 == 4); - v_float32x4 x00 = v_load(inptr), x01 = v_load(inptr + 4); - v_float32x4 x10 = v_load(inptr + inpstep), x11 = v_load(inptr + inpstep + 4); - v_float32x4 x20 = v_load(inptr + inpstep*2), x21 = v_load(inptr + inpstep*2 + 4); - v_float32x4 x30 = v_load(inptr + inpstep*3), x31 = v_load(inptr + inpstep*3 + 4); - v_float32x4 x40 = v_load(inptr + inpstep*4), x41 = v_load(inptr + inpstep*4 + 4); - v_float32x4 x50 = v_load(inptr + inpstep*5), x51 = v_load(inptr + inpstep*5 + 4); - v_float32x4 x60 = v_load(inptr + inpstep*6), x61 = v_load(inptr + inpstep*6 + 4); - v_float32x4 x70 = v_load(inptr + inpstep*7), x71 = v_load(inptr + inpstep*7 + 4); - - v_float32x4 z00, z01, z10, z11, z20, z21, z30, z31, z40, z41, z50, z51, z60, z61, z70, z71; - - { - /* Y[0] = [1.f, 0.f, -5.25f, 0.f, 5.25f, 0.f, -1.f, 0.f]*X */ - /* Y[7] = [0.f, -1.f, 0.f, 5.25f, 0.f, -5.25f, 0.f, 1.f]*X */ - v_float32x4 q5_25 = v_setall_f32(5.25f), t00, t01, t10, t11; - t00 = v_sub(x40, x20); - t01 = v_sub(x41, x21); - t10 = v_sub(x30, x50); - t11 = v_sub(x31, x51); - v_float32x4 y00 = v_fma(t00, q5_25, v_sub(x00, x60)); - v_float32x4 y01 = v_fma(t01, q5_25, v_sub(x01, x61)); - v_float32x4 y70 = v_fma(t10, q5_25, v_sub(x70, x10)); - v_float32x4 y71 = v_fma(t11, q5_25, v_sub(x71, x11)); - - /* Y[1] = [0.f, 1.f, 1.f, -4.25f, -4.25f, 1.f, 1.f, 0.f]*X */ - /* Y[2] = [0.f, -1.f, 1.f, 4.25f, -4.25f, -1.f, 1.f, 0.f]*X */ - v_float32x4 qm4_25 = v_setall_f32(-4.25f); - t00 = v_fma(x30, qm4_25, v_add(x10, x50)); - t01 = v_fma(x31, qm4_25, v_add(x11, x51)); - t10 = v_fma(x40, qm4_25, v_add(x20, x60)); - t11 = v_fma(x41, qm4_25, v_add(x21, x61)); - - v_float32x4 y10 = v_add(t00, t10), y11 = v_add(t01, t11); - v_float32x4 y20 = v_sub(t10, t00), y21 = v_sub(t11, t01); - - /* Y[3] = [0.f, 0.5f, 0.25f, -2.5f, -1.25f, 2.f, 1.f, 0.f]*X */ - /* Y[4] = [0.f, -0.5f, 0.25f, 2.5f, -1.25f, -2.f, 1.f, 0.f]*X */ - v_float32x4 q0_5 = v_setall_f32(0.5f), q0_25 = v_setall_f32(0.25f); - v_float32x4 qm2_5 = v_setall_f32(-2.5f), qm1_25 = v_setall_f32(-1.25f); - t00 = v_fma(x10, q0_5, v_add(x50, x50)); - t01 = v_fma(x11, q0_5, v_add(x51, x51)); - t10 = v_fma(x20, q0_25, x60); - t11 = v_fma(x21, q0_25, x61); - t00 = v_fma(x30, qm2_5, t00); - t01 = v_fma(x31, qm2_5, t01); - t10 = v_fma(x40, qm1_25, t10); - t11 = v_fma(x41, qm1_25, t11); - - v_float32x4 y30 = v_add(t00, t10), y31 = v_add(t01, t11); - v_float32x4 y40 = v_sub(t10, t00), y41 = v_sub(t11, t01); - - /* Y[5] = [0.f, 2.f, 4.f, -2.5f, -5.f, 0.5f, 1.f, 0.f]*X */ - /* Y[6] = [0.f, -2.f, 4.f, 2.5f, -5.f, -0.5f, 1.f, 0.f]*X */ - v_float32x4 q4 = v_setall_f32(4.f), qm5 = v_setall_f32(-5.f); - t00 = v_fma(x50, q0_5, v_add(x10, x10)); - t01 = v_fma(x51, q0_5, v_add(x11, x11)); - t10 = v_fma(x20, q4 , x60); - t11 = v_fma(x21, q4 , x61); - t00 = v_fma(x30, qm2_5, t00); - t01 = v_fma(x31, qm2_5, t01); - t10 = v_fma(x40, qm5 , t10); - t11 = v_fma(x41, qm5 , t11); - - v_float32x4 y50 = v_add(t00, t10), y51 = v_add(t01, t11); - v_float32x4 y60 = v_sub(t10, t00), y61 = v_sub(t11, t01); - - /* transpose 8x8 matrix with v_transpose4x4 */ - - v_float32x4 y000, y100, y200, y300, y010, y110, y210, y310, y400, y500, y600, y700, y410, y510, y610, y710; - v_transpose4x4(y00, y10, y20, y30, y000, y100, y200, y300); - v_transpose4x4(y01, y11, y21, y31, y010, y110, y210, y310); - v_transpose4x4(y40, y50, y60, y70, y400, y500, y600, y700); - v_transpose4x4(y41, y51, y61, y71, y410, y510, y610, y710); - - /* Z[0] = [1.f, 0.f, -5.25f, 0.f, 5.25f, 0.f, -1.f, 0.f]*Y */ - /* Z[7] = [0.f, -1.f, 0.f, 5.25f, 0.f, -5.25f, 0.f, 1.f]*Y */ - t00 = v_sub(y010, y200); - t01 = v_sub(y410, y600); - t10 = v_sub(y300, y110); - t11 = v_sub(y700, y510); - z00 = v_fma(t00, q5_25, v_sub(y000, y210)); - z01 = v_fma(t01, q5_25, v_sub(y400, y610)); - z70 = v_fma(t10, q5_25, v_sub(y310, y100)); - z71 = v_fma(t11, q5_25, v_sub(y710, y500)); - - /* Z[1] = [0.f, 1.f, 1.f, -4.25f, -4.25f, 1.f, 1.f, 0.f]*Y */ - /* Z[2] = [0.f, -1.f, 1.f, 4.25f, -4.25f, -1.f, 1.f, 0.f]*Y */ - t00 = v_fma(y300, qm4_25, v_add(y100, y110)); - t01 = v_fma(y700, qm4_25, v_add(y500, y510)); - t10 = v_fma(y010, qm4_25, v_add(y200, y210)); - t11 = v_fma(y410, qm4_25, v_add(y600, y610)); - - z10 = v_add(t00, t10); z11 = v_add(t01, t11); - z20 = v_sub(t10, t00); z21 = v_sub(t11, t01); - - /* Z[3] = [0.f, 0.5f, 0.25f, -2.5f, -1.25f, 2.f, 1.f, 0.f]*Y */ - /* Z[4] = [0.f, -0.5f, 0.25f, 2.5f, -1.25f, -2.f, 1.f, 0.f]*Y */ - t00 = v_fma(y100, q0_5, v_add(y110, y110)); - t01 = v_fma(y500, q0_5, v_add(y510, y510)); - t10 = v_fma(y200, q0_25, y210); - t11 = v_fma(y600, q0_25, y610); - t00 = v_fma(y300, qm2_5, t00); - t01 = v_fma(y700, qm2_5, t01); - t10 = v_fma(y010, qm1_25, t10); - t11 = v_fma(y410, qm1_25, t11); - - z30 = v_add(t00, t10); z31 = v_add(t01, t11); - z40 = v_sub(t10, t00); z41 = v_sub(t11, t01); - - /* Z[5] = [0.f, 2.f, 4.f, -2.5f, -5.f, 0.5f, 1.f, 0.f]*Y */ - /* Z[6] = [0.f, -2.f, 4.f, 2.5f, -5.f, -0.5f, 1.f, 0.f]*Y */ - t00 = v_fma(y110, q0_5, v_add(y100, y100)); - t01 = v_fma(y510, q0_5, v_add(y500, y500)); - t10 = v_fma(y200, q4, y210); - t11 = v_fma(y600, q4, y610); - t00 = v_fma(y300, qm2_5, t00); - t01 = v_fma(y700, qm2_5, t01); - t10 = v_fma(y010, qm5, t10); - t11 = v_fma(y410, qm5, t11); - - z50 = v_add(t00, t10); z51 = v_add(t01, t11); - z60 = v_sub(t10, t00); z61 = v_sub(t11, t01); - } - - const int outstep = winoIblock*winoAtomF32*Cg; - - v_store(outptr, z00); - v_store(outptr + outstep, z01); - v_store(outptr + outstep*2, z10); - v_store(outptr + outstep*3, z11); - v_store(outptr + outstep*4, z20); - v_store(outptr + outstep*5, z21); - v_store(outptr + outstep*6, z30); - v_store(outptr + outstep*7, z31); - v_store(outptr + outstep*8, z40); - v_store(outptr + outstep*9, z41); - v_store(outptr + outstep*10, z50); - v_store(outptr + outstep*11, z51); - v_store(outptr + outstep*12, z60); - v_store(outptr + outstep*13, z61); - v_store(outptr + outstep*14, z70); - v_store(outptr + outstep*15, z71); -} - -/*Output transform*/ -/* Inverse Winograd 8x8 transform: - out = (A'*inp*A)', where - inp is input 8x8 FP32 matrix, - A' is - [1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 0.f, - 0.f, 1.f, -1.f, 2.f, -2.f, 0.5f, -0.5f, 0.f, - 0.f, 1.f, 1.f, 4.f, 4.f, 0.25f, 0.25f, 0.f, - 0.f, 1.f, -1.f, 8.f, -8.f, 0.125f, -0.125f, 0.f, - 0.f, 1.f, 1.f, 16.f, 16.f, 1.f/16, 1.f/16, 0.f, - 0.f, 1.f, -1.f, 32.f, -32.f, 1.f/32, -1.f/32, 1.f] - - inp is pre-loaded into xij registers, - out will be stored in zij, where (0<=i<=7 for x, 0<=i<=5 for z), 0<=j<=1. - - After the inverse transform is done, we add bias, - optionally add results from the earlier tensors (by-pass), - optionally apply activation function and then - store the final results. - - That is, after both forward and then inverse transformation, - we get non-transposed result. - Of course, for the correct work of Winograd-based convolution, - the Winograd-transformed weights should also be transposed. - init_conv() (see OpConv.fx) takes care of that. -*/ -void winofunc_AtXA_8x8_F32(const float* inptr, int inpstep, - float* bpptr, int bpstep, float* outptr, int outstep, - float bias, float minval, float maxval, bool ifMinMaxAct) -{ - v_float32x4 x00 = v_load(inptr), x01 = v_load(inptr + 4); - v_float32x4 x10 = v_load(inptr + inpstep), x11 = v_load(inptr + inpstep + 4); - v_float32x4 x20 = v_load(inptr + inpstep*2), x21 = v_load(inptr + inpstep*2 + 4); - v_float32x4 x30 = v_load(inptr + inpstep*3), x31 = v_load(inptr + inpstep*3 + 4); - v_float32x4 x40 = v_load(inptr + inpstep*4), x41 = v_load(inptr + inpstep*4 + 4); - v_float32x4 x50 = v_load(inptr + inpstep*5), x51 = v_load(inptr + inpstep*5 + 4); - v_float32x4 x60 = v_load(inptr + inpstep*6), x61 = v_load(inptr + inpstep*6 + 4); - v_float32x4 x70 = v_load(inptr + inpstep*7), x71 = v_load(inptr + inpstep*7 + 4); - v_float32x4 z00, z01, z10, z11, z20, z21, z30, z31, z40, z41, z50, z51; - - { - v_float32x4 s12_0, s12_1, s34_0, s34_1, s56_0, s56_1; - s12_0 = v_add(x10, x20); s12_1 = v_add(x11, x21); - s34_0 = v_add(x30, x40); s34_1 = v_add(x31, x41); - s56_0 = v_add(x50, x60); s56_1 = v_add(x51, x61); - - v_float32x4 y00 = v_add(v_add(v_add(x00, s12_0), s34_0), s56_0); - v_float32x4 y01 = v_add(v_add(v_add(x01, s12_1), s34_1), s56_1); - - v_float32x4 a0 = v_setall_f32(0.25f), a1 = v_setall_f32(4.0f); - v_float32x4 y20 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); - v_float32x4 y21 = v_fma(s56_1, a0 ,v_fma(s34_1, a1, s12_1) ); - - a0 = v_setall_f32(1.f/16), a1 = v_setall_f32(16.0f); - v_float32x4 y40 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); - v_float32x4 y41 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); - - s12_0 = v_sub(x10, x20); s12_1 = v_sub(x11, x21); - s34_0 = v_sub(x30, x40); s34_1 = v_sub(x31, x41); - s56_0 = v_sub(x50, x60); s56_1 = v_sub(x51, x61); - - a0 = v_setall_f32(1.f/32), a1 = v_setall_f32(32.f); - v_float32x4 y50 = v_fma(s56_0, a0, v_fma(s34_0, a1, v_add(x70, s12_0))); - v_float32x4 y51 = v_fma(s56_1, a0, v_fma(s34_1, a1, v_add(x71, s12_1))); - - a0 = v_setall_f32(0.5f), a1 = v_setall_f32(2.f); - v_float32x4 y10 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); - v_float32x4 y11 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); - - a0 = v_setall_f32(0.125f), a1 = v_setall_f32(8.f); - v_float32x4 y30 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); - v_float32x4 y31 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); - - v_float32x4 y60 = v_setall_f32(0.f), y61 = y60, y70 = y60, y71 = y60; - - /* transpose 8x8 matrix with v_transpose4x4 */ - - v_float32x4 y000, y100, y200, y300, y010, y110, y210, y310, y400, y500, y600, y700, y410, y510, y610, y710; - v_transpose4x4(y00, y10, y20, y30, y000, y100, y200, y300); - v_transpose4x4(y01, y11, y21, y31, y010, y110, y210, y310); - v_transpose4x4(y40, y50, y60, y70, y400, y500, y600, y700); - v_transpose4x4(y41, y51, y61, y71, y410, y510, y610, y710); - - s12_0 = v_add(y100, y200); s12_1 = v_add(y500, y600); - s34_0 = v_add(y300, y010); s34_1 = v_add(y700, y410); - s56_0 = v_add(y110, y210); s56_1 = v_add(y510, y610); - - z00 = v_add(v_add(v_add(y000, s12_0), s34_0), s56_0); - z01 = v_add(v_add(v_add(y400, s12_1), s34_1), s56_1); - - a0 = v_setall_f32(0.25f), a1 = v_setall_f32(4.0f); - z20 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); - z21 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); - - a0 = v_setall_f32(1.f/16), a1 = v_setall_f32(16.0f); - z40 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); - z41 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); - - s12_0 = v_sub(y100, y200); s12_1 = v_sub(y500, y600); - s34_0 = v_sub(y300, y010); s34_1 = v_sub(y700, y410); - s56_0 = v_sub(y110, y210); s56_1 = v_sub(y510, y610); - - a0 = v_setall_f32(1.f/32), a1 = v_setall_f32(32.0f); - z50 = v_fma(s56_0, a0, v_fma(s34_0, a1, v_add(y310, s12_0))); - z51 = v_fma(s56_1, a0, v_fma(s34_1, a1, v_add(y710, s12_1))); - a0 = v_setall_f32(0.5f), a1 = v_setall_f32(2.0f); - z10 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); - z11 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); - - a0 = v_setall_f32(0.125f), a1 = v_setall_f32(8.0f); - z30 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); - z31 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); - - v_float32x4 vbias = v_setall_f32(bias); - z00 = v_add(z00, vbias); - z01 = v_add(z01, vbias); - z10 = v_add(z10, vbias); - z11 = v_add(z11, vbias); - z20 = v_add(z20, vbias); - z21 = v_add(z21, vbias); - z30 = v_add(z30, vbias); - z31 = v_add(z31, vbias); - z40 = v_add(z40, vbias); - z41 = v_add(z41, vbias); - z50 = v_add(z50, vbias); - z51 = v_add(z51, vbias); - } - - if (bpptr) - { - z00 = v_add(z00, v_load(bpptr)); - z01 = v_add(z01, v_load_low(bpptr + 4)); - z10 = v_add(z10, v_load(bpptr + bpstep)); - z11 = v_add(z11, v_load_low(bpptr + bpstep + 4)); - z20 = v_add(z20, v_load(bpptr + bpstep * 2)); - z21 = v_add(z21, v_load_low(bpptr + bpstep * 2 + 4)); - z30 = v_add(z30, v_load(bpptr + bpstep * 3)); - z31 = v_add(z31, v_load_low(bpptr + bpstep * 3 + 4)); - z40 = v_add(z40, v_load(bpptr + bpstep * 4)); - z41 = v_add(z41, v_load_low(bpptr + bpstep * 4 + 4)); - z50 = v_add(z50, v_load(bpptr + bpstep * 5)); - z51 = v_add(z51, v_load_low(bpptr + bpstep * 5 + 4)); - } - - if (ifMinMaxAct) - { - v_float32x4 vmax = v_setall_f32(maxval); - v_float32x4 vmin = v_setall_f32(minval); - - z00 = v_min(v_max(z00, vmin), vmax); - z01 = v_min(v_max(z01, vmin), vmax); - z10 = v_min(v_max(z10, vmin), vmax); - z11 = v_min(v_max(z11, vmin), vmax); - z20 = v_min(v_max(z20, vmin), vmax); - z21 = v_min(v_max(z21, vmin), vmax); - z30 = v_min(v_max(z30, vmin), vmax); - z31 = v_min(v_max(z31, vmin), vmax); - z40 = v_min(v_max(z40, vmin), vmax); - z41 = v_min(v_max(z41, vmin), vmax); - z50 = v_min(v_max(z50, vmin), vmax); - z51 = v_min(v_max(z51, vmin), vmax); - } - - v_store(outptr, z00); - v_store_low(outptr + 4, z01); - v_store(outptr + outstep, z10); - v_store_low(outptr + outstep + 4, z11); - v_store(outptr + outstep*2, z20); - v_store_low(outptr + outstep*2 + 4, z21); - v_store(outptr + outstep*3, z30); - v_store_low(outptr + outstep*3 + 4, z31); - v_store(outptr + outstep*4, z40); - v_store_low(outptr + outstep*4 + 4, z41); - v_store(outptr + outstep*5, z50); - v_store_low(outptr + outstep*5 + 4, z51); -} -#endif - -#else -int runWinograd63(InputArray _input, InputArray _fusedAddMat, OutputArray _output, const Ptr& conv, - int ntasks, float minval, float maxval, ActivationLayer* activ, bool ifMinMaxAct) -{ - return 0; -} -#endif - }} // namespace cv::dnn diff --git a/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.dispatch.cpp b/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.dispatch.cpp new file mode 100644 index 0000000000..d927a8ab77 --- /dev/null +++ b/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.dispatch.cpp @@ -0,0 +1,22 @@ +// 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 "convolution.hpp" +#include "conv_winograd_f63.simd.hpp" +#include "layers/cpu_kernels/conv_winograd_f63.simd_declarations.hpp" + +namespace cv { +namespace dnn { + +cv::dnn::Winofunc getWinofunc_F32() +{ + CV_CPU_DISPATCH(getWinofunc_F32, (), CV_CPU_DISPATCH_MODES_ALL); +} + +cv::dnn::Winofunc getWinofunc_F16() +{ + CV_CPU_DISPATCH(getWinofunc_F16, (), CV_CPU_DISPATCH_MODES_ALL); +} + +}} // namespace cv::dnn:: diff --git a/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.neon.cpp b/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.neon.cpp deleted file mode 100644 index 70b716f9c7..0000000000 --- a/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.neon.cpp +++ /dev/null @@ -1,476 +0,0 @@ -// 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 "../../precomp.hpp" -#include "convolution.hpp" -#include "opencv2/core/hal/intrin.hpp" - -namespace cv { -namespace dnn { - -// NEON code work around. -namespace opt_NEON -{ - -#if CV_NEON && CV_NEON_AARCH64 - -/* Accumulate */ -void winofunc_accum_F32(const float* inwptr, const float* wptr, float* outbuf, int Cg, int iblock, - const int winoIblock, const int winoKblock, const int winoAtomF32, const int winoNatomF32) -{ - CV_Assert(winoIblock == 6 && winoKblock == 4 && winoAtomF32 == 4); - if (iblock > 3) - { - for (int atom_id = 0; atom_id < winoNatomF32; atom_id++, - outbuf += winoAtomF32) - { - float32x4_t s00 = vdupq_n_f32(0.f), s01 = s00, s02 = s00, s03 = s00, s04 = s00, s05 = s00; - float32x4_t s10 = vdupq_n_f32(0.f), s11 = s00, s12 = s00, s13 = s00, s14 = s00, s15 = s00; - float32x4_t s20 = vdupq_n_f32(0.f), s21 = s00, s22 = s00, s23 = s00, s24 = s00, s25 = s00; - float32x4_t s30 = vdupq_n_f32(0.f), s31 = s00, s32 = s00, s33 = s00, s34 = s00, s35 = s00; - for (int c = 0; c < Cg; c++, inwptr += winoIblock*winoAtomF32, - wptr += winoKblock*winoAtomF32) { - float32x4_t w0 = vld1q_f32(wptr), w1 = vld1q_f32(wptr + 4); - float32x4_t w2 = vld1q_f32(wptr + 8), w3 = vld1q_f32(wptr + 12); - float32x4_t x0, x1; - x0 = vld1q_f32(inwptr); - x1 = vld1q_f32(inwptr + 4); - s00 = vfmaq_f32(s00, w0, x0); - s01 = vfmaq_f32(s01, w0, x1); - s10 = vfmaq_f32(s10, w1, x0); - s11 = vfmaq_f32(s11, w1, x1); - s20 = vfmaq_f32(s20, w2, x0); - s21 = vfmaq_f32(s21, w2, x1); - s30 = vfmaq_f32(s30, w3, x0); - s31 = vfmaq_f32(s31, w3, x1); - x0 = vld1q_f32(inwptr + 8); - x1 = vld1q_f32(inwptr + 12); - s02 = vfmaq_f32(s02, w0, x0); - s03 = vfmaq_f32(s03, w0, x1); - s12 = vfmaq_f32(s12, w1, x0); - s13 = vfmaq_f32(s13, w1, x1); - s22 = vfmaq_f32(s22, w2, x0); - s23 = vfmaq_f32(s23, w2, x1); - s32 = vfmaq_f32(s32, w3, x0); - s33 = vfmaq_f32(s33, w3, x1); - x0 = vld1q_f32(inwptr + 16); - x1 = vld1q_f32(inwptr + 20); - s04 = vfmaq_f32(s04, w0, x0); - s05 = vfmaq_f32(s05, w0, x1); - s14 = vfmaq_f32(s14, w1, x0); - s15 = vfmaq_f32(s15, w1, x1); - s24 = vfmaq_f32(s24, w2, x0); - s25 = vfmaq_f32(s25, w2, x1); - s34 = vfmaq_f32(s34, w3, x0); - s35 = vfmaq_f32(s35, w3, x1); - } - - vst1q_f32(outbuf, s00); - vst1q_f32(outbuf + 1*64, s01); - vst1q_f32(outbuf + 2*64, s02); - vst1q_f32(outbuf + 3*64, s03); - vst1q_f32(outbuf + 4*64, s04); - vst1q_f32(outbuf + 5*64, s05); - - vst1q_f32(outbuf + 6*64, s10); - vst1q_f32(outbuf + 7*64, s11); - vst1q_f32(outbuf + 8*64, s12); - vst1q_f32(outbuf + 9*64, s13); - vst1q_f32(outbuf + 10*64, s14); - vst1q_f32(outbuf + 11*64, s15); - - vst1q_f32(outbuf + 12*64, s20); - vst1q_f32(outbuf + 13*64, s21); - vst1q_f32(outbuf + 14*64, s22); - vst1q_f32(outbuf + 15*64, s23); - vst1q_f32(outbuf + 16*64, s24); - vst1q_f32(outbuf + 17*64, s25); - - vst1q_f32(outbuf + 18*64, s30); - vst1q_f32(outbuf + 19*64, s31); - vst1q_f32(outbuf + 20*64, s32); - vst1q_f32(outbuf + 21*64, s33); - vst1q_f32(outbuf + 22*64, s34); - vst1q_f32(outbuf + 23*64, s35); - } - } - else - { - for (int atom_id = 0; atom_id < winoNatomF32; atom_id++, - outbuf += winoAtomF32) - { - float32x4_t s00 = vdupq_n_f32(0.f), s01 = s00, s02 = s00; - float32x4_t s10 = vdupq_n_f32(0.f), s11 = s00, s12 = s00; - float32x4_t s20 = vdupq_n_f32(0.f), s21 = s00, s22 = s00; - float32x4_t s30 = vdupq_n_f32(0.f), s31 = s00, s32 = s00; - for (int c = 0; c < Cg; c++, inwptr += winoIblock*winoAtomF32, - wptr += winoKblock*winoAtomF32) { - float32x4_t w0 = vld1q_f32(wptr), w1 = vld1q_f32(wptr + 4); - float32x4_t w2 = vld1q_f32(wptr + 8), w3 = vld1q_f32(wptr + 12); - float32x4_t x0, x1, x2; - x0 = vld1q_f32(inwptr); - x1 = vld1q_f32(inwptr + 4); - x2 = vld1q_f32(inwptr + 8); - s00 = vfmaq_f32(s00, w0, x0); - s01 = vfmaq_f32(s01, w0, x1); - s02 = vfmaq_f32(s02, w0, x2); - s10 = vfmaq_f32(s10, w1, x0); - s11 = vfmaq_f32(s11, w1, x1); - s12 = vfmaq_f32(s12, w1, x2); - s20 = vfmaq_f32(s20, w2, x0); - s21 = vfmaq_f32(s21, w2, x1); - s22 = vfmaq_f32(s22, w2, x2); - s30 = vfmaq_f32(s30, w3, x0); - s31 = vfmaq_f32(s31, w3, x1); - s32 = vfmaq_f32(s32, w3, x2); - } - - vst1q_f32(outbuf, s00); - vst1q_f32(outbuf + 1*64, s01); - vst1q_f32(outbuf + 2*64, s02); - vst1q_f32(outbuf + 6*64, s10); - vst1q_f32(outbuf + 7*64, s11); - vst1q_f32(outbuf + 8*64, s12); - vst1q_f32(outbuf + 12*64, s20); - vst1q_f32(outbuf + 13*64, s21); - vst1q_f32(outbuf + 14*64, s22); - vst1q_f32(outbuf + 18*64, s30); - vst1q_f32(outbuf + 19*64, s31); - vst1q_f32(outbuf + 20*64, s32); - } - } -} - -#undef T4x4 -#define T4x4(a, b, c, d, tr0, tr1) \ - tr0 = vtrnq_f32(a, b); \ - tr1 = vtrnq_f32(c, d); \ - a = vcombine_f32(vget_low_f32(tr0.val[0]), vget_low_f32(tr1.val[0])); \ - b = vcombine_f32(vget_low_f32(tr0.val[1]), vget_low_f32(tr1.val[1])); \ - c = vcombine_f32(vget_high_f32(tr0.val[0]), vget_high_f32(tr1.val[0])); \ - d = vcombine_f32(vget_high_f32(tr0.val[1]), vget_high_f32(tr1.val[1])) - -/*Input transform*/ -void winofunc_BtXB_8x8_F32(const float* inptr, int inpstep, - float* outptr, int Cg, const int winoIblock, const int winoAtomF32) -{ - float32x4_t x00 = vld1q_f32(inptr), x01 = vld1q_f32(inptr + 4); - float32x4_t x10 = vld1q_f32(inptr + inpstep), x11 = vld1q_f32(inptr + inpstep + 4); - float32x4_t x20 = vld1q_f32(inptr + inpstep*2), x21 = vld1q_f32(inptr + inpstep*2 + 4); - float32x4_t x30 = vld1q_f32(inptr + inpstep*3), x31 = vld1q_f32(inptr + inpstep*3 + 4); - float32x4_t x40 = vld1q_f32(inptr + inpstep*4), x41 = vld1q_f32(inptr + inpstep*4 + 4); - float32x4_t x50 = vld1q_f32(inptr + inpstep*5), x51 = vld1q_f32(inptr + inpstep*5 + 4); - float32x4_t x60 = vld1q_f32(inptr + inpstep*6), x61 = vld1q_f32(inptr + inpstep*6 + 4); - float32x4_t x70 = vld1q_f32(inptr + inpstep*7), x71 = vld1q_f32(inptr + inpstep*7 + 4); - - float32x4_t z00, z01, z10, z11, z20, z21, z30, z31, z40, z41, z50, z51, z60, z61, z70, z71; - - { - /* Y[0] = [1.f, 0.f, -5.25f, 0.f, 5.25f, 0.f, -1.f, 0.f]*X */ - /* Y[7] = [0.f, -1.f, 0.f, 5.25f, 0.f, -5.25f, 0.f, 1.f]*X */ - float32x4_t q5_25 = vdupq_n_f32(5.25f), t00, t01, t10, t11; - t00 = vsubq_f32(x40, x20); - t01 = vsubq_f32(x41, x21); - t10 = vsubq_f32(x30, x50); - t11 = vsubq_f32(x31, x51); - float32x4_t y00 = vfmaq_f32(vsubq_f32(x00, x60), t00, q5_25); - float32x4_t y01 = vfmaq_f32(vsubq_f32(x01, x61), t01, q5_25); - float32x4_t y70 = vfmaq_f32(vsubq_f32(x70, x10), t10, q5_25); - float32x4_t y71 = vfmaq_f32(vsubq_f32(x71, x11), t11, q5_25); - - /* Y[1] = [0.f, 1.f, 1.f, -4.25f, -4.25f, 1.f, 1.f, 0.f]*X */ - /* Y[2] = [0.f, -1.f, 1.f, 4.25f, -4.25f, -1.f, 1.f, 0.f]*X */ - float32x4_t qm4_25 = vdupq_n_f32(-4.25f); - t00 = vfmaq_f32(vaddq_f32(x10, x50), x30, qm4_25); - t01 = vfmaq_f32(vaddq_f32(x11, x51), x31, qm4_25); - t10 = vfmaq_f32(vaddq_f32(x20, x60), x40, qm4_25); - t11 = vfmaq_f32(vaddq_f32(x21, x61), x41, qm4_25); - - float32x4_t y10 = vaddq_f32(t00, t10), y11 = vaddq_f32(t01, t11); - float32x4_t y20 = vsubq_f32(t10, t00), y21 = vsubq_f32(t11, t01); - - /* Y[3] = [0.f, 0.5f, 0.25f, -2.5f, -1.25f, 2.f, 1.f, 0.f]*X */ - /* Y[4] = [0.f, -0.5f, 0.25f, 2.5f, -1.25f, -2.f, 1.f, 0.f]*X */ - float32x4_t q0_5 = vdupq_n_f32(0.5f), q0_25 = vdupq_n_f32(0.25f); - float32x4_t qm2_5 = vdupq_n_f32(-2.5f), qm1_25 = vdupq_n_f32(-1.25f); - t00 = vfmaq_f32(vaddq_f32(x50, x50), x10, q0_5); - t01 = vfmaq_f32(vaddq_f32(x51, x51), x11, q0_5); - t10 = vfmaq_f32(x60, x20, q0_25); - t11 = vfmaq_f32(x61, x21, q0_25); - t00 = vfmaq_f32(t00, x30, qm2_5); - t01 = vfmaq_f32(t01, x31, qm2_5); - t10 = vfmaq_f32(t10, x40, qm1_25); - t11 = vfmaq_f32(t11, x41, qm1_25); - - float32x4_t y30 = vaddq_f32(t00, t10), y31 = vaddq_f32(t01, t11); - float32x4_t y40 = vsubq_f32(t10, t00), y41 = vsubq_f32(t11, t01); - - /* Y[5] = [0.f, 2.f, 4.f, -2.5f, -5.f, 0.5f, 1.f, 0.f]*X */ - /* Y[6] = [0.f, -2.f, 4.f, 2.5f, -5.f, -0.5f, 1.f, 0.f]*X */ - float32x4_t q4 = vdupq_n_f32(4.f), qm5 = vdupq_n_f32(-5.f); - t00 = vfmaq_f32(vaddq_f32(x10, x10), x50, q0_5); - t01 = vfmaq_f32(vaddq_f32(x11, x11), x51, q0_5); - t10 = vfmaq_f32(x60, x20, q4); - t11 = vfmaq_f32(x61, x21, q4); - t00 = vfmaq_f32(t00, x30, qm2_5); - t01 = vfmaq_f32(t01, x31, qm2_5); - t10 = vfmaq_f32(t10, x40, qm5); - t11 = vfmaq_f32(t11, x41, qm5); - - float32x4_t y50 = vaddq_f32(t00, t10), y51 = vaddq_f32(t01, t11); - float32x4_t y60 = vsubq_f32(t10, t00), y61 = vsubq_f32(t11, t01); - - /* transpose 8x8 matrix in-place with some renumeration of the elements: */ - /* Y: */ - /* y00 y01 */ - /* y10 y11 */ - /* ... */ - /* y70 y71 */ - /* Y': */ - /* y00 y40 */ - /* y10 y50 */ - /* y20 y60 */ - /* y30 y70 */ - /* y01 y41 */ - /* y11 y51 */ - /* y21 y61 */ - /* y31 y71 */ - /* in other words, y40 <-> y01, y50 <-> y11, y60 <-> y21, y70 <-> y31 */ - float32x4x2_t tr0, tr1; - - T4x4(y00, y10, y20, y30, tr0, tr1); - T4x4(y01, y11, y21, y31, tr0, tr1); - T4x4(y40, y50, y60, y70, tr0, tr1); - T4x4(y41, y51, y61, y71, tr0, tr1); - - /* Z[0] = [1.f, 0.f, -5.25f, 0.f, 5.25f, 0.f, -1.f, 0.f]*Y */ - /* Z[7] = [0.f, -1.f, 0.f, 5.25f, 0.f, -5.25f, 0.f, 1.f]*Y */ - t00 = vsubq_f32(y01, y20); - t01 = vsubq_f32(y41, y60); - t10 = vsubq_f32(y30, y11); - t11 = vsubq_f32(y70, y51); - z00 = vfmaq_f32(vsubq_f32(y00, y21), t00, q5_25); - z01 = vfmaq_f32(vsubq_f32(y40, y61), t01, q5_25); - z70 = vfmaq_f32(vsubq_f32(y31, y10), t10, q5_25); - z71 = vfmaq_f32(vsubq_f32(y71, y50), t11, q5_25); - - /* Z[1] = [0.f, 1.f, 1.f, -4.25f, -4.25f, 1.f, 1.f, 0.f]*Y */ - /* Z[2] = [0.f, -1.f, 1.f, 4.25f, -4.25f, -1.f, 1.f, 0.f]*Y */ - t00 = vfmaq_f32(vaddq_f32(y10, y11), y30, qm4_25); - t01 = vfmaq_f32(vaddq_f32(y50, y51), y70, qm4_25); - t10 = vfmaq_f32(vaddq_f32(y20, y21), y01, qm4_25); - t11 = vfmaq_f32(vaddq_f32(y60, y61), y41, qm4_25); - - z10 = vaddq_f32(t00, t10); z11 = vaddq_f32(t01, t11); - z20 = vsubq_f32(t10, t00); z21 = vsubq_f32(t11, t01); - - /* Z[3] = [0.f, 0.5f, 0.25f, -2.5f, -1.25f, 2.f, 1.f, 0.f]*Y */ - /* Z[4] = [0.f, -0.5f, 0.25f, 2.5f, -1.25f, -2.f, 1.f, 0.f]*Y */ - t00 = vfmaq_f32(vaddq_f32(y11, y11), y10, q0_5); - t01 = vfmaq_f32(vaddq_f32(y51, y51), y50, q0_5); - t10 = vfmaq_f32(y21, y20, q0_25); - t11 = vfmaq_f32(y61, y60, q0_25); - t00 = vfmaq_f32(t00, y30, qm2_5); - t01 = vfmaq_f32(t01, y70, qm2_5); - t10 = vfmaq_f32(t10, y01, qm1_25); - t11 = vfmaq_f32(t11, y41, qm1_25); - - z30 = vaddq_f32(t00, t10); z31 = vaddq_f32(t01, t11); - z40 = vsubq_f32(t10, t00); z41 = vsubq_f32(t11, t01); - - /* Z[5] = [0.f, 2.f, 4.f, -2.5f, -5.f, 0.5f, 1.f, 0.f]*Y */ - /* Z[6] = [0.f, -2.f, 4.f, 2.5f, -5.f, -0.5f, 1.f, 0.f]*Y */ - t00 = vfmaq_f32(vaddq_f32(y10, y10), y11, q0_5); - t01 = vfmaq_f32(vaddq_f32(y50, y50), y51, q0_5); - t10 = vfmaq_f32(y21, y20, q4); - t11 = vfmaq_f32(y61, y60, q4); - t00 = vfmaq_f32(t00, y30, qm2_5); - t01 = vfmaq_f32(t01, y70, qm2_5); - t10 = vfmaq_f32(t10, y01, qm5); - t11 = vfmaq_f32(t11, y41, qm5); - - z50 = vaddq_f32(t00, t10); z51 = vaddq_f32(t01, t11); - z60 = vsubq_f32(t10, t00); z61 = vsubq_f32(t11, t01); - } - - const int outstep = winoIblock*winoAtomF32*Cg; - - vst1q_f32(outptr, z00); - vst1q_f32(outptr + outstep, z01); - vst1q_f32(outptr + outstep*2, z10); - vst1q_f32(outptr + outstep*3, z11); - vst1q_f32(outptr + outstep*4, z20); - vst1q_f32(outptr + outstep*5, z21); - vst1q_f32(outptr + outstep*6, z30); - vst1q_f32(outptr + outstep*7, z31); - vst1q_f32(outptr + outstep*8, z40); - vst1q_f32(outptr + outstep*9, z41); - vst1q_f32(outptr + outstep*10, z50); - vst1q_f32(outptr + outstep*11, z51); - vst1q_f32(outptr + outstep*12, z60); - vst1q_f32(outptr + outstep*13, z61); - vst1q_f32(outptr + outstep*14, z70); - vst1q_f32(outptr + outstep*15, z71); -} - -/*Output transform*/ -void winofunc_AtXA_8x8_F32(const float* inptr, int inpstep, - float* bpptr, int bpstep, float* outptr, int outstep, - float bias, float minval, float maxval, bool ifMinMaxAct) -{ - float32x4_t x00 = vld1q_f32(inptr), x01 = vld1q_f32(inptr + 4); - float32x4_t x10 = vld1q_f32(inptr + inpstep), x11 = vld1q_f32(inptr + inpstep + 4); - float32x4_t x20 = vld1q_f32(inptr + inpstep*2), x21 = vld1q_f32(inptr + inpstep*2 + 4); - float32x4_t x30 = vld1q_f32(inptr + inpstep*3), x31 = vld1q_f32(inptr + inpstep*3 + 4); - float32x4_t x40 = vld1q_f32(inptr + inpstep*4), x41 = vld1q_f32(inptr + inpstep*4 + 4); - float32x4_t x50 = vld1q_f32(inptr + inpstep*5), x51 = vld1q_f32(inptr + inpstep*5 + 4); - float32x4_t x60 = vld1q_f32(inptr + inpstep*6), x61 = vld1q_f32(inptr + inpstep*6 + 4); - float32x4_t x70 = vld1q_f32(inptr + inpstep*7), x71 = vld1q_f32(inptr + inpstep*7 + 4); - float32x4_t z00, z01, z10, z11, z20, z21, z30, z31, z40, z41, z50, z51; - - { - float32x4_t s12_0, s12_1, s34_0, s34_1, s56_0, s56_1; - s12_0 = vaddq_f32(x10, x20); s12_1 = vaddq_f32(x11, x21); - s34_0 = vaddq_f32(x30, x40); s34_1 = vaddq_f32(x31, x41); - s56_0 = vaddq_f32(x50, x60); s56_1 = vaddq_f32(x51, x61); - - float32x4_t y00 = vaddq_f32(vaddq_f32(vaddq_f32(x00, s12_0), s34_0), s56_0); - float32x4_t y01 = vaddq_f32(vaddq_f32(vaddq_f32(x01, s12_1), s34_1), s56_1); - float32x4_t y20 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 4.0f), s56_0, 0.25f); - float32x4_t y21 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 4.0f), s56_1, 0.25f); - float32x4_t y40 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 16.0f), s56_0, 1.f/16); - float32x4_t y41 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 16.0f), s56_1, 1.f/16); - - s12_0 = vsubq_f32(x10, x20); s12_1 = vsubq_f32(x11, x21); - s34_0 = vsubq_f32(x30, x40); s34_1 = vsubq_f32(x31, x41); - s56_0 = vsubq_f32(x50, x60); s56_1 = vsubq_f32(x51, x61); - - float32x4_t y50 = vfmaq_n_f32(vfmaq_n_f32(vaddq_f32(x70, s12_0), - s34_0, 32.f), s56_0, 1.f/32); - float32x4_t y51 = vfmaq_n_f32(vfmaq_n_f32(vaddq_f32(x71, s12_1), - s34_1, 32.f), s56_1, 1.f/32); - float32x4_t y10 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 2.0f), s56_0, 0.5f); - float32x4_t y11 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 2.0f), s56_1, 0.5f); - float32x4_t y30 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 8.0f), s56_0, 0.125f); - float32x4_t y31 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 8.0f), s56_1, 0.125f); - float32x4_t y60 = vdupq_n_f32(0.f), y61 = y60, y70 = y60, y71 = y60; - - /* transpose 8x8 matrix in-place with some renumeration of the elements: */ - /* Y: */ - /* y00 y01 */ - /* y10 y11 */ - /* ... */ - /* y50 y51 */ - /* 0 0 */ - /* 0 0 */ - /* Y': */ - /* y00 y40 */ - /* y10 y50 */ - /* y20 y60 */ - /* y30 y70 */ - /* y01 y41 */ - /* y11 y51 */ - /* y21 y61 */ - /* y31 y71 */ - /* in other words, y40 <-> y01, y50 <-> y11, y60 <-> y21, y70 <-> y31 */ - float32x4x2_t tr0, tr1; - - T4x4(y00, y10, y20, y30, tr0, tr1); - T4x4(y01, y11, y21, y31, tr0, tr1); - T4x4(y40, y50, y60, y70, tr0, tr1); - T4x4(y41, y51, y61, y71, tr0, tr1); - - s12_0 = vaddq_f32(y10, y20); s12_1 = vaddq_f32(y50, y60); - s34_0 = vaddq_f32(y30, y01); s34_1 = vaddq_f32(y70, y41); - s56_0 = vaddq_f32(y11, y21); s56_1 = vaddq_f32(y51, y61); - - z00 = vaddq_f32(vaddq_f32(vaddq_f32(y00, s12_0), s34_0), s56_0); - z01 = vaddq_f32(vaddq_f32(vaddq_f32(y40, s12_1), s34_1), s56_1); - z20 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 4.0f), s56_0, 0.25f); - z21 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 4.0f), s56_1, 0.25f); - z40 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 16.0f), s56_0, 1.f/16); - z41 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 16.0f), s56_1, 1.f/16); - - s12_0 = vsubq_f32(y10, y20); s12_1 = vsubq_f32(y50, y60); - s34_0 = vsubq_f32(y30, y01); s34_1 = vsubq_f32(y70, y41); - s56_0 = vsubq_f32(y11, y21); s56_1 = vsubq_f32(y51, y61); - - z50 = vfmaq_n_f32(vfmaq_n_f32(vaddq_f32(y31, s12_0), - s34_0, 32.f), s56_0, 1.f/32); - z51 = vfmaq_n_f32(vfmaq_n_f32(vaddq_f32(y71, s12_1), - s34_1, 32.f), s56_1, 1.f/32); - z10 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 2.0f), s56_0, 0.5f); - z11 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 2.0f), s56_1, 0.5f); - z30 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 8.0f), s56_0, 0.125f); - z31 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 8.0f), s56_1, 0.125f); - float32x4_t vbias = vdupq_n_f32(bias); - - z00 = vaddq_f32(z00, vbias); - z01 = vaddq_f32(z01, vbias); - z10 = vaddq_f32(z10, vbias); - z11 = vaddq_f32(z11, vbias); - z20 = vaddq_f32(z20, vbias); - z21 = vaddq_f32(z21, vbias); - z30 = vaddq_f32(z30, vbias); - z31 = vaddq_f32(z31, vbias); - z40 = vaddq_f32(z40, vbias); - z41 = vaddq_f32(z41, vbias); - z50 = vaddq_f32(z50, vbias); - z51 = vaddq_f32(z51, vbias); - } - - if (bpptr) - { - float32x2_t zhalf = vdup_n_f32(0.f); - z00 = vaddq_f32(z00, vld1q_f32(bpptr)); - z01 = vaddq_f32(z01, vcombine_f32(vld1_f32(bpptr + 4), zhalf)); - z10 = vaddq_f32(z10, vld1q_f32(bpptr + bpstep)); - z11 = vaddq_f32(z11, vcombine_f32(vld1_f32(bpptr + bpstep + 4), zhalf)); - z20 = vaddq_f32(z20, vld1q_f32(bpptr + bpstep*2)); - z21 = vaddq_f32(z21, vcombine_f32(vld1_f32(bpptr + bpstep*2 + 4), zhalf)); - z30 = vaddq_f32(z30, vld1q_f32(bpptr + bpstep*3)); - z31 = vaddq_f32(z31, vcombine_f32(vld1_f32(bpptr + bpstep*3 + 4), zhalf)); - z40 = vaddq_f32(z40, vld1q_f32(bpptr + bpstep*4)); - z41 = vaddq_f32(z41, vcombine_f32(vld1_f32(bpptr + bpstep*4 + 4), zhalf)); - z50 = vaddq_f32(z50, vld1q_f32(bpptr + bpstep*5)); - z51 = vaddq_f32(z51, vcombine_f32(vld1_f32(bpptr + bpstep*5 + 4), zhalf)); - } - - if (ifMinMaxAct) - { - float32x4_t vmax = vdupq_n_f32(maxval); - float32x4_t vmin = vdupq_n_f32(minval); - - z00 = vminq_f32(vmaxq_f32(z00, vmin), vmax); - z01 = vminq_f32(vmaxq_f32(z01, vmin), vmax); - z10 = vminq_f32(vmaxq_f32(z10, vmin), vmax); - z11 = vminq_f32(vmaxq_f32(z11, vmin), vmax); - z20 = vminq_f32(vmaxq_f32(z20, vmin), vmax); - z21 = vminq_f32(vmaxq_f32(z21, vmin), vmax); - z30 = vminq_f32(vmaxq_f32(z30, vmin), vmax); - z31 = vminq_f32(vmaxq_f32(z31, vmin), vmax); - z40 = vminq_f32(vmaxq_f32(z40, vmin), vmax); - z41 = vminq_f32(vmaxq_f32(z41, vmin), vmax); - z50 = vminq_f32(vmaxq_f32(z50, vmin), vmax); - z51 = vminq_f32(vmaxq_f32(z51, vmin), vmax); - } - - vst1q_f32(outptr, z00); - vst1_f32(outptr + 4, vget_low_f32(z01)); - vst1q_f32(outptr + outstep, z10); - vst1_f32(outptr + outstep + 4, vget_low_f32(z11)); - vst1q_f32(outptr + outstep*2, z20); - vst1_f32(outptr + outstep*2 + 4, vget_low_f32(z21)); - vst1q_f32(outptr + outstep*3, z30); - vst1_f32(outptr + outstep*3 + 4, vget_low_f32(z31)); - vst1q_f32(outptr + outstep*4, z40); - vst1_f32(outptr + outstep*4 + 4, vget_low_f32(z41)); - vst1q_f32(outptr + outstep*5, z50); - vst1_f32(outptr + outstep*5 + 4, vget_low_f32(z51)); -} - -#endif -} - -}} // namespace diff --git a/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.simd.hpp b/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.simd.hpp index e44d0f8004..cea726a374 100644 --- a/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.simd.hpp +++ b/modules/dnn/src/layers/cpu_kernels/conv_winograd_f63.simd.hpp @@ -3,45 +3,44 @@ // of this distribution and at http://opencv.org/license.html. #include "opencv2/core/hal/intrin.hpp" +#include "convolution.hpp" + +// === dispatched calls (implemented here) namespace cv { namespace dnn { CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN -/* Accumulate */ -void winofunc_accum_F32(const float* inwptr, const float* wptr, float* outbuf, int Cg, int iblock, - const int winoIblock, const int winoKblock, const int winoAtomF32, const int winoNatomF32); +cv::dnn::Winofunc getWinofunc_F32(); +cv::dnn::Winofunc getWinofunc_F16(); -/*Input transform*/ -void winofunc_BtXB_8x8_F32(const float* inptr, int inpstep, - float* outptr, int Cg, const int winoIblock, const int winoAtomF32); +CV_CPU_OPTIMIZATION_NAMESPACE_END +}} // cv::dnn:: -/*Output transform*/ -void winofunc_AtXA_8x8_F32(const float* inptr, int inpstep, - float* bpptr, int bpstep, float* outptr, int outstep, - float bias, float minval, float maxval, bool ifMinMaxAct); +// === implementation -// FP 16 branch, only ARMv8 supports. -void winofunc_accum_F16(const char* _inwptr, const char* _wptr, char* _outbuf, int Cg, int iblock, - const int winoIblock, const int winoKblock, const int winoAtomF16, const int winoNatomF16); -void winofunc_BtXB_8x8_F16(const float * inptr, int inpstep, - char * _outptr, int Cg, const int winoIblock, const int winoAtomF16); -void winofunc_AtXA_8x8_F16(const char* inptr, int inpstep, - float * bpptr, int bpstep, float* outptr, int outstep, - float bias, float minval, float maxval, bool ifMinMaxAct); +#ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY -#if !defined(CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY) +namespace cv { +namespace dnn { +CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN + + +#if defined(CV_CPU_COMPILE_AVX) && CV_CPU_COMPILE_AVX || defined(CV_CPU_COMPILE_AVX2) && CV_CPU_COMPILE_AVX2 -#if CV_AVX #if !CV_FMA3 // AVX workaround #undef _mm256_fmadd_ps #define _mm256_fmadd_ps(a, b, c) _mm256_add_ps(c, _mm256_mul_ps(a, b)) #endif -void winofunc_accum_F32(const float* inwptr, const float* wptr, float* outbuf, int Cg, int iblock, +void impl_accum_F32(const uchar* inwptr_, const uchar* wptr_, uchar* outbuf_, int Cg, int iblock, const int winoIblock, const int winoKblock, const int winoAtomF32, const int winoNatomF32) { + const float * inwptr = (float*)inwptr_; + const float * wptr = (float*)wptr_; + float * outbuf = (float*)outbuf_; + CV_Assert(winoIblock == 6 && winoKblock == 4 && winoAtomF32 == 8); if (iblock > 3) { @@ -166,6 +165,7 @@ void winofunc_accum_F32(const float* inwptr, const float* wptr, float* outbuf, i } _mm256_zeroupper(); } + static inline void transpose8_ps(__m256 &row0, __m256 &row1, __m256 &row2, __m256 &row3, __m256 &row4, __m256 &row5, __m256 &row6, __m256 &row7) { @@ -198,9 +198,11 @@ void transpose8_ps(__m256 &row0, __m256 &row1, __m256 &row2, __m256 &row3, __m25 } /*Input transform*/ -void winofunc_BtXB_8x8_F32(const float* inptr, int inpstep, - float* outptr, int Cg, const int winoIblock, const int winoAtomF32) +void impl_BtXB_8x8_F32(const float* inptr, int inpstep, + uchar* outptr_, int Cg, const int winoIblock, const int winoAtomF32) { + float * outptr = (float*)outptr_; + __m256 x00 = _mm256_loadu_ps(inptr); __m256 x10 = _mm256_loadu_ps(inptr + inpstep); __m256 x20 = _mm256_loadu_ps(inptr + inpstep*2); @@ -322,10 +324,11 @@ void winofunc_BtXB_8x8_F32(const float* inptr, int inpstep, 0.f, 1.f, 1.f, 16.f, 16.f, 1.f/16, 1.f/16, 0.f, 0.f, 1.f, -1.f, 32.f, -32.f, 1.f/32, -1.f/32, 1.f] */ -void winofunc_AtXA_8x8_F32(const float* inptr, int inpstep, +void impl_AtXA_8x8_F32(const uchar* inptr_, int inpstep, float* bpptr, int bpstep, float* outptr, int outstep, float bias, float minval, float maxval, bool ifMinMaxAct) { + const float * inptr = (float*)inptr_; __m256 x00 = _mm256_load_ps(inptr); __m256 x10 = _mm256_load_ps(inptr + inpstep); @@ -417,10 +420,940 @@ void winofunc_AtXA_8x8_F32(const float* inptr, int inpstep, _mm256_zeroupper(); } -#endif // CV_AVX +cv::dnn::Winofunc getWinofunc_F32() +{ + return {&impl_accum_F32, &impl_BtXB_8x8_F32, &impl_AtXA_8x8_F32, 6, 8, 4}; +} + + +// end of AVX/AVX2 +#elif defined(CV_CPU_COMPILE_NEON) && CV_CPU_COMPILE_NEON && defined(CV_NEON_AARCH64) && CV_NEON_AARCH64 + + +/* Accumulate */ +void impl_accum_F32(const uchar* inwptr_, const uchar* wptr_, uchar* outbuf_, int Cg, int iblock, + const int winoIblock, const int winoKblock, const int winoAtomF32, const int winoNatomF32) +{ + const float * inwptr = (float*)inwptr_; + const float * wptr = (float*)wptr_; + float * outbuf = (float*)outbuf_; + + CV_Assert(winoIblock == 6 && winoKblock == 4 && winoAtomF32 == 4); + if (iblock > 3) + { + for (int atom_id = 0; atom_id < winoNatomF32; atom_id++, + outbuf += winoAtomF32) + { + float32x4_t s00 = vdupq_n_f32(0.f), s01 = s00, s02 = s00, s03 = s00, s04 = s00, s05 = s00; + float32x4_t s10 = vdupq_n_f32(0.f), s11 = s00, s12 = s00, s13 = s00, s14 = s00, s15 = s00; + float32x4_t s20 = vdupq_n_f32(0.f), s21 = s00, s22 = s00, s23 = s00, s24 = s00, s25 = s00; + float32x4_t s30 = vdupq_n_f32(0.f), s31 = s00, s32 = s00, s33 = s00, s34 = s00, s35 = s00; + for (int c = 0; c < Cg; c++, inwptr += winoIblock*winoAtomF32, + wptr += winoKblock*winoAtomF32) { + float32x4_t w0 = vld1q_f32(wptr), w1 = vld1q_f32(wptr + 4); + float32x4_t w2 = vld1q_f32(wptr + 8), w3 = vld1q_f32(wptr + 12); + float32x4_t x0, x1; + x0 = vld1q_f32(inwptr); + x1 = vld1q_f32(inwptr + 4); + s00 = vfmaq_f32(s00, w0, x0); + s01 = vfmaq_f32(s01, w0, x1); + s10 = vfmaq_f32(s10, w1, x0); + s11 = vfmaq_f32(s11, w1, x1); + s20 = vfmaq_f32(s20, w2, x0); + s21 = vfmaq_f32(s21, w2, x1); + s30 = vfmaq_f32(s30, w3, x0); + s31 = vfmaq_f32(s31, w3, x1); + x0 = vld1q_f32(inwptr + 8); + x1 = vld1q_f32(inwptr + 12); + s02 = vfmaq_f32(s02, w0, x0); + s03 = vfmaq_f32(s03, w0, x1); + s12 = vfmaq_f32(s12, w1, x0); + s13 = vfmaq_f32(s13, w1, x1); + s22 = vfmaq_f32(s22, w2, x0); + s23 = vfmaq_f32(s23, w2, x1); + s32 = vfmaq_f32(s32, w3, x0); + s33 = vfmaq_f32(s33, w3, x1); + x0 = vld1q_f32(inwptr + 16); + x1 = vld1q_f32(inwptr + 20); + s04 = vfmaq_f32(s04, w0, x0); + s05 = vfmaq_f32(s05, w0, x1); + s14 = vfmaq_f32(s14, w1, x0); + s15 = vfmaq_f32(s15, w1, x1); + s24 = vfmaq_f32(s24, w2, x0); + s25 = vfmaq_f32(s25, w2, x1); + s34 = vfmaq_f32(s34, w3, x0); + s35 = vfmaq_f32(s35, w3, x1); + } + + vst1q_f32(outbuf, s00); + vst1q_f32(outbuf + 1*64, s01); + vst1q_f32(outbuf + 2*64, s02); + vst1q_f32(outbuf + 3*64, s03); + vst1q_f32(outbuf + 4*64, s04); + vst1q_f32(outbuf + 5*64, s05); + + vst1q_f32(outbuf + 6*64, s10); + vst1q_f32(outbuf + 7*64, s11); + vst1q_f32(outbuf + 8*64, s12); + vst1q_f32(outbuf + 9*64, s13); + vst1q_f32(outbuf + 10*64, s14); + vst1q_f32(outbuf + 11*64, s15); + + vst1q_f32(outbuf + 12*64, s20); + vst1q_f32(outbuf + 13*64, s21); + vst1q_f32(outbuf + 14*64, s22); + vst1q_f32(outbuf + 15*64, s23); + vst1q_f32(outbuf + 16*64, s24); + vst1q_f32(outbuf + 17*64, s25); + + vst1q_f32(outbuf + 18*64, s30); + vst1q_f32(outbuf + 19*64, s31); + vst1q_f32(outbuf + 20*64, s32); + vst1q_f32(outbuf + 21*64, s33); + vst1q_f32(outbuf + 22*64, s34); + vst1q_f32(outbuf + 23*64, s35); + } + } + else + { + for (int atom_id = 0; atom_id < winoNatomF32; atom_id++, + outbuf += winoAtomF32) + { + float32x4_t s00 = vdupq_n_f32(0.f), s01 = s00, s02 = s00; + float32x4_t s10 = vdupq_n_f32(0.f), s11 = s00, s12 = s00; + float32x4_t s20 = vdupq_n_f32(0.f), s21 = s00, s22 = s00; + float32x4_t s30 = vdupq_n_f32(0.f), s31 = s00, s32 = s00; + for (int c = 0; c < Cg; c++, inwptr += winoIblock*winoAtomF32, + wptr += winoKblock*winoAtomF32) { + float32x4_t w0 = vld1q_f32(wptr), w1 = vld1q_f32(wptr + 4); + float32x4_t w2 = vld1q_f32(wptr + 8), w3 = vld1q_f32(wptr + 12); + float32x4_t x0, x1, x2; + x0 = vld1q_f32(inwptr); + x1 = vld1q_f32(inwptr + 4); + x2 = vld1q_f32(inwptr + 8); + s00 = vfmaq_f32(s00, w0, x0); + s01 = vfmaq_f32(s01, w0, x1); + s02 = vfmaq_f32(s02, w0, x2); + s10 = vfmaq_f32(s10, w1, x0); + s11 = vfmaq_f32(s11, w1, x1); + s12 = vfmaq_f32(s12, w1, x2); + s20 = vfmaq_f32(s20, w2, x0); + s21 = vfmaq_f32(s21, w2, x1); + s22 = vfmaq_f32(s22, w2, x2); + s30 = vfmaq_f32(s30, w3, x0); + s31 = vfmaq_f32(s31, w3, x1); + s32 = vfmaq_f32(s32, w3, x2); + } + + vst1q_f32(outbuf, s00); + vst1q_f32(outbuf + 1*64, s01); + vst1q_f32(outbuf + 2*64, s02); + vst1q_f32(outbuf + 6*64, s10); + vst1q_f32(outbuf + 7*64, s11); + vst1q_f32(outbuf + 8*64, s12); + vst1q_f32(outbuf + 12*64, s20); + vst1q_f32(outbuf + 13*64, s21); + vst1q_f32(outbuf + 14*64, s22); + vst1q_f32(outbuf + 18*64, s30); + vst1q_f32(outbuf + 19*64, s31); + vst1q_f32(outbuf + 20*64, s32); + } + } +} + +#undef T4x4 +#define T4x4(a, b, c, d, tr0, tr1) \ + tr0 = vtrnq_f32(a, b); \ + tr1 = vtrnq_f32(c, d); \ + a = vcombine_f32(vget_low_f32(tr0.val[0]), vget_low_f32(tr1.val[0])); \ + b = vcombine_f32(vget_low_f32(tr0.val[1]), vget_low_f32(tr1.val[1])); \ + c = vcombine_f32(vget_high_f32(tr0.val[0]), vget_high_f32(tr1.val[0])); \ + d = vcombine_f32(vget_high_f32(tr0.val[1]), vget_high_f32(tr1.val[1])) + +/*Input transform*/ +void impl_BtXB_8x8_F32(const float* inptr, int inpstep, + uchar* outptr_, int Cg, const int winoIblock, const int winoAtomF32) +{ + float * outptr = (float*)outptr_; + + float32x4_t x00 = vld1q_f32(inptr), x01 = vld1q_f32(inptr + 4); + float32x4_t x10 = vld1q_f32(inptr + inpstep), x11 = vld1q_f32(inptr + inpstep + 4); + float32x4_t x20 = vld1q_f32(inptr + inpstep*2), x21 = vld1q_f32(inptr + inpstep*2 + 4); + float32x4_t x30 = vld1q_f32(inptr + inpstep*3), x31 = vld1q_f32(inptr + inpstep*3 + 4); + float32x4_t x40 = vld1q_f32(inptr + inpstep*4), x41 = vld1q_f32(inptr + inpstep*4 + 4); + float32x4_t x50 = vld1q_f32(inptr + inpstep*5), x51 = vld1q_f32(inptr + inpstep*5 + 4); + float32x4_t x60 = vld1q_f32(inptr + inpstep*6), x61 = vld1q_f32(inptr + inpstep*6 + 4); + float32x4_t x70 = vld1q_f32(inptr + inpstep*7), x71 = vld1q_f32(inptr + inpstep*7 + 4); + + float32x4_t z00, z01, z10, z11, z20, z21, z30, z31, z40, z41, z50, z51, z60, z61, z70, z71; + + { + /* Y[0] = [1.f, 0.f, -5.25f, 0.f, 5.25f, 0.f, -1.f, 0.f]*X */ + /* Y[7] = [0.f, -1.f, 0.f, 5.25f, 0.f, -5.25f, 0.f, 1.f]*X */ + float32x4_t q5_25 = vdupq_n_f32(5.25f), t00, t01, t10, t11; + t00 = vsubq_f32(x40, x20); + t01 = vsubq_f32(x41, x21); + t10 = vsubq_f32(x30, x50); + t11 = vsubq_f32(x31, x51); + float32x4_t y00 = vfmaq_f32(vsubq_f32(x00, x60), t00, q5_25); + float32x4_t y01 = vfmaq_f32(vsubq_f32(x01, x61), t01, q5_25); + float32x4_t y70 = vfmaq_f32(vsubq_f32(x70, x10), t10, q5_25); + float32x4_t y71 = vfmaq_f32(vsubq_f32(x71, x11), t11, q5_25); + + /* Y[1] = [0.f, 1.f, 1.f, -4.25f, -4.25f, 1.f, 1.f, 0.f]*X */ + /* Y[2] = [0.f, -1.f, 1.f, 4.25f, -4.25f, -1.f, 1.f, 0.f]*X */ + float32x4_t qm4_25 = vdupq_n_f32(-4.25f); + t00 = vfmaq_f32(vaddq_f32(x10, x50), x30, qm4_25); + t01 = vfmaq_f32(vaddq_f32(x11, x51), x31, qm4_25); + t10 = vfmaq_f32(vaddq_f32(x20, x60), x40, qm4_25); + t11 = vfmaq_f32(vaddq_f32(x21, x61), x41, qm4_25); + + float32x4_t y10 = vaddq_f32(t00, t10), y11 = vaddq_f32(t01, t11); + float32x4_t y20 = vsubq_f32(t10, t00), y21 = vsubq_f32(t11, t01); + + /* Y[3] = [0.f, 0.5f, 0.25f, -2.5f, -1.25f, 2.f, 1.f, 0.f]*X */ + /* Y[4] = [0.f, -0.5f, 0.25f, 2.5f, -1.25f, -2.f, 1.f, 0.f]*X */ + float32x4_t q0_5 = vdupq_n_f32(0.5f), q0_25 = vdupq_n_f32(0.25f); + float32x4_t qm2_5 = vdupq_n_f32(-2.5f), qm1_25 = vdupq_n_f32(-1.25f); + t00 = vfmaq_f32(vaddq_f32(x50, x50), x10, q0_5); + t01 = vfmaq_f32(vaddq_f32(x51, x51), x11, q0_5); + t10 = vfmaq_f32(x60, x20, q0_25); + t11 = vfmaq_f32(x61, x21, q0_25); + t00 = vfmaq_f32(t00, x30, qm2_5); + t01 = vfmaq_f32(t01, x31, qm2_5); + t10 = vfmaq_f32(t10, x40, qm1_25); + t11 = vfmaq_f32(t11, x41, qm1_25); + + float32x4_t y30 = vaddq_f32(t00, t10), y31 = vaddq_f32(t01, t11); + float32x4_t y40 = vsubq_f32(t10, t00), y41 = vsubq_f32(t11, t01); + + /* Y[5] = [0.f, 2.f, 4.f, -2.5f, -5.f, 0.5f, 1.f, 0.f]*X */ + /* Y[6] = [0.f, -2.f, 4.f, 2.5f, -5.f, -0.5f, 1.f, 0.f]*X */ + float32x4_t q4 = vdupq_n_f32(4.f), qm5 = vdupq_n_f32(-5.f); + t00 = vfmaq_f32(vaddq_f32(x10, x10), x50, q0_5); + t01 = vfmaq_f32(vaddq_f32(x11, x11), x51, q0_5); + t10 = vfmaq_f32(x60, x20, q4); + t11 = vfmaq_f32(x61, x21, q4); + t00 = vfmaq_f32(t00, x30, qm2_5); + t01 = vfmaq_f32(t01, x31, qm2_5); + t10 = vfmaq_f32(t10, x40, qm5); + t11 = vfmaq_f32(t11, x41, qm5); + + float32x4_t y50 = vaddq_f32(t00, t10), y51 = vaddq_f32(t01, t11); + float32x4_t y60 = vsubq_f32(t10, t00), y61 = vsubq_f32(t11, t01); + + /* transpose 8x8 matrix in-place with some renumeration of the elements: */ + /* Y: */ + /* y00 y01 */ + /* y10 y11 */ + /* ... */ + /* y70 y71 */ + /* Y': */ + /* y00 y40 */ + /* y10 y50 */ + /* y20 y60 */ + /* y30 y70 */ + /* y01 y41 */ + /* y11 y51 */ + /* y21 y61 */ + /* y31 y71 */ + /* in other words, y40 <-> y01, y50 <-> y11, y60 <-> y21, y70 <-> y31 */ + float32x4x2_t tr0, tr1; + + T4x4(y00, y10, y20, y30, tr0, tr1); + T4x4(y01, y11, y21, y31, tr0, tr1); + T4x4(y40, y50, y60, y70, tr0, tr1); + T4x4(y41, y51, y61, y71, tr0, tr1); + + /* Z[0] = [1.f, 0.f, -5.25f, 0.f, 5.25f, 0.f, -1.f, 0.f]*Y */ + /* Z[7] = [0.f, -1.f, 0.f, 5.25f, 0.f, -5.25f, 0.f, 1.f]*Y */ + t00 = vsubq_f32(y01, y20); + t01 = vsubq_f32(y41, y60); + t10 = vsubq_f32(y30, y11); + t11 = vsubq_f32(y70, y51); + z00 = vfmaq_f32(vsubq_f32(y00, y21), t00, q5_25); + z01 = vfmaq_f32(vsubq_f32(y40, y61), t01, q5_25); + z70 = vfmaq_f32(vsubq_f32(y31, y10), t10, q5_25); + z71 = vfmaq_f32(vsubq_f32(y71, y50), t11, q5_25); + + /* Z[1] = [0.f, 1.f, 1.f, -4.25f, -4.25f, 1.f, 1.f, 0.f]*Y */ + /* Z[2] = [0.f, -1.f, 1.f, 4.25f, -4.25f, -1.f, 1.f, 0.f]*Y */ + t00 = vfmaq_f32(vaddq_f32(y10, y11), y30, qm4_25); + t01 = vfmaq_f32(vaddq_f32(y50, y51), y70, qm4_25); + t10 = vfmaq_f32(vaddq_f32(y20, y21), y01, qm4_25); + t11 = vfmaq_f32(vaddq_f32(y60, y61), y41, qm4_25); + + z10 = vaddq_f32(t00, t10); z11 = vaddq_f32(t01, t11); + z20 = vsubq_f32(t10, t00); z21 = vsubq_f32(t11, t01); + + /* Z[3] = [0.f, 0.5f, 0.25f, -2.5f, -1.25f, 2.f, 1.f, 0.f]*Y */ + /* Z[4] = [0.f, -0.5f, 0.25f, 2.5f, -1.25f, -2.f, 1.f, 0.f]*Y */ + t00 = vfmaq_f32(vaddq_f32(y11, y11), y10, q0_5); + t01 = vfmaq_f32(vaddq_f32(y51, y51), y50, q0_5); + t10 = vfmaq_f32(y21, y20, q0_25); + t11 = vfmaq_f32(y61, y60, q0_25); + t00 = vfmaq_f32(t00, y30, qm2_5); + t01 = vfmaq_f32(t01, y70, qm2_5); + t10 = vfmaq_f32(t10, y01, qm1_25); + t11 = vfmaq_f32(t11, y41, qm1_25); + + z30 = vaddq_f32(t00, t10); z31 = vaddq_f32(t01, t11); + z40 = vsubq_f32(t10, t00); z41 = vsubq_f32(t11, t01); + + /* Z[5] = [0.f, 2.f, 4.f, -2.5f, -5.f, 0.5f, 1.f, 0.f]*Y */ + /* Z[6] = [0.f, -2.f, 4.f, 2.5f, -5.f, -0.5f, 1.f, 0.f]*Y */ + t00 = vfmaq_f32(vaddq_f32(y10, y10), y11, q0_5); + t01 = vfmaq_f32(vaddq_f32(y50, y50), y51, q0_5); + t10 = vfmaq_f32(y21, y20, q4); + t11 = vfmaq_f32(y61, y60, q4); + t00 = vfmaq_f32(t00, y30, qm2_5); + t01 = vfmaq_f32(t01, y70, qm2_5); + t10 = vfmaq_f32(t10, y01, qm5); + t11 = vfmaq_f32(t11, y41, qm5); + + z50 = vaddq_f32(t00, t10); z51 = vaddq_f32(t01, t11); + z60 = vsubq_f32(t10, t00); z61 = vsubq_f32(t11, t01); + } + + const int outstep = winoIblock*winoAtomF32*Cg; + + vst1q_f32(outptr, z00); + vst1q_f32(outptr + outstep, z01); + vst1q_f32(outptr + outstep*2, z10); + vst1q_f32(outptr + outstep*3, z11); + vst1q_f32(outptr + outstep*4, z20); + vst1q_f32(outptr + outstep*5, z21); + vst1q_f32(outptr + outstep*6, z30); + vst1q_f32(outptr + outstep*7, z31); + vst1q_f32(outptr + outstep*8, z40); + vst1q_f32(outptr + outstep*9, z41); + vst1q_f32(outptr + outstep*10, z50); + vst1q_f32(outptr + outstep*11, z51); + vst1q_f32(outptr + outstep*12, z60); + vst1q_f32(outptr + outstep*13, z61); + vst1q_f32(outptr + outstep*14, z70); + vst1q_f32(outptr + outstep*15, z71); +} + +/*Output transform*/ +void impl_AtXA_8x8_F32(const uchar* inptr_, int inpstep, + float* bpptr, int bpstep, float* outptr, int outstep, + float bias, float minval, float maxval, bool ifMinMaxAct) +{ + const float * inptr = (float*)inptr_; + + float32x4_t x00 = vld1q_f32(inptr), x01 = vld1q_f32(inptr + 4); + float32x4_t x10 = vld1q_f32(inptr + inpstep), x11 = vld1q_f32(inptr + inpstep + 4); + float32x4_t x20 = vld1q_f32(inptr + inpstep*2), x21 = vld1q_f32(inptr + inpstep*2 + 4); + float32x4_t x30 = vld1q_f32(inptr + inpstep*3), x31 = vld1q_f32(inptr + inpstep*3 + 4); + float32x4_t x40 = vld1q_f32(inptr + inpstep*4), x41 = vld1q_f32(inptr + inpstep*4 + 4); + float32x4_t x50 = vld1q_f32(inptr + inpstep*5), x51 = vld1q_f32(inptr + inpstep*5 + 4); + float32x4_t x60 = vld1q_f32(inptr + inpstep*6), x61 = vld1q_f32(inptr + inpstep*6 + 4); + float32x4_t x70 = vld1q_f32(inptr + inpstep*7), x71 = vld1q_f32(inptr + inpstep*7 + 4); + float32x4_t z00, z01, z10, z11, z20, z21, z30, z31, z40, z41, z50, z51; + + { + float32x4_t s12_0, s12_1, s34_0, s34_1, s56_0, s56_1; + s12_0 = vaddq_f32(x10, x20); s12_1 = vaddq_f32(x11, x21); + s34_0 = vaddq_f32(x30, x40); s34_1 = vaddq_f32(x31, x41); + s56_0 = vaddq_f32(x50, x60); s56_1 = vaddq_f32(x51, x61); + + float32x4_t y00 = vaddq_f32(vaddq_f32(vaddq_f32(x00, s12_0), s34_0), s56_0); + float32x4_t y01 = vaddq_f32(vaddq_f32(vaddq_f32(x01, s12_1), s34_1), s56_1); + float32x4_t y20 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 4.0f), s56_0, 0.25f); + float32x4_t y21 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 4.0f), s56_1, 0.25f); + float32x4_t y40 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 16.0f), s56_0, 1.f/16); + float32x4_t y41 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 16.0f), s56_1, 1.f/16); + + s12_0 = vsubq_f32(x10, x20); s12_1 = vsubq_f32(x11, x21); + s34_0 = vsubq_f32(x30, x40); s34_1 = vsubq_f32(x31, x41); + s56_0 = vsubq_f32(x50, x60); s56_1 = vsubq_f32(x51, x61); + + float32x4_t y50 = vfmaq_n_f32(vfmaq_n_f32(vaddq_f32(x70, s12_0), + s34_0, 32.f), s56_0, 1.f/32); + float32x4_t y51 = vfmaq_n_f32(vfmaq_n_f32(vaddq_f32(x71, s12_1), + s34_1, 32.f), s56_1, 1.f/32); + float32x4_t y10 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 2.0f), s56_0, 0.5f); + float32x4_t y11 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 2.0f), s56_1, 0.5f); + float32x4_t y30 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 8.0f), s56_0, 0.125f); + float32x4_t y31 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 8.0f), s56_1, 0.125f); + float32x4_t y60 = vdupq_n_f32(0.f), y61 = y60, y70 = y60, y71 = y60; + + /* transpose 8x8 matrix in-place with some renumeration of the elements: */ + /* Y: */ + /* y00 y01 */ + /* y10 y11 */ + /* ... */ + /* y50 y51 */ + /* 0 0 */ + /* 0 0 */ + /* Y': */ + /* y00 y40 */ + /* y10 y50 */ + /* y20 y60 */ + /* y30 y70 */ + /* y01 y41 */ + /* y11 y51 */ + /* y21 y61 */ + /* y31 y71 */ + /* in other words, y40 <-> y01, y50 <-> y11, y60 <-> y21, y70 <-> y31 */ + float32x4x2_t tr0, tr1; + + T4x4(y00, y10, y20, y30, tr0, tr1); + T4x4(y01, y11, y21, y31, tr0, tr1); + T4x4(y40, y50, y60, y70, tr0, tr1); + T4x4(y41, y51, y61, y71, tr0, tr1); + + s12_0 = vaddq_f32(y10, y20); s12_1 = vaddq_f32(y50, y60); + s34_0 = vaddq_f32(y30, y01); s34_1 = vaddq_f32(y70, y41); + s56_0 = vaddq_f32(y11, y21); s56_1 = vaddq_f32(y51, y61); + + z00 = vaddq_f32(vaddq_f32(vaddq_f32(y00, s12_0), s34_0), s56_0); + z01 = vaddq_f32(vaddq_f32(vaddq_f32(y40, s12_1), s34_1), s56_1); + z20 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 4.0f), s56_0, 0.25f); + z21 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 4.0f), s56_1, 0.25f); + z40 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 16.0f), s56_0, 1.f/16); + z41 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 16.0f), s56_1, 1.f/16); + + s12_0 = vsubq_f32(y10, y20); s12_1 = vsubq_f32(y50, y60); + s34_0 = vsubq_f32(y30, y01); s34_1 = vsubq_f32(y70, y41); + s56_0 = vsubq_f32(y11, y21); s56_1 = vsubq_f32(y51, y61); + + z50 = vfmaq_n_f32(vfmaq_n_f32(vaddq_f32(y31, s12_0), + s34_0, 32.f), s56_0, 1.f/32); + z51 = vfmaq_n_f32(vfmaq_n_f32(vaddq_f32(y71, s12_1), + s34_1, 32.f), s56_1, 1.f/32); + z10 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 2.0f), s56_0, 0.5f); + z11 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 2.0f), s56_1, 0.5f); + z30 = vfmaq_n_f32(vfmaq_n_f32(s12_0, s34_0, 8.0f), s56_0, 0.125f); + z31 = vfmaq_n_f32(vfmaq_n_f32(s12_1, s34_1, 8.0f), s56_1, 0.125f); + float32x4_t vbias = vdupq_n_f32(bias); + + z00 = vaddq_f32(z00, vbias); + z01 = vaddq_f32(z01, vbias); + z10 = vaddq_f32(z10, vbias); + z11 = vaddq_f32(z11, vbias); + z20 = vaddq_f32(z20, vbias); + z21 = vaddq_f32(z21, vbias); + z30 = vaddq_f32(z30, vbias); + z31 = vaddq_f32(z31, vbias); + z40 = vaddq_f32(z40, vbias); + z41 = vaddq_f32(z41, vbias); + z50 = vaddq_f32(z50, vbias); + z51 = vaddq_f32(z51, vbias); + } + + if (bpptr) + { + float32x2_t zhalf = vdup_n_f32(0.f); + z00 = vaddq_f32(z00, vld1q_f32(bpptr)); + z01 = vaddq_f32(z01, vcombine_f32(vld1_f32(bpptr + 4), zhalf)); + z10 = vaddq_f32(z10, vld1q_f32(bpptr + bpstep)); + z11 = vaddq_f32(z11, vcombine_f32(vld1_f32(bpptr + bpstep + 4), zhalf)); + z20 = vaddq_f32(z20, vld1q_f32(bpptr + bpstep*2)); + z21 = vaddq_f32(z21, vcombine_f32(vld1_f32(bpptr + bpstep*2 + 4), zhalf)); + z30 = vaddq_f32(z30, vld1q_f32(bpptr + bpstep*3)); + z31 = vaddq_f32(z31, vcombine_f32(vld1_f32(bpptr + bpstep*3 + 4), zhalf)); + z40 = vaddq_f32(z40, vld1q_f32(bpptr + bpstep*4)); + z41 = vaddq_f32(z41, vcombine_f32(vld1_f32(bpptr + bpstep*4 + 4), zhalf)); + z50 = vaddq_f32(z50, vld1q_f32(bpptr + bpstep*5)); + z51 = vaddq_f32(z51, vcombine_f32(vld1_f32(bpptr + bpstep*5 + 4), zhalf)); + } + + if (ifMinMaxAct) + { + float32x4_t vmax = vdupq_n_f32(maxval); + float32x4_t vmin = vdupq_n_f32(minval); + + z00 = vminq_f32(vmaxq_f32(z00, vmin), vmax); + z01 = vminq_f32(vmaxq_f32(z01, vmin), vmax); + z10 = vminq_f32(vmaxq_f32(z10, vmin), vmax); + z11 = vminq_f32(vmaxq_f32(z11, vmin), vmax); + z20 = vminq_f32(vmaxq_f32(z20, vmin), vmax); + z21 = vminq_f32(vmaxq_f32(z21, vmin), vmax); + z30 = vminq_f32(vmaxq_f32(z30, vmin), vmax); + z31 = vminq_f32(vmaxq_f32(z31, vmin), vmax); + z40 = vminq_f32(vmaxq_f32(z40, vmin), vmax); + z41 = vminq_f32(vmaxq_f32(z41, vmin), vmax); + z50 = vminq_f32(vmaxq_f32(z50, vmin), vmax); + z51 = vminq_f32(vmaxq_f32(z51, vmin), vmax); + } + + vst1q_f32(outptr, z00); + vst1_f32(outptr + 4, vget_low_f32(z01)); + vst1q_f32(outptr + outstep, z10); + vst1_f32(outptr + outstep + 4, vget_low_f32(z11)); + vst1q_f32(outptr + outstep*2, z20); + vst1_f32(outptr + outstep*2 + 4, vget_low_f32(z21)); + vst1q_f32(outptr + outstep*3, z30); + vst1_f32(outptr + outstep*3 + 4, vget_low_f32(z31)); + vst1q_f32(outptr + outstep*4, z40); + vst1_f32(outptr + outstep*4 + 4, vget_low_f32(z41)); + vst1q_f32(outptr + outstep*5, z50); + vst1_f32(outptr + outstep*5 + 4, vget_low_f32(z51)); +} + +cv::dnn::Winofunc getWinofunc_F32() +{ + return {&impl_accum_F32, &impl_BtXB_8x8_F32, &impl_AtXA_8x8_F32, 6, 4, 4}; +} + + +// end of NEON/AArch64 +#elif CV_SIMD128 + + +void impl_accum_F32(const uchar* inwptr_, const uchar* wptr_, uchar* outbuf_, int Cg, int iblock, + const int winoIblock, const int winoKblock, const int winoAtomF32, const int winoNatomF32) +{ + const float * inwptr = (float*)inwptr_; + const float * wptr = (float*)wptr_; + float * outbuf = (float*)outbuf_; +#if 1 + CV_Assert(winoIblock == 3 && winoKblock == 4 && winoAtomF32 == 4); + for (int atom_id = 0; atom_id < winoNatomF32; atom_id++, + outbuf += winoAtomF32) + { + v_float32x4 s00 = v_setzero_f32(), s01 = s00, s02 = s00; + v_float32x4 s10 = v_setzero_f32(), s11 = s00, s12 = s00; + v_float32x4 s20 = v_setzero_f32(), s21 = s00, s22 = s00; + v_float32x4 s30 = v_setzero_f32(), s31 = s00, s32 = s00; + + for (int c = 0; c < Cg; c++, inwptr += winoIblock*winoAtomF32, + wptr += winoKblock*winoAtomF32) + { + v_float32x4 x0, x1, x2; + x0 = v_load(inwptr); + x1 = v_load(inwptr + 4); + x2 = v_load(inwptr + 8); + + v_float32x4 w0 = v_load(wptr); + s00 = v_fma(w0, x0, s00); + s01 = v_fma(w0, x1, s01); + s02 = v_fma(w0, x2, s02); + + w0 = v_load(wptr + 4); + s10 = v_fma(w0, x0, s10); + s11 = v_fma(w0, x1, s11); + s12 = v_fma(w0, x2, s12); + + w0 = v_load(wptr + 8); + s20 = v_fma(w0, x0, s20); + s21 = v_fma(w0, x1, s21); + s22 = v_fma(w0, x2, s22); + + w0 = v_load(wptr + 12); + s30 = v_fma(w0, x0, s30); + s31 = v_fma(w0, x1, s31); + s32 = v_fma(w0, x2, s32); + } + + v_store(outbuf, s00); + v_store(outbuf + 1*64, s01); + v_store(outbuf + 2*64, s02); + v_store(outbuf + 3*64, s10); + v_store(outbuf + 4*64, s11); + v_store(outbuf + 5*64, s12); + v_store(outbuf + 6*64, s20); + v_store(outbuf + 7*64, s21); + v_store(outbuf + 8*64, s22); + v_store(outbuf + 9*64, s30); + v_store(outbuf + 10*64, s31); + v_store(outbuf + 11*64, s32); + } +#else + // Naive C++ code, the code should never be run here. + for (int atom_id = 0; atom_id < winoNatomF32; + atom_id++, outbuf += winoAtomF32) + { + float sumbuf[winoIblock*winoKblock*winoAtomF32]; + memset(sumbuf, 0, sizeof(sumbuf)); + for (int c = 0; c < Cg; c++, inwptr += winoIblock*winoAtomF32, + wptr += winoKblock*winoAtomF32) + { + for (int i = 0; i < winoKblock; i++) + { + for (int j = 0; j < winoIblock; j++) + { + int i_ = i*winoAtomF32; + int j_ = j*winoAtomF32; + int ij_ = i_*winoIblock + j_; + float s0 = inwptr[j_ + 0]*wptr[i_ + 0]; + float s1 = inwptr[j_ + 1]*wptr[i_ + 1]; + float s2 = inwptr[j_ + 2]*wptr[i_ + 2]; + float s3 = inwptr[j_ + 3]*wptr[i_ + 3]; + sumbuf[ij_ + 0] += s0; + sumbuf[ij_ + 1] += s1; + sumbuf[ij_ + 2] += s2; + sumbuf[ij_ + 3] += s3; + } + } + } + for (int ij = 0; ij < winoKblock*winoIblock; ij++) + { + int ij_ = ij*winoAtomF32; + int ij_out = ij*CONV_WINO_AREA; + outbuf[ij_out + 0] = sumbuf[ij_ + 0]; + outbuf[ij_out + 1] = sumbuf[ij_ + 1]; + outbuf[ij_out + 2] = sumbuf[ij_ + 2]; + outbuf[ij_out + 3] = sumbuf[ij_ + 3]; + } + } +#endif +} + +/*Input transform*/ +void impl_BtXB_8x8_F32(const float* inptr, int inpstep, uchar* outptr_, int Cg, const int winoIblock, const int winoAtomF32) +{ + float * outptr = (float*)outptr_; + + CV_Assert(winoIblock == 3 && winoAtomF32 == 4); + v_float32x4 x00 = v_load(inptr), x01 = v_load(inptr + 4); + v_float32x4 x10 = v_load(inptr + inpstep), x11 = v_load(inptr + inpstep + 4); + v_float32x4 x20 = v_load(inptr + inpstep*2), x21 = v_load(inptr + inpstep*2 + 4); + v_float32x4 x30 = v_load(inptr + inpstep*3), x31 = v_load(inptr + inpstep*3 + 4); + v_float32x4 x40 = v_load(inptr + inpstep*4), x41 = v_load(inptr + inpstep*4 + 4); + v_float32x4 x50 = v_load(inptr + inpstep*5), x51 = v_load(inptr + inpstep*5 + 4); + v_float32x4 x60 = v_load(inptr + inpstep*6), x61 = v_load(inptr + inpstep*6 + 4); + v_float32x4 x70 = v_load(inptr + inpstep*7), x71 = v_load(inptr + inpstep*7 + 4); + + v_float32x4 z00, z01, z10, z11, z20, z21, z30, z31, z40, z41, z50, z51, z60, z61, z70, z71; + + { + /* Y[0] = [1.f, 0.f, -5.25f, 0.f, 5.25f, 0.f, -1.f, 0.f]*X */ + /* Y[7] = [0.f, -1.f, 0.f, 5.25f, 0.f, -5.25f, 0.f, 1.f]*X */ + v_float32x4 q5_25 = v_setall_f32(5.25f), t00, t01, t10, t11; + t00 = v_sub(x40, x20); + t01 = v_sub(x41, x21); + t10 = v_sub(x30, x50); + t11 = v_sub(x31, x51); + v_float32x4 y00 = v_fma(t00, q5_25, v_sub(x00, x60)); + v_float32x4 y01 = v_fma(t01, q5_25, v_sub(x01, x61)); + v_float32x4 y70 = v_fma(t10, q5_25, v_sub(x70, x10)); + v_float32x4 y71 = v_fma(t11, q5_25, v_sub(x71, x11)); + + /* Y[1] = [0.f, 1.f, 1.f, -4.25f, -4.25f, 1.f, 1.f, 0.f]*X */ + /* Y[2] = [0.f, -1.f, 1.f, 4.25f, -4.25f, -1.f, 1.f, 0.f]*X */ + v_float32x4 qm4_25 = v_setall_f32(-4.25f); + t00 = v_fma(x30, qm4_25, v_add(x10, x50)); + t01 = v_fma(x31, qm4_25, v_add(x11, x51)); + t10 = v_fma(x40, qm4_25, v_add(x20, x60)); + t11 = v_fma(x41, qm4_25, v_add(x21, x61)); + + v_float32x4 y10 = v_add(t00, t10), y11 = v_add(t01, t11); + v_float32x4 y20 = v_sub(t10, t00), y21 = v_sub(t11, t01); + + /* Y[3] = [0.f, 0.5f, 0.25f, -2.5f, -1.25f, 2.f, 1.f, 0.f]*X */ + /* Y[4] = [0.f, -0.5f, 0.25f, 2.5f, -1.25f, -2.f, 1.f, 0.f]*X */ + v_float32x4 q0_5 = v_setall_f32(0.5f), q0_25 = v_setall_f32(0.25f); + v_float32x4 qm2_5 = v_setall_f32(-2.5f), qm1_25 = v_setall_f32(-1.25f); + t00 = v_fma(x10, q0_5, v_add(x50, x50)); + t01 = v_fma(x11, q0_5, v_add(x51, x51)); + t10 = v_fma(x20, q0_25, x60); + t11 = v_fma(x21, q0_25, x61); + t00 = v_fma(x30, qm2_5, t00); + t01 = v_fma(x31, qm2_5, t01); + t10 = v_fma(x40, qm1_25, t10); + t11 = v_fma(x41, qm1_25, t11); + + v_float32x4 y30 = v_add(t00, t10), y31 = v_add(t01, t11); + v_float32x4 y40 = v_sub(t10, t00), y41 = v_sub(t11, t01); + + /* Y[5] = [0.f, 2.f, 4.f, -2.5f, -5.f, 0.5f, 1.f, 0.f]*X */ + /* Y[6] = [0.f, -2.f, 4.f, 2.5f, -5.f, -0.5f, 1.f, 0.f]*X */ + v_float32x4 q4 = v_setall_f32(4.f), qm5 = v_setall_f32(-5.f); + t00 = v_fma(x50, q0_5, v_add(x10, x10)); + t01 = v_fma(x51, q0_5, v_add(x11, x11)); + t10 = v_fma(x20, q4 , x60); + t11 = v_fma(x21, q4 , x61); + t00 = v_fma(x30, qm2_5, t00); + t01 = v_fma(x31, qm2_5, t01); + t10 = v_fma(x40, qm5 , t10); + t11 = v_fma(x41, qm5 , t11); + + v_float32x4 y50 = v_add(t00, t10), y51 = v_add(t01, t11); + v_float32x4 y60 = v_sub(t10, t00), y61 = v_sub(t11, t01); + + /* transpose 8x8 matrix with v_transpose4x4 */ + + v_float32x4 y000, y100, y200, y300, y010, y110, y210, y310, y400, y500, y600, y700, y410, y510, y610, y710; + v_transpose4x4(y00, y10, y20, y30, y000, y100, y200, y300); + v_transpose4x4(y01, y11, y21, y31, y010, y110, y210, y310); + v_transpose4x4(y40, y50, y60, y70, y400, y500, y600, y700); + v_transpose4x4(y41, y51, y61, y71, y410, y510, y610, y710); + + /* Z[0] = [1.f, 0.f, -5.25f, 0.f, 5.25f, 0.f, -1.f, 0.f]*Y */ + /* Z[7] = [0.f, -1.f, 0.f, 5.25f, 0.f, -5.25f, 0.f, 1.f]*Y */ + t00 = v_sub(y010, y200); + t01 = v_sub(y410, y600); + t10 = v_sub(y300, y110); + t11 = v_sub(y700, y510); + z00 = v_fma(t00, q5_25, v_sub(y000, y210)); + z01 = v_fma(t01, q5_25, v_sub(y400, y610)); + z70 = v_fma(t10, q5_25, v_sub(y310, y100)); + z71 = v_fma(t11, q5_25, v_sub(y710, y500)); + + /* Z[1] = [0.f, 1.f, 1.f, -4.25f, -4.25f, 1.f, 1.f, 0.f]*Y */ + /* Z[2] = [0.f, -1.f, 1.f, 4.25f, -4.25f, -1.f, 1.f, 0.f]*Y */ + t00 = v_fma(y300, qm4_25, v_add(y100, y110)); + t01 = v_fma(y700, qm4_25, v_add(y500, y510)); + t10 = v_fma(y010, qm4_25, v_add(y200, y210)); + t11 = v_fma(y410, qm4_25, v_add(y600, y610)); + + z10 = v_add(t00, t10); z11 = v_add(t01, t11); + z20 = v_sub(t10, t00); z21 = v_sub(t11, t01); + + /* Z[3] = [0.f, 0.5f, 0.25f, -2.5f, -1.25f, 2.f, 1.f, 0.f]*Y */ + /* Z[4] = [0.f, -0.5f, 0.25f, 2.5f, -1.25f, -2.f, 1.f, 0.f]*Y */ + t00 = v_fma(y100, q0_5, v_add(y110, y110)); + t01 = v_fma(y500, q0_5, v_add(y510, y510)); + t10 = v_fma(y200, q0_25, y210); + t11 = v_fma(y600, q0_25, y610); + t00 = v_fma(y300, qm2_5, t00); + t01 = v_fma(y700, qm2_5, t01); + t10 = v_fma(y010, qm1_25, t10); + t11 = v_fma(y410, qm1_25, t11); + + z30 = v_add(t00, t10); z31 = v_add(t01, t11); + z40 = v_sub(t10, t00); z41 = v_sub(t11, t01); + + /* Z[5] = [0.f, 2.f, 4.f, -2.5f, -5.f, 0.5f, 1.f, 0.f]*Y */ + /* Z[6] = [0.f, -2.f, 4.f, 2.5f, -5.f, -0.5f, 1.f, 0.f]*Y */ + t00 = v_fma(y110, q0_5, v_add(y100, y100)); + t01 = v_fma(y510, q0_5, v_add(y500, y500)); + t10 = v_fma(y200, q4, y210); + t11 = v_fma(y600, q4, y610); + t00 = v_fma(y300, qm2_5, t00); + t01 = v_fma(y700, qm2_5, t01); + t10 = v_fma(y010, qm5, t10); + t11 = v_fma(y410, qm5, t11); + + z50 = v_add(t00, t10); z51 = v_add(t01, t11); + z60 = v_sub(t10, t00); z61 = v_sub(t11, t01); + } + + const int outstep = winoIblock*winoAtomF32*Cg; + + v_store(outptr, z00); + v_store(outptr + outstep, z01); + v_store(outptr + outstep*2, z10); + v_store(outptr + outstep*3, z11); + v_store(outptr + outstep*4, z20); + v_store(outptr + outstep*5, z21); + v_store(outptr + outstep*6, z30); + v_store(outptr + outstep*7, z31); + v_store(outptr + outstep*8, z40); + v_store(outptr + outstep*9, z41); + v_store(outptr + outstep*10, z50); + v_store(outptr + outstep*11, z51); + v_store(outptr + outstep*12, z60); + v_store(outptr + outstep*13, z61); + v_store(outptr + outstep*14, z70); + v_store(outptr + outstep*15, z71); +} + +/*Output transform*/ +/* Inverse Winograd 8x8 transform: + out = (A'*inp*A)', where + inp is input 8x8 FP32 matrix, + A' is + [1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 0.f, + 0.f, 1.f, -1.f, 2.f, -2.f, 0.5f, -0.5f, 0.f, + 0.f, 1.f, 1.f, 4.f, 4.f, 0.25f, 0.25f, 0.f, + 0.f, 1.f, -1.f, 8.f, -8.f, 0.125f, -0.125f, 0.f, + 0.f, 1.f, 1.f, 16.f, 16.f, 1.f/16, 1.f/16, 0.f, + 0.f, 1.f, -1.f, 32.f, -32.f, 1.f/32, -1.f/32, 1.f] + + inp is pre-loaded into xij registers, + out will be stored in zij, where (0<=i<=7 for x, 0<=i<=5 for z), 0<=j<=1. + + After the inverse transform is done, we add bias, + optionally add results from the earlier tensors (by-pass), + optionally apply activation function and then + store the final results. + + That is, after both forward and then inverse transformation, + we get non-transposed result. + Of course, for the correct work of Winograd-based convolution, + the Winograd-transformed weights should also be transposed. + init_conv() (see OpConv.fx) takes care of that. +*/ +void impl_AtXA_8x8_F32(const uchar* inptr_, int inpstep, + float* bpptr, int bpstep, float* outptr, int outstep, + float bias, float minval, float maxval, bool ifMinMaxAct) +{ + const float * inptr = (float*)inptr_; + + v_float32x4 x00 = v_load(inptr), x01 = v_load(inptr + 4); + v_float32x4 x10 = v_load(inptr + inpstep), x11 = v_load(inptr + inpstep + 4); + v_float32x4 x20 = v_load(inptr + inpstep*2), x21 = v_load(inptr + inpstep*2 + 4); + v_float32x4 x30 = v_load(inptr + inpstep*3), x31 = v_load(inptr + inpstep*3 + 4); + v_float32x4 x40 = v_load(inptr + inpstep*4), x41 = v_load(inptr + inpstep*4 + 4); + v_float32x4 x50 = v_load(inptr + inpstep*5), x51 = v_load(inptr + inpstep*5 + 4); + v_float32x4 x60 = v_load(inptr + inpstep*6), x61 = v_load(inptr + inpstep*6 + 4); + v_float32x4 x70 = v_load(inptr + inpstep*7), x71 = v_load(inptr + inpstep*7 + 4); + v_float32x4 z00, z01, z10, z11, z20, z21, z30, z31, z40, z41, z50, z51; + + { + v_float32x4 s12_0, s12_1, s34_0, s34_1, s56_0, s56_1; + s12_0 = v_add(x10, x20); s12_1 = v_add(x11, x21); + s34_0 = v_add(x30, x40); s34_1 = v_add(x31, x41); + s56_0 = v_add(x50, x60); s56_1 = v_add(x51, x61); + + v_float32x4 y00 = v_add(v_add(v_add(x00, s12_0), s34_0), s56_0); + v_float32x4 y01 = v_add(v_add(v_add(x01, s12_1), s34_1), s56_1); + + v_float32x4 a0 = v_setall_f32(0.25f), a1 = v_setall_f32(4.0f); + v_float32x4 y20 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); + v_float32x4 y21 = v_fma(s56_1, a0 ,v_fma(s34_1, a1, s12_1) ); + + a0 = v_setall_f32(1.f/16), a1 = v_setall_f32(16.0f); + v_float32x4 y40 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); + v_float32x4 y41 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); + + s12_0 = v_sub(x10, x20); s12_1 = v_sub(x11, x21); + s34_0 = v_sub(x30, x40); s34_1 = v_sub(x31, x41); + s56_0 = v_sub(x50, x60); s56_1 = v_sub(x51, x61); + + a0 = v_setall_f32(1.f/32), a1 = v_setall_f32(32.f); + v_float32x4 y50 = v_fma(s56_0, a0, v_fma(s34_0, a1, v_add(x70, s12_0))); + v_float32x4 y51 = v_fma(s56_1, a0, v_fma(s34_1, a1, v_add(x71, s12_1))); + + a0 = v_setall_f32(0.5f), a1 = v_setall_f32(2.f); + v_float32x4 y10 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); + v_float32x4 y11 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); + + a0 = v_setall_f32(0.125f), a1 = v_setall_f32(8.f); + v_float32x4 y30 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); + v_float32x4 y31 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); + + v_float32x4 y60 = v_setall_f32(0.f), y61 = y60, y70 = y60, y71 = y60; + + /* transpose 8x8 matrix with v_transpose4x4 */ + + v_float32x4 y000, y100, y200, y300, y010, y110, y210, y310, y400, y500, y600, y700, y410, y510, y610, y710; + v_transpose4x4(y00, y10, y20, y30, y000, y100, y200, y300); + v_transpose4x4(y01, y11, y21, y31, y010, y110, y210, y310); + v_transpose4x4(y40, y50, y60, y70, y400, y500, y600, y700); + v_transpose4x4(y41, y51, y61, y71, y410, y510, y610, y710); + + s12_0 = v_add(y100, y200); s12_1 = v_add(y500, y600); + s34_0 = v_add(y300, y010); s34_1 = v_add(y700, y410); + s56_0 = v_add(y110, y210); s56_1 = v_add(y510, y610); + + z00 = v_add(v_add(v_add(y000, s12_0), s34_0), s56_0); + z01 = v_add(v_add(v_add(y400, s12_1), s34_1), s56_1); + + a0 = v_setall_f32(0.25f), a1 = v_setall_f32(4.0f); + z20 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); + z21 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); + + a0 = v_setall_f32(1.f/16), a1 = v_setall_f32(16.0f); + z40 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); + z41 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); + + s12_0 = v_sub(y100, y200); s12_1 = v_sub(y500, y600); + s34_0 = v_sub(y300, y010); s34_1 = v_sub(y700, y410); + s56_0 = v_sub(y110, y210); s56_1 = v_sub(y510, y610); + + a0 = v_setall_f32(1.f/32), a1 = v_setall_f32(32.0f); + z50 = v_fma(s56_0, a0, v_fma(s34_0, a1, v_add(y310, s12_0))); + z51 = v_fma(s56_1, a0, v_fma(s34_1, a1, v_add(y710, s12_1))); + a0 = v_setall_f32(0.5f), a1 = v_setall_f32(2.0f); + z10 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); + z11 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); + + a0 = v_setall_f32(0.125f), a1 = v_setall_f32(8.0f); + z30 = v_fma(s56_0, a0, v_fma(s34_0, a1, s12_0)); + z31 = v_fma(s56_1, a0, v_fma(s34_1, a1, s12_1)); + + v_float32x4 vbias = v_setall_f32(bias); + z00 = v_add(z00, vbias); + z01 = v_add(z01, vbias); + z10 = v_add(z10, vbias); + z11 = v_add(z11, vbias); + z20 = v_add(z20, vbias); + z21 = v_add(z21, vbias); + z30 = v_add(z30, vbias); + z31 = v_add(z31, vbias); + z40 = v_add(z40, vbias); + z41 = v_add(z41, vbias); + z50 = v_add(z50, vbias); + z51 = v_add(z51, vbias); + } + + if (bpptr) + { + z00 = v_add(z00, v_load(bpptr)); + z01 = v_add(z01, v_load_low(bpptr + 4)); + z10 = v_add(z10, v_load(bpptr + bpstep)); + z11 = v_add(z11, v_load_low(bpptr + bpstep + 4)); + z20 = v_add(z20, v_load(bpptr + bpstep * 2)); + z21 = v_add(z21, v_load_low(bpptr + bpstep * 2 + 4)); + z30 = v_add(z30, v_load(bpptr + bpstep * 3)); + z31 = v_add(z31, v_load_low(bpptr + bpstep * 3 + 4)); + z40 = v_add(z40, v_load(bpptr + bpstep * 4)); + z41 = v_add(z41, v_load_low(bpptr + bpstep * 4 + 4)); + z50 = v_add(z50, v_load(bpptr + bpstep * 5)); + z51 = v_add(z51, v_load_low(bpptr + bpstep * 5 + 4)); + } + + if (ifMinMaxAct) + { + v_float32x4 vmax = v_setall_f32(maxval); + v_float32x4 vmin = v_setall_f32(minval); + + z00 = v_min(v_max(z00, vmin), vmax); + z01 = v_min(v_max(z01, vmin), vmax); + z10 = v_min(v_max(z10, vmin), vmax); + z11 = v_min(v_max(z11, vmin), vmax); + z20 = v_min(v_max(z20, vmin), vmax); + z21 = v_min(v_max(z21, vmin), vmax); + z30 = v_min(v_max(z30, vmin), vmax); + z31 = v_min(v_max(z31, vmin), vmax); + z40 = v_min(v_max(z40, vmin), vmax); + z41 = v_min(v_max(z41, vmin), vmax); + z50 = v_min(v_max(z50, vmin), vmax); + z51 = v_min(v_max(z51, vmin), vmax); + } + + v_store(outptr, z00); + v_store_low(outptr + 4, z01); + v_store(outptr + outstep, z10); + v_store_low(outptr + outstep + 4, z11); + v_store(outptr + outstep*2, z20); + v_store_low(outptr + outstep*2 + 4, z21); + v_store(outptr + outstep*3, z30); + v_store_low(outptr + outstep*3 + 4, z31); + v_store(outptr + outstep*4, z40); + v_store_low(outptr + outstep*4 + 4, z41); + v_store(outptr + outstep*5, z50); + v_store_low(outptr + outstep*5 + 4, z51); +} + +cv::dnn::Winofunc getWinofunc_F32() +{ + return {&impl_accum_F32, &impl_BtXB_8x8_F32, &impl_AtXA_8x8_F32, 3, 4, 4}; +} + + +// end of CV_SIMD128 +#else + + +cv::dnn::Winofunc getWinofunc_F32() +{ + return cv::dnn::Winofunc::empty(); +} + + +// end of fallback +#endif + +//============================================================================== // FP16, currently, only ARMv8 may support it -#if defined(CV_NEON_AARCH64) && CV_NEON_AARCH64 && defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) +#if defined(CV_CPU_COMPILE_NEON_FP16) && CV_CPU_COMPILE_NEON_FP16 #undef T4x4 #define T4x4(a, b, c, d, tr0, tr1) \ @@ -432,12 +1365,12 @@ void winofunc_AtXA_8x8_F32(const float* inptr, int inpstep, d = vcombine_f32(vget_high_f32(tr0.val[1]), vget_high_f32(tr1.val[1])) /* Accumulate */ -void winofunc_accum_F16(const char* _inwptr, const char* _wptr, char* _outbuf, int Cg, int iblock, +void impl_accum_F16(const uchar* inwptr_, const uchar* wptr_, uchar* outbuf_, int Cg, int iblock, const int winoIblock, const int winoKblock, const int winoAtomF16, const int winoNatomF16) { - const __fp16* inwptr = (const __fp16*)_inwptr; - const __fp16* wptr = (const __fp16*)_wptr; - __fp16* outbuf = (__fp16*)_outbuf; + const __fp16* inwptr = (const __fp16*)inwptr_; + const __fp16* wptr = (const __fp16*)wptr_; + __fp16* outbuf = (__fp16*)outbuf_; CV_Assert(winoIblock == 6 && winoKblock == 4 && winoAtomF16 == 8); @@ -587,10 +1520,11 @@ void winofunc_accum_F16(const char* _inwptr, const char* _wptr, char* _outbuf, i /*Input transform*/ //NOTE: Since we don't have the fully fp16 support. Current work around is that we need packing the data and // convert it to FP16 in input transform stage. And at output transform stage we will convert it back to FP32. -void winofunc_BtXB_8x8_F16(const float * inptr, int inpstep, - char * _outptr, int Cg, const int winoIblock, const int winoAtomF16) +void impl_BtXB_8x8_F16(const float * inptr, int inpstep, + uchar * outptr_, int Cg, const int winoIblock, const int winoAtomF16) { - __fp16* outptr = (__fp16*)_outptr; + __fp16* outptr = (__fp16*)outptr_; + float32x4_t x00 = vld1q_f32(inptr), x01 = vld1q_f32(inptr + 4); float32x4_t x10 = vld1q_f32(inptr + inpstep), x11 = vld1q_f32(inptr + inpstep + 4); float32x4_t x20 = vld1q_f32(inptr + inpstep*2), x21 = vld1q_f32(inptr + inpstep*2 + 4); @@ -751,11 +1685,11 @@ void winofunc_BtXB_8x8_F16(const float * inptr, int inpstep, } // Output transform -void winofunc_AtXA_8x8_F16(const char* _inptr, int inpstep, +void impl_AtXA_8x8_F16(const uchar* inptr_, int inpstep, float * bpptr, int bpstep, float* outptr, int outstep, float bias, float minval, float maxval, bool ifMinMaxAct) { - const __fp16* inptr = (const __fp16*)_inptr; + const __fp16* inptr = (const __fp16*)inptr_; float32x4_t x00 = vcvt_f32_f16(vld1_f16(inptr)), x01 = vcvt_f32_f16(vld1_f16(inptr + 4)); float32x4_t x10 = vcvt_f32_f16(vld1_f16(inptr + inpstep)), x11 = vcvt_f32_f16(vld1_f16(inptr + inpstep + 4)); @@ -907,8 +1841,26 @@ void winofunc_AtXA_8x8_F16(const char* _inptr, int inpstep, vst1q_f32(outptr + outstep*5, z50); vst1_f32(outptr + outstep*5 + 4, vget_low_f32(z51)); } -#endif + +cv::dnn::Winofunc getWinofunc_F16() +{ + return {&impl_accum_F16, &impl_BtXB_8x8_F16, &impl_AtXA_8x8_F16, 6, 8, 2}; +} + +// end of NEON_FP16 +#else + +cv::dnn::Winofunc getWinofunc_F16() +{ + return cv::dnn::Winofunc::empty(); +} + + +// end of fallback #endif + CV_CPU_OPTIMIZATION_NAMESPACE_END -}} // namespace +}} // cv::dnn:: + +#endif // !CV_CPU_DECLARATIONS_ONLY diff --git a/modules/dnn/src/layers/cpu_kernels/convolution.hpp b/modules/dnn/src/layers/cpu_kernels/convolution.hpp index 5c8055337c..98b33ddc5f 100644 --- a/modules/dnn/src/layers/cpu_kernels/convolution.hpp +++ b/modules/dnn/src/layers/cpu_kernels/convolution.hpp @@ -6,6 +6,7 @@ #define OPENCV_FAST_CONVOLUTION_HPP #include "opencv2/core/hal/intrin.hpp" +#include "opencv2/dnn/all_layers.hpp" #ifndef CONV_PRAM #define CONV_PRAM @@ -119,25 +120,30 @@ void convBlock_F32(int np, const float* a, const float* b, float* c, int ldc, bo void convBlockMR1_F32(int np, const float* a, const float* b, float* c, const float bias, bool init_c, const float minval, const float maxval, bool ifMinMaxAct, const int width, const int convNR); - -#if CV_NEON_AARCH64 -/* Accumulate */ -void winofunc_accum_F32(const float* inwptr, const float* wptr, float* outbuf, int Cg, int iblock, - const int winoIblock, const int winoKblock, const int winoAtom, const int winoNatom); - -/*Input transform*/ -void winofunc_BtXB_8x8_F32(const float* inptr, int inpstep, - float* outptr, int Cg, const int winoIblock, const int winoAtom); - -/*Output transform*/ -void winofunc_AtXA_8x8_F32(const float* inptr, int inpstep, - float* bpptr, int bpstep, float* outptr, int outstep, - float bias, float minval, float maxval, bool ifMinMaxAct); -#endif // CV_NEON_AARCH64 #endif // CV_NEON } // namespace opt_NEON. + +// === Function tables +struct Winofunc +{ + void (*accum)(const uchar* inwptr, const uchar* wptr, uchar* outbuf, int Cg, int iblock, const int winoIblock, const int winoKblock, const int winoAtomF32, const int winoNatomF32); + void (*BtXB_8x8)(const float* inptr, int inpstep, uchar* outptr, int Cg, const int winoIblock, const int winoAtomF32); + void (*AtXA_8x8)(const uchar* inptr, int inpstep, float* bpptr, int bpstep, float* outptr, int outstep, float bias, float minval, float maxval, bool ifMinMaxAct); + int iblock; + int natom; + int esz; + + bool isGood() const { return accum && BtXB_8x8 && AtXA_8x8 && iblock > 0 && natom > 0 && esz > 0; } + static Winofunc empty() { return {0, 0, 0, 0, 0, 0}; } +}; + +// === wrapper calls (implemented in .dispatch.cpp) +Winofunc getWinofunc_F32(); +Winofunc getWinofunc_F16(); + + } // namespace dnn } // namespace cv From 1a775198ce3cac8d137035c41e7ef9465c509b85 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Mon, 14 Oct 2024 17:15:37 +0300 Subject: [PATCH 03/10] Skip KleidiCV in offline build. --- 3rdparty/kleidicv/CMakeLists.txt | 23 +++-------------------- 3rdparty/kleidicv/kleidicv.cmake | 21 +++++++++++++++++++++ CMakeLists.txt | 2 +- cmake/OpenCVFindLibsPerf.cmake | 16 ++++++++++++++++ 4 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 3rdparty/kleidicv/kleidicv.cmake diff --git a/3rdparty/kleidicv/CMakeLists.txt b/3rdparty/kleidicv/CMakeLists.txt index 060357662c..a236483c27 100644 --- a/3rdparty/kleidicv/CMakeLists.txt +++ b/3rdparty/kleidicv/CMakeLists.txt @@ -1,24 +1,7 @@ project(kleidicv_hal) -set(KLEIDICV_SOURCE_PATH "" CACHE PATH "Directory containing KleidiCV sources") -ocv_update(KLEIDICV_SRC_COMMIT "0.2.0") -ocv_update(KLEIDICV_SRC_HASH "dabe522e8f55ac342d07a787391dab80") - -if(KLEIDICV_SOURCE_PATH) - set(THE_ROOT "${KLEIDICV_SOURCE_PATH}") -else() - ocv_download(FILENAME "kleidicv-${KLEIDICV_SRC_COMMIT}.tar.gz" - HASH ${KLEIDICV_SRC_HASH} - URL - "${OPENCV_KLEIDICV_URL}" - "$ENV{OPENCV_KLEIDICV_URL}" - "https://gitlab.arm.com/kleidi/kleidicv/-/archive/${KLEIDICV_SRC_COMMIT}/" - DESTINATION_DIR "${OpenCV_BINARY_DIR}/3rdparty/kleidicv/" - ID KLEIDICV - STATUS res - UNPACK RELATIVE_URL) - set(THE_ROOT "${OpenCV_BINARY_DIR}/3rdparty/kleidicv/kleidicv-${KLEIDICV_SRC_COMMIT}") +if(HAVE_KLEIDICV) + option(KLEIDICV_ENABLE_SME2 "" OFF) # not compatible with some CLang versions in NDK + include("${KLEIDICV_SOURCE_PATH}/adapters/opencv/CMakeLists.txt") endif() -option(KLEIDICV_ENABLE_SME2 "" OFF) # not compatible with some CLang versions in NDK -include("${THE_ROOT}/adapters/opencv/CMakeLists.txt") diff --git a/3rdparty/kleidicv/kleidicv.cmake b/3rdparty/kleidicv/kleidicv.cmake new file mode 100644 index 0000000000..57d3843ef0 --- /dev/null +++ b/3rdparty/kleidicv/kleidicv.cmake @@ -0,0 +1,21 @@ +function(download_kleidicv root_var) + set(${root_var} "" PARENT_SCOPE) + + ocv_update(KLEIDICV_SRC_COMMIT "0.2.0") + ocv_update(KLEIDICV_SRC_HASH "dabe522e8f55ac342d07a787391dab80") + + set(THE_ROOT "${OpenCV_BINARY_DIR}/3rdparty/kleidicv") + ocv_download(FILENAME "kleidicv-${KLEIDICV_SRC_COMMIT}.tar.gz" + HASH ${KLEIDICV_SRC_HASH} + URL + "${OPENCV_KLEIDICV_URL}" + "$ENV{OPENCV_KLEIDICV_URL}" + "https://gitlab.arm.com/kleidi/kleidicv/-/archive/${KLEIDICV_SRC_COMMIT}/" + DESTINATION_DIR ${THE_ROOT} + ID KLEIDICV + STATUS res + UNPACK RELATIVE_URL) + if(res) + set(${root_var} "${OpenCV_BINARY_DIR}/3rdparty/kleidicv/kleidicv-${KLEIDICV_SRC_COMMIT}" PARENT_SCOPE) + endif() +endfunction() diff --git a/CMakeLists.txt b/CMakeLists.txt index c8e4ef09c3..3520e92e06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -935,7 +935,7 @@ if(HAVE_OPENVX) endif() endif() -if(WITH_KLEIDICV) +if(HAVE_KLEIDICV) ocv_debug_message(STATUS "Enable KleidiCV acceleration") if(NOT ";${OpenCV_HAL};" MATCHES ";kleidicv;") set(OpenCV_HAL "kleidicv;${OpenCV_HAL}") diff --git a/cmake/OpenCVFindLibsPerf.cmake b/cmake/OpenCVFindLibsPerf.cmake index 5f72a67d89..493f005d7a 100644 --- a/cmake/OpenCVFindLibsPerf.cmake +++ b/cmake/OpenCVFindLibsPerf.cmake @@ -161,3 +161,19 @@ if(WITH_CLP) endif() endif() endif(WITH_CLP) + +# --- ARM KleidiCV +if(WITH_KLEIDICV) + if(KLEIDICV_SOURCE_PATH AND EXISTS "${KLEIDICV_SOURCE_PATH}/adapters/opencv/CMakeLists.txt") + set(HAVE_KLEIDICV ON) + endif() + if(NOT HAVE_KLEIDICV) + include("${OpenCV_SOURCE_DIR}/3rdparty/kleidicv/kleidicv.cmake") + download_kleidicv(KLEIDICV_SOURCE_PATH) + if(KLEIDICV_SOURCE_PATH) + set(HAVE_KLEIDICV ON) + endif() + else() + set(HAVE_KLEIDICV OFF) + endif() +endif(WITH_KLEIDICV) From 1ff16cb551c39d76c80387e45d4657fadd5ec9ef Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 14 Nov 2024 11:24:00 +0300 Subject: [PATCH 04/10] Backport some of C API removal in core module implementation. --- modules/core/src/matmul.dispatch.cpp | 24 ++++++++++++------------ modules/core/src/matrix_expressions.cpp | 18 +++++++++--------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/modules/core/src/matmul.dispatch.cpp b/modules/core/src/matmul.dispatch.cpp index 35b7ad54c4..c78fcc0b7a 100644 --- a/modules/core/src/matmul.dispatch.cpp +++ b/modules/core/src/matmul.dispatch.cpp @@ -696,7 +696,7 @@ void calcCovarMatrix( const Mat* data, int nsamples, Mat& covar, Mat& _mean, int Mat mean; ctype = std::max(std::max(CV_MAT_DEPTH(ctype >= 0 ? ctype : type), _mean.depth()), CV_32F); - if( (flags & CV_COVAR_USE_AVG) != 0 ) + if( (flags & cv::COVAR_USE_AVG) != 0 ) { CV_Assert( _mean.size() == size ); if( _mean.isContinuous() && _mean.type() == ctype ) @@ -722,8 +722,8 @@ void calcCovarMatrix( const Mat* data, int nsamples, Mat& covar, Mat& _mean, int } } - calcCovarMatrix( _data, covar, mean, (flags & ~(CV_COVAR_ROWS|CV_COVAR_COLS)) | CV_COVAR_ROWS, ctype ); - if( (flags & CV_COVAR_USE_AVG) == 0 ) + calcCovarMatrix( _data, covar, mean, (flags & ~(cv::COVAR_ROWS|cv::COVAR_COLS)) | cv::COVAR_ROWS, ctype ); + if( (flags & cv::COVAR_USE_AVG) == 0 ) _mean = mean.reshape(1, size.height); } @@ -754,7 +754,7 @@ void calcCovarMatrix( InputArray _src, OutputArray _covar, InputOutputArray _mea } Mat mean; - if( (flags & CV_COVAR_USE_AVG) != 0 ) + if( (flags & cv::COVAR_USE_AVG) != 0 ) { CV_Assert( _mean.size() == size ); @@ -770,9 +770,9 @@ void calcCovarMatrix( InputArray _src, OutputArray _covar, InputOutputArray _mea mean = _mean.getMat().reshape(1, 1); } - calcCovarMatrix( _data, _covar, mean, (flags & ~(CV_COVAR_ROWS|CV_COVAR_COLS)) | CV_COVAR_ROWS, ctype ); + calcCovarMatrix( _data, _covar, mean, (flags & ~(cv::COVAR_ROWS|cv::COVAR_COLS)) | cv::COVAR_ROWS, ctype ); - if( (flags & CV_COVAR_USE_AVG) == 0 ) + if( (flags & cv::COVAR_USE_AVG) == 0 ) { mean = mean.reshape(1, size.height); mean.copyTo(_mean); @@ -781,14 +781,14 @@ void calcCovarMatrix( InputArray _src, OutputArray _covar, InputOutputArray _mea } Mat data = _src.getMat(), mean; - CV_Assert( ((flags & CV_COVAR_ROWS) != 0) ^ ((flags & CV_COVAR_COLS) != 0) ); - bool takeRows = (flags & CV_COVAR_ROWS) != 0; + CV_Assert( ((flags & cv::COVAR_ROWS) != 0) ^ ((flags & cv::COVAR_COLS) != 0) ); + bool takeRows = (flags & cv::COVAR_ROWS) != 0; int type = data.type(); int nsamples = takeRows ? data.rows : data.cols; CV_Assert( nsamples > 0 ); Size size = takeRows ? Size(data.cols, 1) : Size(1, data.rows); - if( (flags & CV_COVAR_USE_AVG) != 0 ) + if( (flags & cv::COVAR_USE_AVG) != 0 ) { mean = _mean.getMat(); ctype = std::max(std::max(CV_MAT_DEPTH(ctype >= 0 ? ctype : type), mean.depth()), CV_32F); @@ -808,8 +808,8 @@ void calcCovarMatrix( InputArray _src, OutputArray _covar, InputOutputArray _mea mean = _mean.getMat(); } - mulTransposed( data, _covar, ((flags & CV_COVAR_NORMAL) == 0) ^ takeRows, - mean, (flags & CV_COVAR_SCALE) != 0 ? 1./nsamples : 1, ctype ); + mulTransposed( data, _covar, ((flags & cv::COVAR_NORMAL) == 0) ^ takeRows, + mean, (flags & cv::COVAR_SCALE) != 0 ? 1./nsamples : 1, ctype ); } @@ -1171,7 +1171,7 @@ cvCalcCovarMatrix( const CvArr** vecarr, int count, if( avgarr ) mean = mean0 = cv::cvarrToMat(avgarr); - if( (flags & CV_COVAR_COLS) != 0 || (flags & CV_COVAR_ROWS) != 0 ) + if( (flags & cv::COVAR_COLS) != 0 || (flags & cv::COVAR_ROWS) != 0 ) { cv::Mat data = cv::cvarrToMat(vecarr[0]); diff --git a/modules/core/src/matrix_expressions.cpp b/modules/core/src/matrix_expressions.cpp index dd39d50a01..86acab9d93 100644 --- a/modules/core/src/matrix_expressions.cpp +++ b/modules/core/src/matrix_expressions.cpp @@ -554,7 +554,7 @@ void MatOp::matmul(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const if( isT(e1) ) { - flags = CV_GEMM_A_T; + flags = cv::GEMM_1_T; scale = e1.alpha; m1 = e1.a; } @@ -568,7 +568,7 @@ void MatOp::matmul(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const if( isT(e2) ) { - flags |= CV_GEMM_B_T; + flags |= cv::GEMM_2_T; scale *= e2.alpha; m2 = e2.a; } @@ -1574,10 +1574,10 @@ void MatOp_GEMM::add(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const double alpha1 = i1 ? 1 : e1.alpha, alpha2 = i2 ? 1 : e2.alpha; if( isMatProd(e1) && (i2 || isScaled(e2) || isT(e2)) ) - MatOp_GEMM::makeExpr(res, (e1.flags & ~CV_GEMM_C_T)|(isT(e2) ? CV_GEMM_C_T : 0), + MatOp_GEMM::makeExpr(res, (e1.flags & ~cv::GEMM_3_T)|(isT(e2) ? cv::GEMM_3_T : 0), e1.a, e1.b, alpha1, e2.a, alpha2); else if( isMatProd(e2) && (i1 || isScaled(e1) || isT(e1)) ) - MatOp_GEMM::makeExpr(res, (e2.flags & ~CV_GEMM_C_T)|(isT(e1) ? CV_GEMM_C_T : 0), + MatOp_GEMM::makeExpr(res, (e2.flags & ~cv::GEMM_3_T)|(isT(e1) ? cv::GEMM_3_T : 0), e2.a, e2.b, alpha2, e1.a, alpha1); else if( this == e2.op ) MatOp::add(e1, e2, res); @@ -1593,10 +1593,10 @@ void MatOp_GEMM::subtract(const MatExpr& e1, const MatExpr& e2, MatExpr& res) co double alpha1 = i1 ? 1 : e1.alpha, alpha2 = i2 ? 1 : e2.alpha; if( isMatProd(e1) && (i2 || isScaled(e2) || isT(e2)) ) - MatOp_GEMM::makeExpr(res, (e1.flags & ~CV_GEMM_C_T)|(isT(e2) ? CV_GEMM_C_T : 0), + MatOp_GEMM::makeExpr(res, (e1.flags & ~cv::GEMM_3_T)|(isT(e2) ? cv::GEMM_3_T : 0), e1.a, e1.b, alpha1, e2.a, -alpha2); else if( isMatProd(e2) && (i1 || isScaled(e1) || isT(e1)) ) - MatOp_GEMM::makeExpr(res, (e2.flags & ~CV_GEMM_C_T)|(isT(e1) ? CV_GEMM_C_T : 0), + MatOp_GEMM::makeExpr(res, (e2.flags & ~cv::GEMM_3_T)|(isT(e1) ? cv::GEMM_3_T : 0), e2.a, e2.b, -alpha2, e1.a, alpha1); else if( this == e2.op ) MatOp::subtract(e1, e2, res); @@ -1618,9 +1618,9 @@ void MatOp_GEMM::transpose(const MatExpr& e, MatExpr& res) const CV_INSTRUMENT_REGION(); res = e; - res.flags = (!(e.flags & CV_GEMM_A_T) ? CV_GEMM_B_T : 0) | - (!(e.flags & CV_GEMM_B_T) ? CV_GEMM_A_T : 0) | - (!(e.flags & CV_GEMM_C_T) ? CV_GEMM_C_T : 0); + res.flags = (!(e.flags & cv::GEMM_1_T) ? cv::GEMM_2_T : 0) | + (!(e.flags & cv::GEMM_2_T) ? cv::GEMM_1_T : 0) | + (!(e.flags & cv::GEMM_3_T) ? cv::GEMM_3_T : 0); swap(res.a, res.b); } From b7e609d5e8b43fa15bda4a6cb2d7dfddd5930fe5 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Thu, 14 Nov 2024 19:44:10 +0300 Subject: [PATCH 05/10] flann: remove unused hdf5 header --- modules/flann/include/opencv2/flann/hdf5.h | 235 --------------------- 1 file changed, 235 deletions(-) delete mode 100644 modules/flann/include/opencv2/flann/hdf5.h diff --git a/modules/flann/include/opencv2/flann/hdf5.h b/modules/flann/include/opencv2/flann/hdf5.h deleted file mode 100644 index 75543840d6..0000000000 --- a/modules/flann/include/opencv2/flann/hdf5.h +++ /dev/null @@ -1,235 +0,0 @@ -/*********************************************************************** - * Software License Agreement (BSD License) - * - * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. - * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. - *************************************************************************/ - - -#ifndef OPENCV_FLANN_HDF5_H_ -#define OPENCV_FLANN_HDF5_H_ - -//! @cond IGNORED - -#include - -#include "matrix.h" - - -namespace cvflann -{ - -namespace -{ - -template -hid_t get_hdf5_type() -{ - throw FLANNException("Unsupported type for IO operations"); -} - -template<> -hid_t get_hdf5_type() { return H5T_NATIVE_CHAR; } -template<> -hid_t get_hdf5_type() { return H5T_NATIVE_UCHAR; } -template<> -hid_t get_hdf5_type() { return H5T_NATIVE_SHORT; } -template<> -hid_t get_hdf5_type() { return H5T_NATIVE_USHORT; } -template<> -hid_t get_hdf5_type() { return H5T_NATIVE_INT; } -template<> -hid_t get_hdf5_type() { return H5T_NATIVE_UINT; } -template<> -hid_t get_hdf5_type() { return H5T_NATIVE_LONG; } -template<> -hid_t get_hdf5_type() { return H5T_NATIVE_ULONG; } -template<> -hid_t get_hdf5_type() { return H5T_NATIVE_FLOAT; } -template<> -hid_t get_hdf5_type() { return H5T_NATIVE_DOUBLE; } -} - - -#define CHECK_ERROR(x,y) if ((x)<0) throw FLANNException((y)); - -template -void save_to_file(const cvflann::Matrix& dataset, const String& filename, const String& name) -{ - -#if H5Eset_auto_vers == 2 - H5Eset_auto( H5E_DEFAULT, NULL, NULL ); -#else - H5Eset_auto( NULL, NULL ); -#endif - - herr_t status; - hid_t file_id; - file_id = H5Fopen(filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT); - if (file_id < 0) { - file_id = H5Fcreate(filename.c_str(), H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT); - } - CHECK_ERROR(file_id,"Error creating hdf5 file."); - - hsize_t dimsf[2]; // dataset dimensions - dimsf[0] = dataset.rows; - dimsf[1] = dataset.cols; - - hid_t space_id = H5Screate_simple(2, dimsf, NULL); - hid_t memspace_id = H5Screate_simple(2, dimsf, NULL); - - hid_t dataset_id; -#if H5Dcreate_vers == 2 - dataset_id = H5Dcreate2(file_id, name.c_str(), get_hdf5_type(), space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); -#else - dataset_id = H5Dcreate(file_id, name.c_str(), get_hdf5_type(), space_id, H5P_DEFAULT); -#endif - - if (dataset_id<0) { -#if H5Dopen_vers == 2 - dataset_id = H5Dopen2(file_id, name.c_str(), H5P_DEFAULT); -#else - dataset_id = H5Dopen(file_id, name.c_str()); -#endif - } - CHECK_ERROR(dataset_id,"Error creating or opening dataset in file."); - - status = H5Dwrite(dataset_id, get_hdf5_type(), memspace_id, space_id, H5P_DEFAULT, dataset.data ); - CHECK_ERROR(status, "Error writing to dataset"); - - H5Sclose(memspace_id); - H5Sclose(space_id); - H5Dclose(dataset_id); - H5Fclose(file_id); - -} - - -template -void load_from_file(cvflann::Matrix& dataset, const String& filename, const String& name) -{ - herr_t status; - hid_t file_id = H5Fopen(filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT); - CHECK_ERROR(file_id,"Error opening hdf5 file."); - - hid_t dataset_id; -#if H5Dopen_vers == 2 - dataset_id = H5Dopen2(file_id, name.c_str(), H5P_DEFAULT); -#else - dataset_id = H5Dopen(file_id, name.c_str()); -#endif - CHECK_ERROR(dataset_id,"Error opening dataset in file."); - - hid_t space_id = H5Dget_space(dataset_id); - - hsize_t dims_out[2]; - H5Sget_simple_extent_dims(space_id, dims_out, NULL); - - dataset = cvflann::Matrix(new T[dims_out[0]*dims_out[1]], dims_out[0], dims_out[1]); - - status = H5Dread(dataset_id, get_hdf5_type(), H5S_ALL, H5S_ALL, H5P_DEFAULT, dataset[0]); - CHECK_ERROR(status, "Error reading dataset"); - - H5Sclose(space_id); - H5Dclose(dataset_id); - H5Fclose(file_id); -} - - -#ifdef HAVE_MPI - -namespace mpi -{ -/** - * Loads a the hyperslice corresponding to this processor from a hdf5 file. - * @param flann_dataset Dataset where the data is loaded - * @param filename HDF5 file name - * @param name Name of dataset inside file - */ -template -void load_from_file(cvflann::Matrix& dataset, const String& filename, const String& name) -{ - MPI_Comm comm = MPI_COMM_WORLD; - MPI_Info info = MPI_INFO_NULL; - - int mpi_size, mpi_rank; - MPI_Comm_size(comm, &mpi_size); - MPI_Comm_rank(comm, &mpi_rank); - - herr_t status; - - hid_t plist_id = H5Pcreate(H5P_FILE_ACCESS); - H5Pset_fapl_mpio(plist_id, comm, info); - hid_t file_id = H5Fopen(filename.c_str(), H5F_ACC_RDWR, plist_id); - CHECK_ERROR(file_id,"Error opening hdf5 file."); - H5Pclose(plist_id); - hid_t dataset_id; -#if H5Dopen_vers == 2 - dataset_id = H5Dopen2(file_id, name.c_str(), H5P_DEFAULT); -#else - dataset_id = H5Dopen(file_id, name.c_str()); -#endif - CHECK_ERROR(dataset_id,"Error opening dataset in file."); - - hid_t space_id = H5Dget_space(dataset_id); - hsize_t dims[2]; - H5Sget_simple_extent_dims(space_id, dims, NULL); - - hsize_t count[2]; - hsize_t offset[2]; - - hsize_t item_cnt = dims[0]/mpi_size+(dims[0]%mpi_size==0 ? 0 : 1); - hsize_t cnt = (mpi_rank(), memspace_id, space_id, plist_id, dataset.data); - CHECK_ERROR(status, "Error reading dataset"); - - H5Pclose(plist_id); - H5Sclose(space_id); - H5Sclose(memspace_id); - H5Dclose(dataset_id); - H5Fclose(file_id); -} -} -#endif // HAVE_MPI -} // namespace cvflann::mpi - -//! @endcond - -#endif /* OPENCV_FLANN_HDF5_H_ */ From 8c6339c04d7f9fe819926979907d87acb33f68d9 Mon Sep 17 00:00:00 2001 From: Vincent Rabaud Date: Thu, 14 Nov 2024 14:13:18 +0100 Subject: [PATCH 06/10] Remove internal calib3d_c_api.h The new C++ code is copy/pasted from OpenCV5: - functions initIntrinsicParams2D, subMatrix (the first 160 lines) - function prepareDistCoeffs - the different asserts Not all the API/code is ported to C++ yet to ease the review. --- modules/calib3d/src/calib3d_c_api.h | 94 --- modules/calib3d/src/calibration.cpp | 788 +++++++++++------------- modules/calib3d/src/compat_ptsetreg.cpp | 38 +- 3 files changed, 348 insertions(+), 572 deletions(-) delete mode 100644 modules/calib3d/src/calib3d_c_api.h diff --git a/modules/calib3d/src/calib3d_c_api.h b/modules/calib3d/src/calib3d_c_api.h deleted file mode 100644 index 68d3c20b78..0000000000 --- a/modules/calib3d/src/calib3d_c_api.h +++ /dev/null @@ -1,94 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2009, Willow Garage Inc., all rights reserved. -// Copyright (C) 2013, OpenCV Foundation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's 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. -// -// * The name of the copyright holders may not 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 Intel Corporation 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. -// -//M*/ - -#ifndef OPENCV_CALIB3D_C_API_H -#define OPENCV_CALIB3D_C_API_H - -#include "opencv2/core/core_c.h" -#include "opencv2/calib3d/calib3d_c.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/****************************************************************************************\ -* Camera Calibration, Pose Estimation and Stereo * -\****************************************************************************************/ - -/* Finds perspective transformation between the object plane and image (view) plane */ -int cvFindHomography( const CvMat* src_points, - const CvMat* dst_points, - CvMat* homography, - int method CV_DEFAULT(0), - double ransacReprojThreshold CV_DEFAULT(3), - CvMat* mask CV_DEFAULT(0), - int maxIters CV_DEFAULT(2000), - double confidence CV_DEFAULT(0.995)); - -/* Computes initial estimate of the intrinsic camera parameters - in case of planar calibration target (e.g. chessboard) */ -void cvInitIntrinsicParams2D( const CvMat* object_points, - const CvMat* image_points, - const CvMat* npoints, CvSize image_size, - CvMat* camera_matrix, - double aspect_ratio CV_DEFAULT(1.) ); - -/* Finds intrinsic and extrinsic camera parameters - from a few views of known calibration pattern */ -double cvCalibrateCamera2( const CvMat* object_points, - const CvMat* image_points, - const CvMat* point_counts, - CvSize image_size, - CvMat* camera_matrix, - CvMat* distortion_coeffs, - CvMat* rotation_vectors CV_DEFAULT(NULL), - CvMat* translation_vectors CV_DEFAULT(NULL), - int flags CV_DEFAULT(0), - CvTermCriteria term_crit CV_DEFAULT(cvTermCriteria( - CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,30,DBL_EPSILON)) ); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif /* OPENCV_CALIB3D_C_API_H */ diff --git a/modules/calib3d/src/calibration.cpp b/modules/calib3d/src/calibration.cpp index 58544909a2..12ce907f48 100644 --- a/modules/calib3d/src/calibration.cpp +++ b/modules/calib3d/src/calibration.cpp @@ -43,7 +43,8 @@ #include "precomp.hpp" #include "hal_replacement.hpp" #include "distortion_model.hpp" -#include "calib3d_c_api.h" +#include "opencv2/core/core_c.h" +#include "opencv2/calib3d/calib3d_c.h" #include #include @@ -55,69 +56,54 @@ The 1st initial port was done by Valery Mosyagin. */ -using namespace cv; +namespace cv { static const char* cvDistCoeffErr = "Distortion coefficients must be 1x4, 4x1, 1x5, 5x1, 1x8, 8x1, 1x12, 12x1, 1x14 or 14x1 floating-point vector"; -CV_IMPL void cvInitIntrinsicParams2D( const CvMat* objectPoints, - const CvMat* imagePoints, const CvMat* npoints, - CvSize imageSize, CvMat* cameraMatrix, +static void initIntrinsicParams2D( const Mat& objectPoints, + const Mat& imagePoints, const Mat& npoints, + Size imageSize, OutputArray cameraMatrix, double aspectRatio ) { - Ptr matA, _b, _allH; + CV_Assert(npoints.type() == CV_32SC1 && (npoints.rows == 1 || npoints.cols == 1) && npoints.isContinuous()); + int nimages = npoints.rows + npoints.cols - 1; - int i, j, pos, nimages, ni = 0; - double a[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - double H[9] = {0}, f[2] = {0}; - CvMat _a = cvMat( 3, 3, CV_64F, a ); - CvMat matH = cvMat( 3, 3, CV_64F, H ); - CvMat _f = cvMat( 2, 1, CV_64F, f ); + CV_Assert( objectPoints.type() == CV_32FC3 || + objectPoints.type() == CV_64FC3 ); + CV_Assert( imagePoints.type() == CV_32FC2 || + imagePoints.type() == CV_64FC2 ); - CV_Assert(npoints); - CV_Assert(CV_MAT_TYPE(npoints->type) == CV_32SC1); - CV_Assert(CV_IS_MAT_CONT(npoints->type)); - nimages = npoints->rows + npoints->cols - 1; - - if( (CV_MAT_TYPE(objectPoints->type) != CV_32FC3 && - CV_MAT_TYPE(objectPoints->type) != CV_64FC3) || - (CV_MAT_TYPE(imagePoints->type) != CV_32FC2 && - CV_MAT_TYPE(imagePoints->type) != CV_64FC2) ) - CV_Error( cv::Error::StsUnsupportedFormat, "Both object points and image points must be 2D" ); - - if( objectPoints->rows != 1 || imagePoints->rows != 1 ) + if( objectPoints.rows != 1 || imagePoints.rows != 1 ) CV_Error( cv::Error::StsBadSize, "object points and image points must be a single-row matrices" ); - matA.reset(cvCreateMat( 2*nimages, 2, CV_64F )); - _b.reset(cvCreateMat( 2*nimages, 1, CV_64F )); - a[2] = (!imageSize.width) ? 0.5 : (imageSize.width - 1)*0.5; - a[5] = (!imageSize.height) ? 0.5 : (imageSize.height - 1)*0.5; - _allH.reset(cvCreateMat( nimages, 9, CV_64F )); + Mat_ matA(2*nimages, 2); + Mat_ matb(2*nimages, 1, CV_64F ); + double fx, fy, cx, cy; + cx = (!imageSize.width ) ? 0.5 : (imageSize.width - 1)*0.5; + cy = (!imageSize.height) ? 0.5 : (imageSize.height - 1)*0.5; // extract vanishing points in order to obtain initial value for the focal length - for( i = 0, pos = 0; i < nimages; i++, pos += ni ) + int pos = 0; + for(int i = 0; i < nimages; i++ ) { - CV_DbgAssert(npoints->data.i); - CV_DbgAssert(matA && matA->data.db); - CV_DbgAssert(_b && _b->data.db); - double* Ap = matA->data.db + i*4; - double* bp = _b->data.db + i*2; - ni = npoints->data.i[i]; - double h[3], v[3], d1[3], d2[3]; - double n[4] = {0,0,0,0}; - CvMat _m, matM; - cvGetCols( objectPoints, &matM, pos, pos + ni ); - cvGetCols( imagePoints, &_m, pos, pos + ni ); + int ni = npoints.at(i); + Mat matM = objectPoints.colRange(pos, pos + ni); + Mat _m = imagePoints.colRange(pos, pos + ni); + pos += ni; - cvFindHomography( &matM, &_m, &matH ); - CV_DbgAssert(_allH && _allH->data.db); - memcpy( _allH->data.db + i*9, H, sizeof(H) ); + Matx33d H; + Mat matH0 = findHomography(matM, _m); + CV_Assert(matH0.size() == Size(3, 3)); + matH0.convertTo(H, CV_64F); - H[0] -= H[6]*a[2]; H[1] -= H[7]*a[2]; H[2] -= H[8]*a[2]; - H[3] -= H[6]*a[5]; H[4] -= H[7]*a[5]; H[5] -= H[8]*a[5]; + H(0, 0) -= H(2, 0)*cx; H(0, 1) -= H(2, 1)*cx; H(0, 2) -= H(2, 2)*cx; + H(1, 0) -= H(2, 0)*cy; H(1, 1) -= H(2, 1)*cy; H(1, 2) -= H(2, 2)*cy; - for( j = 0; j < 3; j++ ) + Vec3d h, v, d1, d2; + Vec4d n; + for(int j = 0; j < 3; j++ ) { - double t0 = H[j*3], t1 = H[j*3+1]; + double t0 = H(j, 0), t1 = H(j, 1); h[j] = t0; v[j] = t1; d1[j] = (t0 + t1)*0.5; d2[j] = (t0 - t1)*0.5; @@ -125,62 +111,65 @@ CV_IMPL void cvInitIntrinsicParams2D( const CvMat* objectPoints, n[2] += d1[j]*d1[j]; n[3] += d2[j]*d2[j]; } - for( j = 0; j < 4; j++ ) + for(int j = 0; j < 4; j++ ) n[j] = 1./std::sqrt(n[j]); - for( j = 0; j < 3; j++ ) + for(int j = 0; j < 3; j++ ) { h[j] *= n[0]; v[j] *= n[1]; d1[j] *= n[2]; d2[j] *= n[3]; } - Ap[0] = h[0]*v[0]; Ap[1] = h[1]*v[1]; - Ap[2] = d1[0]*d2[0]; Ap[3] = d1[1]*d2[1]; - bp[0] = -h[2]*v[2]; bp[1] = -d1[2]*d2[2]; + matA(i*2+0, 0) = h[0]*v[0]; matA(i*2+0, 1) = h[1]*v[1]; + matA(i*2+1, 0) = d1[0]*d2[0]; matA(i*2+1, 1) = d1[1]*d2[1]; + matb(i*2+0) = -h[2]*v[2]; + matb(i*2+1) = -d1[2]*d2[2]; } - cvSolve( matA, _b, &_f, CV_NORMAL + CV_SVD ); - a[0] = std::sqrt(fabs(1./f[0])); - a[4] = std::sqrt(fabs(1./f[1])); + Vec2d f; + solve(matA, matb, f, DECOMP_NORMAL + DECOMP_SVD); + fx = std::sqrt(fabs(1./f[0])); + fy = std::sqrt(fabs(1./f[1])); if( aspectRatio != 0 ) { - double tf = (a[0] + a[4])/(aspectRatio + 1.); - a[0] = aspectRatio*tf; - a[4] = tf; + double tf = (fx + fy)/(aspectRatio + 1.); + fx = aspectRatio*tf; + fy = tf; } - - cvConvert( &_a, cameraMatrix ); + Mat(Matx33d(fx, 0, cx, + 0, fy, cy, + 0, 0, 1)).copyTo(cameraMatrix); } -static void subMatrix(const cv::Mat& src, cv::Mat& dst, const std::vector& cols, - const std::vector& rows) { - int nonzeros_cols = cv::countNonZero(cols); - cv::Mat tmp(src.rows, nonzeros_cols, CV_64FC1); - - for (int i = 0, j = 0; i < (int)cols.size(); i++) +static void subMatrix(const Mat& src, Mat& dst, + const std::vector& cols, + const std::vector& rows) +{ + CV_Assert(src.type() == CV_64F && dst.type() == CV_64F); + int m = (int)rows.size(), n = (int)cols.size(); + int i1 = 0, j1 = 0; + const uchar* colsdata = cols.empty() ? 0 : &cols[0]; + for(int i = 0; i < m; i++) { - if (cols[i]) + if(rows[i]) { - src.col(i).copyTo(tmp.col(j++)); - } - } + const double* srcptr = src.ptr(i); + double* dstptr = dst.ptr(i1++); - int nonzeros_rows = cv::countNonZero(rows); - dst.create(nonzeros_rows, nonzeros_cols, CV_64FC1); - for (int i = 0, j = 0; i < (int)rows.size(); i++) - { - if (rows[i]) - { - tmp.row(i).copyTo(dst.row(j++)); + for(int j = j1 = 0; j < n; j++) + { + if(colsdata[j]) + dstptr[j1++] = srcptr[j]; + } } } } -static double cvCalibrateCamera2Internal( const CvMat* objectPoints, +static double calibrateCameraInternal( const CvMat* objectPoints, const CvMat* imagePoints, const CvMat* npoints, CvSize imageSize, int iFixedPoint, CvMat* cameraMatrix, CvMat* distCoeffs, - CvMat* rvecs, CvMat* tvecs, CvMat* newObjPoints, CvMat* stdDevs, - CvMat* perViewErrors, int flags, CvTermCriteria termCrit ) + Mat rvecs, Mat tvecs, Mat newObjPoints, Mat stdDevs, + Mat perViewErr, int flags, const CvTermCriteria& termCrit ) { const int NINTRINSIC = CV_CALIB_NINTRINSIC; double reprojErr = 0; @@ -188,7 +177,7 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, Matx33d A; double k[14] = {0}; CvMat matA = cvMat(3, 3, CV_64F, A.val), _k; - int i, nimages, maxPoints = 0, ni = 0, pos, total = 0, nparams, npstep, cn; + int nimages, maxPoints = 0, ni = 0, total = 0, nparams, npstep; double aspectRatio = 0.; // 0. check the parameters & allocate buffers @@ -220,42 +209,23 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, nimages = npoints->rows*npoints->cols; npstep = npoints->rows == 1 ? 1 : npoints->step/CV_ELEM_SIZE(npoints->type); - if( rvecs ) - { - cn = CV_MAT_CN(rvecs->type); - if( !CV_IS_MAT(rvecs) || - (CV_MAT_DEPTH(rvecs->type) != CV_32F && CV_MAT_DEPTH(rvecs->type) != CV_64F) || - ((rvecs->rows != nimages || (rvecs->cols*cn != 3 && rvecs->cols*cn != 9)) && - (rvecs->rows != 1 || rvecs->cols != nimages || cn != 3)) ) - CV_Error( cv::Error::StsBadArg, "the output array of rotation vectors must be 3-channel " - "1xn or nx1 array or 1-channel nx3 or nx9 array, where n is the number of views" ); - } - if( tvecs ) + if( !rvecs.empty() ) { - cn = CV_MAT_CN(tvecs->type); - if( !CV_IS_MAT(tvecs) || - (CV_MAT_DEPTH(tvecs->type) != CV_32F && CV_MAT_DEPTH(tvecs->type) != CV_64F) || - ((tvecs->rows != nimages || tvecs->cols*cn != 3) && - (tvecs->rows != 1 || tvecs->cols != nimages || cn != 3)) ) - CV_Error( cv::Error::StsBadArg, "the output array of translation vectors must be 3-channel " - "1xn or nx1 array or 1-channel nx3 array, where n is the number of views" ); + int cn = rvecs.channels(); + CV_Assert(rvecs.depth() == CV_32F || rvecs.depth() == CV_64F); + CV_Assert((rvecs.rows == nimages && (rvecs.cols*cn == 3 || rvecs.cols*cn == 3)) || + (rvecs.rows == 1 && rvecs.cols == nimages && cn == 3)); } bool releaseObject = iFixedPoint > 0 && iFixedPoint < npoints->data.i[0] - 1; - if( stdDevs && !releaseObject ) + if( !tvecs.empty() ) { - cn = CV_MAT_CN(stdDevs->type); - if( !CV_IS_MAT(stdDevs) || - (CV_MAT_DEPTH(stdDevs->type) != CV_32F && CV_MAT_DEPTH(stdDevs->type) != CV_64F) || - ((stdDevs->rows != (nimages*6 + NINTRINSIC) || stdDevs->cols*cn != 1) && - (stdDevs->rows != 1 || stdDevs->cols != (nimages*6 + NINTRINSIC) || cn != 1)) ) -#define STR__(x) #x -#define STR_(x) STR__(x) - CV_Error( cv::Error::StsBadArg, "the output array of standard deviations vectors must be 1-channel " - "1x(n*6 + NINTRINSIC) or (n*6 + NINTRINSIC)x1 array, where n is the number of views," - " NINTRINSIC = " STR_(CV_CALIB_NINTRINSIC)); + int cn = tvecs.channels(); + CV_Assert(tvecs.depth() == CV_32F || tvecs.depth() == CV_64F); + CV_Assert((tvecs.rows == nimages && tvecs.cols*cn == 3) || + (tvecs.rows == 1 && tvecs.cols == nimages && cn == 3)); } if( (CV_MAT_TYPE(cameraMatrix->type) != CV_32FC1 && @@ -274,7 +244,7 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, distCoeffs->cols*distCoeffs->rows != 14) ) CV_Error( cv::Error::StsBadArg, cvDistCoeffErr ); - for( i = 0; i < nimages; i++ ) + for(int i = 0; i < nimages; i++ ) { ni = npoints->data.i[i*npstep]; if( ni < 4 ) @@ -285,27 +255,22 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, total += ni; } - if( newObjPoints ) + if( !newObjPoints.empty() ) { - cn = CV_MAT_CN(newObjPoints->type); - if( !CV_IS_MAT(newObjPoints) || - (CV_MAT_DEPTH(newObjPoints->type) != CV_32F && CV_MAT_DEPTH(newObjPoints->type) != CV_64F) || - ((newObjPoints->rows != maxPoints || newObjPoints->cols*cn != 3) && - (newObjPoints->rows != 1 || newObjPoints->cols != maxPoints || cn != 3)) ) - CV_Error( cv::Error::StsBadArg, "the output array of refined object points must be 3-channel " - "1xn or nx1 array or 1-channel nx3 array, where n is the number of object points per view" ); + int cn = newObjPoints.channels(); + CV_Assert(newObjPoints.depth() == CV_32F || newObjPoints.depth() == CV_64F); + CV_Assert((newObjPoints.rows == maxPoints && newObjPoints.cols*cn == 3) || + (newObjPoints.rows == 1 && newObjPoints.cols == maxPoints && cn == 3)); } - if( stdDevs && releaseObject ) + if( !stdDevs.empty() && releaseObject ) { - cn = CV_MAT_CN(stdDevs->type); - if( !CV_IS_MAT(stdDevs) || - (CV_MAT_DEPTH(stdDevs->type) != CV_32F && CV_MAT_DEPTH(stdDevs->type) != CV_64F) || - ((stdDevs->rows != (nimages*6 + NINTRINSIC + maxPoints*3) || stdDevs->cols*cn != 1) && - (stdDevs->rows != 1 || stdDevs->cols != (nimages*6 + NINTRINSIC + maxPoints*3) || cn != 1)) ) - CV_Error( cv::Error::StsBadArg, "the output array of standard deviations vectors must be 1-channel " - "1x(n*6 + NINTRINSIC + m*3) or (n*6 + NINTRINSIC + m*3)x1 array, where n is the number of views," - " NINTRINSIC = " STR_(CV_CALIB_NINTRINSIC) ", m is the number of object points per view"); + int cn = stdDevs.channels(); + CV_Assert(stdDevs.depth() == CV_32F || stdDevs.depth() == CV_64F); + int nstddev = nimages*6 + NINTRINSIC + (releaseObject ? maxPoints*3 : 0); + + CV_Assert((stdDevs.rows == nstddev && stdDevs.cols*cn == 1) || + (stdDevs.rows == 1 && stdDevs.cols == nstddev && cn == 1)); } Mat matM( 1, total, CV_64FC3 ); @@ -373,7 +338,7 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, if( fabs(mean[2]) > 1e-5 || fabs(sdv[2]) > 1e-5 ) CV_Error( cv::Error::StsBadArg, "For non-planar calibration rigs the initial intrinsic matrix must be specified" ); - for( i = 0; i < total; i++ ) + for(int i = 0; i < total; i++ ) matM.at(i).z = 0.; if( flags & CALIB_FIX_ASPECT_RATIO ) @@ -384,8 +349,7 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, CV_Error( cv::Error::StsOutOfRange, "The specified aspect ratio (= cameraMatrix[0][0] / cameraMatrix[1][1]) is incorrect" ); } - CvMat _matM = cvMat(matM), m = cvMat(_m); - cvInitIntrinsicParams2D( &_matM, &m, npoints, imageSize, &matA, aspectRatio ); + initIntrinsicParams2D( matM, _m, cvarrToMat(npoints), imageSize, cvarrToMat(&matA), aspectRatio ); } CvLevMarq solver( nparams, 0, termCrit ); @@ -394,7 +358,7 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, Mat _Je( maxPoints*2, 6, CV_64FC1 ); Mat _err( maxPoints*2, 1, CV_64FC1 ); - const bool allocJo = (solver.state == CvLevMarq::CALC_J) || stdDevs || releaseObject; + const bool allocJo = (solver.state == CvLevMarq::CALC_J) || !stdDevs.empty() || releaseObject; Mat _Jo = allocJo ? Mat( maxPoints*2, maxPoints*3, CV_64FC1, Scalar(0) ) : Mat(); if(flags & CALIB_USE_LU) { @@ -432,9 +396,7 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, mask[ 4] = !(flags & CALIB_FIX_K1); mask[ 5] = !(flags & CALIB_FIX_K2); if( flags & CALIB_FIX_TANGENT_DIST ) - { - mask[6] = mask[7] = 0; - } + mask[6] = mask[7] = 0; mask[ 8] = !(flags & CALIB_FIX_K3); mask[ 9] = !(flags & CALIB_FIX_K4); mask[10] = !(flags & CALIB_FIX_K5); @@ -448,23 +410,22 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, mask[15] = 0; } if(flags & CALIB_FIX_TAUX_TAUY) - { - mask[16] = 0; - mask[17] = 0; - } + mask[16] = mask[17] = 0; if(releaseObject) { // copy object points + int s = NINTRINSIC + nimages * 6; + std::copy( matM.ptr(), matM.ptr( 0, maxPoints - 1 ) + 3, param + NINTRINSIC + nimages * 6 ); // fix points - mask[NINTRINSIC + nimages * 6] = 0; - mask[NINTRINSIC + nimages * 6 + 1] = 0; - mask[NINTRINSIC + nimages * 6 + 2] = 0; - mask[NINTRINSIC + nimages * 6 + iFixedPoint * 3] = 0; - mask[NINTRINSIC + nimages * 6 + iFixedPoint * 3 + 1] = 0; - mask[NINTRINSIC + nimages * 6 + iFixedPoint * 3 + 2] = 0; + mask[s + 0] = 0; + mask[s + 1] = 0; + mask[s + 2] = 0; + mask[s + iFixedPoint * 3 + 0] = 0; + mask[s + iFixedPoint * 3 + 1] = 0; + mask[s + iFixedPoint * 3 + 2] = 0; mask[nparams - 1] = 0; } } @@ -472,11 +433,11 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, Mat mask = cvarrToMat(solver.mask); int nparams_nz = countNonZero(mask); if (nparams_nz >= 2 * total) - CV_Error_(cv::Error::StsBadArg, + CV_Error_(Error::StsBadArg, ("There should be less vars to optimize (having %d) than the number of residuals (%d = 2 per point)", nparams_nz, 2 * total)); // 2. initialize extrinsic parameters - for( i = 0, pos = 0; i < nimages; i++, pos += ni ) + for(int i = 0, pos = 0; i < nimages; i++, pos += ni ) { CvMat _ri, _ti; ni = npoints->data.i[i*npstep]; @@ -492,6 +453,9 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, cvarrToMat(&_k), r_mat, t_mat, /*useExtrinsicGuess=*/0 ); } + //std::cout << "single camera calib. param before LM: " << param0.t() << "\n"; + //std::cout << "single camera calib. mask: " << mask0.t() << "\n"; + // 3. run the optimization for(;;) { @@ -500,7 +464,7 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, double* _errNorm = 0; bool proceed = solver.updateAlt( _param, _JtJ, _JtErr, _errNorm ); double *param = solver.param->data.db, *pparam = solver.prevParam->data.db; - bool calcJ = solver.state == CvLevMarq::CALC_J || (!proceed && stdDevs); + bool calcJ = solver.state == CvLevMarq::CALC_J || (!proceed && !stdDevs.empty()); if( flags & CALIB_FIX_ASPECT_RATIO ) { @@ -511,14 +475,14 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, A(0, 0) = param[0]; A(1, 1) = param[1]; A(0, 2) = param[2]; A(1, 2) = param[3]; std::copy(param + 4, param + 4 + 14, k); - if ( !proceed && !stdDevs && !perViewErrors ) + if ( !proceed && stdDevs.empty() && perViewErr.empty() ) break; - else if ( !proceed && stdDevs ) + else if ( !proceed && !stdDevs.empty() ) cvZero(_JtJ); reprojErr = 0; - for( i = 0, pos = 0; i < nimages; i++, pos += ni ) + for(int i = 0, pos = 0; i < nimages; i++, pos += ni ) { CvMat _ri, _ti; ni = npoints->data.i[i*npstep]; @@ -555,7 +519,7 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, cvarrToMat(&_k), cvarrToMat(&_mp) ); cvSub( &_mp, &_mi, &_mp ); - if (perViewErrors || stdDevs) + if (!perViewErr.empty() || !stdDevs.empty()) cvCopy(&_mp, &_me); if( calcJ ) @@ -585,8 +549,8 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, double viewErr = norm(_err, NORM_L2SQR); - if( perViewErrors ) - perViewErrors->data.db[i] = std::sqrt(viewErr / ni); + if( !perViewErr.empty() ) + perViewErr.at(i) = std::sqrt(viewErr / ni); reprojErr += viewErr; } @@ -595,7 +559,7 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, if( !proceed ) { - if( stdDevs ) + if( !stdDevs.empty() ) { Mat JtJinv, JtJN; JtJN.create(nparams_nz, nparams_nz, CV_64F); @@ -607,11 +571,10 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, // see the discussion for more details: https://github.com/opencv/opencv/pull/22992 int nErrors = 2 * total - nparams_nz; double sigma2 = norm(allErrors, NORM_L2SQR) / nErrors; - Mat stdDevsM = cvarrToMat(stdDevs); int j = 0; for ( int s = 0; s < nparams; s++ ) { - stdDevsM.at(s) = mask.data[s] ? std::sqrt(JtJinv.at(j,j) * sigma2) : 0.0; + stdDevs.at(s) = mask.data[s] ? std::sqrt(JtJinv.at(j,j) * sigma2) : 0.0; if( mask.data[s] ) j++; } @@ -623,63 +586,44 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, // 4. store the results cvConvert( &matA, cameraMatrix ); cvConvert( &_k, distCoeffs ); - if( newObjPoints && releaseObject ) + if( !newObjPoints.empty() && releaseObject ) { - CvMat _Mi; - cvGetRows( solver.param, &_Mi, NINTRINSIC + nimages * 6, - NINTRINSIC + nimages * 6 + maxPoints * 3 ); - cvReshape( &_Mi, &_Mi, 3, 1 ); - cvConvert( &_Mi, newObjPoints ); + int s = NINTRINSIC + nimages * 6; + Mat _Mi = cvarrToMat(solver.param).rowRange(s, s + maxPoints * 3); + _Mi.reshape(3, 1).convertTo(newObjPoints, newObjPoints.type()); } - for( i = 0, pos = 0; i < nimages; i++ ) + for(int i = 0; i < nimages; i++ ) { - CvMat src, dst; - - if( rvecs ) + if( !rvecs.empty() ) { - src = cvMat( 3, 1, CV_64F, solver.param->data.db + NINTRINSIC + i*6 ); - if( rvecs->rows == nimages && rvecs->cols*CV_MAT_CN(rvecs->type) == 9 ) + Mat src = Mat(3, 1, CV_64F, solver.param->data.db + NINTRINSIC + i*6); + if( rvecs.rows == nimages && rvecs.cols*rvecs.channels() == 9 ) { - dst = cvMat( 3, 3, CV_MAT_DEPTH(rvecs->type), - rvecs->data.ptr + rvecs->step*i ); - Rodrigues( cvarrToMat(&src), cvarrToMat(&matA) ); - cvConvert( &matA, &dst ); + Mat dst(3, 3, rvecs.depth(), rvecs.ptr(i)); + Rodrigues(src, A); + Mat(A).convertTo(dst, dst.type()); } else { - dst = cvMat( 3, 1, CV_MAT_DEPTH(rvecs->type), rvecs->rows == 1 ? - rvecs->data.ptr + i*CV_ELEM_SIZE(rvecs->type) : - rvecs->data.ptr + rvecs->step*i ); - cvConvert( &src, &dst ); + Mat dst(3, 1, rvecs.depth(), rvecs.rows == 1 ? + rvecs.data + i*rvecs.elemSize() : rvecs.ptr(i)); + src.convertTo(dst, dst.type()); } } - if( tvecs ) + if( !tvecs.empty() ) { - src = cvMat( 3, 1, CV_64F, solver.param->data.db + NINTRINSIC + i*6 + 3 ); - dst = cvMat( 3, 1, CV_MAT_DEPTH(tvecs->type), tvecs->rows == 1 ? - tvecs->data.ptr + i*CV_ELEM_SIZE(tvecs->type) : - tvecs->data.ptr + tvecs->step*i ); - cvConvert( &src, &dst ); - } + Mat src(3, 1, CV_64F, solver.param->data.db + NINTRINSIC + i*6 + 3); + Mat dst(3, 1, tvecs.depth(), tvecs.rows == 1 ? + tvecs.data + i*tvecs.elemSize() : tvecs.ptr(i)); + src.convertTo(dst, dst.type()); + } } return std::sqrt(reprojErr/total); } -/* finds intrinsic and extrinsic camera parameters - from a few views of known calibration pattern */ -CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints, - const CvMat* imagePoints, const CvMat* npoints, - CvSize imageSize, CvMat* cameraMatrix, CvMat* distCoeffs, - CvMat* rvecs, CvMat* tvecs, int flags, CvTermCriteria termCrit ) -{ - return cvCalibrateCamera2Internal(objectPoints, imagePoints, npoints, imageSize, -1, cameraMatrix, - distCoeffs, rvecs, tvecs, NULL, NULL, NULL, flags, termCrit); -} - - //////////////////////////////// Stereo Calibration /////////////////////////////////// static int dbCmp( const void* _a, const void* _b ) @@ -690,14 +634,15 @@ static int dbCmp( const void* _a, const void* _b ) return (a > b) - (a < b); } -static double cvStereoCalibrateImpl( const CvMat* _objectPoints, const CvMat* _imagePoints1, +static double stereoCalibrateImpl( const CvMat* _objectPoints, const CvMat* _imagePoints1, const CvMat* _imagePoints2, const CvMat* _npoints, CvMat* _cameraMatrix1, CvMat* _distCoeffs1, CvMat* _cameraMatrix2, CvMat* _distCoeffs2, CvSize imageSize, CvMat* matR, CvMat* matT, - CvMat* matE, CvMat* matF, - CvMat* rvecs, CvMat* tvecs, CvMat* perViewErr, int flags, - CvTermCriteria termCrit ) + Mat matE, Mat matF, + Mat rvecs, Mat tvecs, + Mat perViewErr, int flags, + CvTermCriteria termCrit ) { const int NINTRINSIC = 18; Ptr npoints, imagePoints[2], objectPoints, RT0; @@ -709,7 +654,7 @@ static double cvStereoCalibrateImpl( const CvMat* _objectPoints, const CvMat* _i int i, k, p, ni = 0, ofs, nimages, pointsTotal, maxPoints = 0; int nparams; bool recomputeIntrinsics = false; - double aspectRatio[2] = {0}; + double aspectRatio[2] = {0, 0}; CV_Assert( CV_IS_MAT(_imagePoints1) && CV_IS_MAT(_imagePoints2) && CV_IS_MAT(_objectPoints) && CV_IS_MAT(_npoints) && @@ -736,24 +681,23 @@ static double cvStereoCalibrateImpl( const CvMat* _objectPoints, const CvMat* _i cvConvert( _objectPoints, objectPoints ); cvReshape( objectPoints, objectPoints, 3, 1 ); - if( rvecs ) + if( !rvecs.empty() ) { - int cn = CV_MAT_CN(rvecs->type); - if( !CV_IS_MAT(rvecs) || - (CV_MAT_DEPTH(rvecs->type) != CV_32F && CV_MAT_DEPTH(rvecs->type) != CV_64F) || - ((rvecs->rows != nimages || (rvecs->cols*cn != 3 && rvecs->cols*cn != 9)) && - (rvecs->rows != 1 || rvecs->cols != nimages || cn != 3)) ) + int cn = rvecs.channels(); + int depth = rvecs.depth(); + if( (depth != CV_32F && depth != CV_64F) || + ((rvecs.rows != nimages || (rvecs.cols*cn != 3 && rvecs.cols*cn != 9)) && + (rvecs.rows != 1 || rvecs.cols != nimages || cn != 3)) ) CV_Error( cv::Error::StsBadArg, "the output array of rotation vectors must be 3-channel " "1xn or nx1 array or 1-channel nx3 or nx9 array, where n is the number of views" ); } - - if( tvecs ) + if( !tvecs.empty() ) { - int cn = CV_MAT_CN(tvecs->type); - if( !CV_IS_MAT(tvecs) || - (CV_MAT_DEPTH(tvecs->type) != CV_32F && CV_MAT_DEPTH(tvecs->type) != CV_64F) || - ((tvecs->rows != nimages || tvecs->cols*cn != 3) && - (tvecs->rows != 1 || tvecs->cols != nimages || cn != 3)) ) + int cn = tvecs.channels(); + int depth = tvecs.depth(); + if( (depth != CV_32F && depth != CV_64F) || + ((tvecs.rows != nimages || tvecs.cols*cn != 3) && + (tvecs.rows != 1 || tvecs.cols != nimages || cn != 3)) ) CV_Error( cv::Error::StsBadArg, "the output array of translation vectors must be 3-channel " "1xn or nx1 array or 1-channel nx3 array, where n is the number of views" ); } @@ -791,8 +735,9 @@ static double cvStereoCalibrateImpl( const CvMat* _objectPoints, const CvMat* _i if( !(flags & (CALIB_FIX_INTRINSIC|CALIB_USE_INTRINSIC_GUESS))) { - cvCalibrateCamera2( objectPoints, imagePoints[k], - npoints, imageSize, &K[k], &Dist[k], NULL, NULL, flags ); + calibrateCameraInternal( objectPoints, imagePoints[k], + npoints, imageSize, -1, &K[k], &Dist[k], Mat(), Mat(), + Mat(), Mat(), Mat(), flags, termCrit ); } } @@ -818,6 +763,10 @@ static double cvStereoCalibrateImpl( const CvMat* _objectPoints, const CvMat* _i // we optimize for the inter-camera R(3),t(3), then, optionally, // for intrinisic parameters of each camera ((fx,fy,cx,cy,k1,k2,p1,p2) ~ 8 parameters). + // Param mapping is: + // - from 0 next 6: stereo pair Rt, from 6+i*6 next 6: Rt for each ith camera of nimages, + // - from 6*(nimages+1) next NINTRINSICS: intrinsics for 1st camera: fx, fy, cx, cy, 14 x dist + // - next NINTRINSICS: the same for for 2nd camera nparams = 6*(nimages+1) + (recomputeIntrinsics ? NINTRINSIC*2 : 0); CvLevMarq solver( nparams, 0, termCrit ); @@ -1130,10 +1079,8 @@ static double cvStereoCalibrateImpl( const CvMat* _objectPoints, const CvMat* _i } double viewErr = norm(err, NORM_L2SQR); - - if(perViewErr) - perViewErr->data.db[i*2 + k] = std::sqrt(viewErr/ni); - + if(!perViewErr.empty()) + perViewErr.at(i, k) = std::sqrt(viewErr/ni); reprojErr += viewErr; } } @@ -1162,86 +1109,70 @@ static double cvStereoCalibrateImpl( const CvMat* _objectPoints, const CvMat* _i } } - if( matE || matF ) + if( !matE.empty() || !matF.empty() ) { double* t = T_LR.data.db; - double tx[] = + Matx33d Tx(0, -t[2], t[1], + t[2], 0, -t[0], + -t[1], t[0], 0); + Matx33d E = Mat(Tx*cvarrToMat(&R_LR)); + if( !matE.empty() ) + Mat(E).convertTo(matE, matE.depth()); + if( !matF.empty()) { - 0, -t[2], t[1], - t[2], 0, -t[0], - -t[1], t[0], 0 - }; - CvMat Tx = cvMat(3, 3, CV_64F, tx); - double e[9], f[9]; - CvMat E = cvMat(3, 3, CV_64F, e); - CvMat F = cvMat(3, 3, CV_64F, f); - cvMatMul( &Tx, &R_LR, &E ); - if( matE ) - cvConvert( &E, matE ); - if( matF ) - { - double ik[9]; - CvMat iK = cvMat(3, 3, CV_64F, ik); - cvInvert(&K[1], &iK); - cvGEMM( &iK, &E, 1, 0, 0, &E, CV_GEMM_A_T ); - cvInvert(&K[0], &iK); - cvMatMul(&E, &iK, &F); - cvConvertScale( &F, matF, fabs(f[8]) > 0 ? 1./f[8] : 1 ); + Matx33d iA0 = Mat(cvarrToMat(&K[0]).inv()), iA1 = Mat(cvarrToMat(&K[1]).inv()); + Matx33d F = iA1.t() * E * iA0; + Mat(F).convertTo(matF, matF.depth(), fabs(F(2,2)) > 0 ? 1./F(2,2) : 1.); } } - CvMat tmp = cvMat(3, 3, CV_64F); + double* param = solver.param->data.db; + Mat r1d = rvecs.empty() ? Mat() : rvecs.reshape(1, nimages); + Mat t1d = tvecs.empty() ? Mat() : tvecs.reshape(1, nimages); for( i = 0; i < nimages; i++ ) { - CvMat src, dst; + int idx = (i + 1) * 6; - if( rvecs ) + if( !rvecs.empty() ) { - src = cvMat(3, 1, CV_64F, solver.param->data.db+(i+1)*6); - if( rvecs->rows == nimages && rvecs->cols*CV_MAT_CN(rvecs->type) == 9 ) + Vec3d srcR(param[idx + 0], param[idx + 1], param[idx + 2]); + if( rvecs.rows * rvecs.cols * rvecs.channels() == nimages * 9 ) { - dst = cvMat(3, 3, CV_MAT_DEPTH(rvecs->type), - rvecs->data.ptr + rvecs->step*i); - Rodrigues( cvarrToMat(&src), cvarrToMat(&tmp) ); - cvConvert( &tmp, &dst ); + Matx33d rod; + Rodrigues(srcR, rod); + Mat(rod).convertTo(r1d.row(i).reshape(1, 3), rvecs.depth()); } - else + else if (rvecs.rows * rvecs.cols * rvecs.channels() == nimages * 3 ) { - dst = cvMat(3, 1, CV_MAT_DEPTH(rvecs->type), rvecs->rows == 1 ? - rvecs->data.ptr + i*CV_ELEM_SIZE(rvecs->type) : - rvecs->data.ptr + rvecs->step*i); - cvConvert( &src, &dst ); + Mat(Mat(srcR).t()).convertTo(r1d.row(i), rvecs.depth()); } } - if( tvecs ) + if( !tvecs.empty() ) { - src = cvMat(3, 1,CV_64F,solver.param->data.db+(i+1)*6+3); - dst = cvMat(3, 1, CV_MAT_DEPTH(tvecs->type), tvecs->rows == 1 ? - tvecs->data.ptr + i*CV_ELEM_SIZE(tvecs->type) : - tvecs->data.ptr + tvecs->step*i); - cvConvert( &src, &dst ); - } + Vec3d srcT(param[idx + 3], param[idx + 4], param[idx + 5]); + Mat(Mat(srcT).t()).convertTo(t1d.row(i), tvecs.depth()); + } } return std::sqrt(reprojErr/(pointsTotal*2)); } -namespace cv -{ - static void collectCalibrationData( InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2, int iFixedPoint, - Mat& objPtMat, Mat& imgPtMat1, Mat* imgPtMat2, - Mat& npoints ) + OutputArray objPt, OutputArray imgPt1, OutputArray imgPt2, + OutputArray npoints ) { int nimages = (int)objectPoints.total(); int total = 0; CV_Assert(nimages > 0); CV_CheckEQ(nimages, (int)imagePoints1.total(), ""); - if (imgPtMat2) + if (!imagePoints2.empty()) + { CV_CheckEQ(nimages, (int)imagePoints2.total(), ""); + CV_Assert(imgPt2.needed()); + } for (int i = 0; i < nimages; i++) { @@ -1264,25 +1195,28 @@ static void collectCalibrationData( InputArrayOfArrays objectPoints, } npoints.create(1, (int)nimages, CV_32S); - objPtMat.create(1, (int)total, CV_32FC3); - imgPtMat1.create(1, (int)total, CV_32FC2); + objPt.create(1, (int)total, CV_32FC3); + imgPt1.create(1, (int)total, CV_32FC2); Point2f* imgPtData2 = 0; - if (imgPtMat2) + Mat imgPt1Mat = imgPt1.getMat(); + if (!imagePoints2.empty()) { - imgPtMat2->create(1, (int)total, CV_32FC2); - imgPtData2 = imgPtMat2->ptr(); + imgPt2.create(1, (int)total, CV_32FC2); + imgPtData2 = imgPt2.getMat().ptr(); } + Mat nPointsMat = npoints.getMat(); + Mat objPtMat = objPt.getMat(); Point3f* objPtData = objPtMat.ptr(); - Point2f* imgPtData1 = imgPtMat1.ptr(); + Point2f* imgPtData1 = imgPt1.getMat().ptr(); for (int i = 0, j = 0; i < nimages; i++) { Mat objpt = objectPoints.getMat(i); Mat imgpt1 = imagePoints1.getMat(i); int numberOfObjectPoints = objpt.checkVector(3, CV_32F); - npoints.at(i) = numberOfObjectPoints; + nPointsMat.at(i) = numberOfObjectPoints; for (int n = 0; n < numberOfObjectPoints; ++n) { objPtData[j + n] = objpt.ptr()[n]; @@ -1303,14 +1237,14 @@ static void collectCalibrationData( InputArrayOfArrays objectPoints, j += numberOfObjectPoints; } - int ni = npoints.at(0); + int ni = nPointsMat.at(0); bool releaseObject = iFixedPoint > 0 && iFixedPoint < ni - 1; // check object points. If not qualified, report errors. if( releaseObject ) { for (int i = 1; i < nimages; i++) { - if( npoints.at(i) != ni ) + if( nPointsMat.at(i) != ni ) { CV_Error( cv::Error::StsBadArg, "All objectPoints[i].size() should be equal when " "object-releasing method is requested." ); @@ -1329,10 +1263,10 @@ static void collectCalibrationData( InputArrayOfArrays objectPoints, static void collectCalibrationData( InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2, - Mat& objPtMat, Mat& imgPtMat1, Mat* imgPtMat2, - Mat& npoints ) + OutputArray objPt, OutputArray imgPtMat1, OutputArray imgPtMat2, + OutputArray npoints ) { - collectCalibrationData( objectPoints, imagePoints1, imagePoints2, -1, objPtMat, imgPtMat1, + collectCalibrationData( objectPoints, imagePoints1, imagePoints2, -1, objPt, imgPtMat1, imgPtMat2, npoints ); } @@ -1346,50 +1280,38 @@ static Mat prepareCameraMatrix(Mat& cameraMatrix0, int rtype, int flags) return cameraMatrix; } -static Mat prepareDistCoeffs(Mat& distCoeffs0, int rtype, int outputSize = 14) +Mat initCameraMatrix2D( InputArrayOfArrays objectPoints, + InputArrayOfArrays imagePoints, + Size imageSize, double aspectRatio ) { + CV_INSTRUMENT_REGION(); + + Mat objPt, imgPt, npoints, cameraMatrix; + collectCalibrationData( objectPoints, imagePoints, noArray(), + objPt, imgPt, noArray(), npoints ); + initIntrinsicParams2D( objPt, imgPt, npoints, imageSize, cameraMatrix, aspectRatio ); + return cameraMatrix; +} + +static Mat prepareDistCoeffs(Mat& distCoeffs0, int rtype, int outputSize) +{ + Size sz = distCoeffs0.size(); + int n = sz.area(); + if (n > 0) + CV_Assert(sz.width == 1 || sz.height == 1); CV_Assert((int)distCoeffs0.total() <= outputSize); - Mat distCoeffs = Mat::zeros(distCoeffs0.cols == 1 ? Size(1, outputSize) : Size(outputSize, 1), rtype); - if( distCoeffs0.size() == Size(1, 4) || - distCoeffs0.size() == Size(1, 5) || - distCoeffs0.size() == Size(1, 8) || - distCoeffs0.size() == Size(1, 12) || - distCoeffs0.size() == Size(1, 14) || - distCoeffs0.size() == Size(4, 1) || - distCoeffs0.size() == Size(5, 1) || - distCoeffs0.size() == Size(8, 1) || - distCoeffs0.size() == Size(12, 1) || - distCoeffs0.size() == Size(14, 1) ) + Mat distCoeffs = Mat::zeros(sz.width == 1 ? Size(1, outputSize) : Size(outputSize, 1), rtype); + if( n == 4 || n == 5 || n == 8 || n == 12 || n == 14 ) { - Mat dstCoeffs(distCoeffs, Rect(0, 0, distCoeffs0.cols, distCoeffs0.rows)); - distCoeffs0.convertTo(dstCoeffs, rtype); + distCoeffs0.convertTo(distCoeffs(Rect(Point(), sz)), rtype); } return distCoeffs; } -} // namespace cv - -cv::Mat cv::initCameraMatrix2D( InputArrayOfArrays objectPoints, - InputArrayOfArrays imagePoints, - Size imageSize, double aspectRatio ) -{ - CV_INSTRUMENT_REGION(); - - Mat objPt, imgPt, npoints, cameraMatrix(3, 3, CV_64F); - collectCalibrationData( objectPoints, imagePoints, noArray(), - objPt, imgPt, 0, npoints ); - CvMat _objPt = cvMat(objPt), _imgPt = cvMat(imgPt), _npoints = cvMat(npoints), _cameraMatrix = cvMat(cameraMatrix); - cvInitIntrinsicParams2D( &_objPt, &_imgPt, &_npoints, - cvSize(imageSize), &_cameraMatrix, aspectRatio ); - return cameraMatrix; -} - - - -double cv::calibrateCamera( InputArrayOfArrays _objectPoints, - InputArrayOfArrays _imagePoints, - Size imageSize, InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs, - OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, int flags, TermCriteria criteria ) +double calibrateCamera( InputArrayOfArrays _objectPoints, + InputArrayOfArrays _imagePoints, + Size imageSize, InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs, + OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, int flags, TermCriteria criteria ) { CV_INSTRUMENT_REGION(); @@ -1397,13 +1319,13 @@ double cv::calibrateCamera( InputArrayOfArrays _objectPoints, _rvecs, _tvecs, noArray(), noArray(), noArray(), flags, criteria); } -double cv::calibrateCamera(InputArrayOfArrays _objectPoints, - InputArrayOfArrays _imagePoints, - Size imageSize, InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs, - OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, - OutputArray stdDeviationsIntrinsics, - OutputArray stdDeviationsExtrinsics, - OutputArray _perViewErrors, int flags, TermCriteria criteria ) +double calibrateCamera(InputArrayOfArrays _objectPoints, + InputArrayOfArrays _imagePoints, + Size imageSize, InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs, + OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, + OutputArray stdDeviationsIntrinsics, + OutputArray stdDeviationsExtrinsics, + OutputArray _perViewErrors, int flags, TermCriteria criteria ) { CV_INSTRUMENT_REGION(); @@ -1412,13 +1334,13 @@ double cv::calibrateCamera(InputArrayOfArrays _objectPoints, noArray(), _perViewErrors, flags, criteria); } -double cv::calibrateCameraRO(InputArrayOfArrays _objectPoints, - InputArrayOfArrays _imagePoints, - Size imageSize, int iFixedPoint, InputOutputArray _cameraMatrix, - InputOutputArray _distCoeffs, - OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, - OutputArray newObjPoints, - int flags, TermCriteria criteria) +double calibrateCameraRO(InputArrayOfArrays _objectPoints, + InputArrayOfArrays _imagePoints, + Size imageSize, int iFixedPoint, InputOutputArray _cameraMatrix, + InputOutputArray _distCoeffs, + OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, + OutputArray newObjPoints, + int flags, TermCriteria criteria) { CV_INSTRUMENT_REGION(); @@ -1427,16 +1349,16 @@ double cv::calibrateCameraRO(InputArrayOfArrays _objectPoints, noArray(), noArray(), flags, criteria); } -double cv::calibrateCameraRO(InputArrayOfArrays _objectPoints, - InputArrayOfArrays _imagePoints, - Size imageSize, int iFixedPoint, InputOutputArray _cameraMatrix, - InputOutputArray _distCoeffs, - OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, - OutputArray newObjPoints, - OutputArray stdDeviationsIntrinsics, - OutputArray stdDeviationsExtrinsics, - OutputArray stdDeviationsObjPoints, - OutputArray _perViewErrors, int flags, TermCriteria criteria ) +double calibrateCameraRO(InputArrayOfArrays _objectPoints, + InputArrayOfArrays _imagePoints, + Size imageSize, int iFixedPoint, InputOutputArray _cameraMatrix, + InputOutputArray _distCoeffs, + OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, + OutputArray newObjPoints, + OutputArray stdDeviationsIntrinsics, + OutputArray stdDeviationsExtrinsics, + OutputArray stdDeviationsObjPoints, + OutputArray _perViewErrors, int flags, TermCriteria criteria ) { CV_INSTRUMENT_REGION(); @@ -1448,8 +1370,11 @@ double cv::calibrateCameraRO(InputArrayOfArrays _objectPoints, Mat cameraMatrix = _cameraMatrix.getMat(); cameraMatrix = prepareCameraMatrix(cameraMatrix, rtype, flags); Mat distCoeffs = _distCoeffs.getMat(); - distCoeffs = (flags & CALIB_THIN_PRISM_MODEL) && !(flags & CALIB_TILTED_MODEL) ? prepareDistCoeffs(distCoeffs, rtype, 12) : - prepareDistCoeffs(distCoeffs, rtype); + distCoeffs = + (flags & CALIB_THIN_PRISM_MODEL) && + !(flags & CALIB_TILTED_MODEL) ? + prepareDistCoeffs(distCoeffs, rtype, 12) : + prepareDistCoeffs(distCoeffs, rtype, 14); if( !(flags & CALIB_RATIONAL_MODEL) && (!(flags & CALIB_THIN_PRISM_MODEL)) && (!(flags & CALIB_TILTED_MODEL))) @@ -1489,7 +1414,7 @@ double cv::calibrateCameraRO(InputArrayOfArrays _objectPoints, } collectCalibrationData( _objectPoints, _imagePoints, noArray(), iFixedPoint, - objPt, imgPt, 0, npoints ); + objPt, imgPt, noArray(), npoints ); bool releaseObject = iFixedPoint > 0 && iFixedPoint < npoints.at(0) - 1; newobj_needed = newobj_needed && releaseObject; @@ -1504,10 +1429,8 @@ double cv::calibrateCameraRO(InputArrayOfArrays _objectPoints, bool stddev_any_needed = stddev_needed || stddev_ext_needed || stddev_obj_needed; if( stddev_any_needed ) { - if( releaseObject ) - stdDeviationsM.create(nimages*6 + CV_CALIB_NINTRINSIC + np * 3, 1, CV_64F); - else - stdDeviationsM.create(nimages*6 + CV_CALIB_NINTRINSIC, 1, CV_64F); + int sz = nimages*6 + CALIB_NINTRINSIC + (releaseObject ? np * 3 : 0); + stdDeviationsM.create(sz, 1, CV_64F); } if( errors_needed ) @@ -1518,45 +1441,30 @@ double cv::calibrateCameraRO(InputArrayOfArrays _objectPoints, CvMat c_objPt = cvMat(objPt), c_imgPt = cvMat(imgPt), c_npoints = cvMat(npoints); CvMat c_cameraMatrix = cvMat(cameraMatrix), c_distCoeffs = cvMat(distCoeffs); - CvMat c_rvecM = cvMat(rvecM), c_tvecM = cvMat(tvecM), c_stdDev = cvMat(stdDeviationsM), c_errors = cvMat(errorsM); - CvMat c_newObjPt = cvMat( newObjPt ); - double reprojErr = cvCalibrateCamera2Internal(&c_objPt, &c_imgPt, &c_npoints, cvSize(imageSize), - iFixedPoint, - &c_cameraMatrix, &c_distCoeffs, - rvecs_needed ? &c_rvecM : NULL, - tvecs_needed ? &c_tvecM : NULL, - newobj_needed ? &c_newObjPt : NULL, - stddev_any_needed ? &c_stdDev : NULL, - errors_needed ? &c_errors : NULL, flags, cvTermCriteria(criteria)); - - if( newobj_needed ) - newObjPt.copyTo(newObjPoints); + double reprojErr = calibrateCameraInternal( + &c_objPt, &c_imgPt, &c_npoints, cvSize(imageSize), iFixedPoint, + &c_cameraMatrix, &c_distCoeffs, + rvecM, tvecM, + newObjPt, + stdDeviationsM, + errorsM, flags, cvTermCriteria(criteria)); if( stddev_needed ) { - stdDeviationsIntrinsics.create(CV_CALIB_NINTRINSIC, 1, CV_64F); - Mat stdDeviationsIntrinsicsMat = stdDeviationsIntrinsics.getMat(); - std::memcpy(stdDeviationsIntrinsicsMat.ptr(), stdDeviationsM.ptr(), - CV_CALIB_NINTRINSIC*sizeof(double)); + stdDeviationsM.rowRange(0, CALIB_NINTRINSIC).copyTo(stdDeviationsIntrinsics); } if ( stddev_ext_needed ) { - stdDeviationsExtrinsics.create(nimages*6, 1, CV_64F); - Mat stdDeviationsExtrinsicsMat = stdDeviationsExtrinsics.getMat(); - std::memcpy(stdDeviationsExtrinsicsMat.ptr(), - stdDeviationsM.ptr() + CV_CALIB_NINTRINSIC*sizeof(double), - nimages*6*sizeof(double)); + int s = CALIB_NINTRINSIC; + stdDeviationsM.rowRange(s, s + nimages*6).copyTo(stdDeviationsExtrinsics); } if( stddev_obj_needed ) { - stdDeviationsObjPoints.create( np * 3, 1, CV_64F ); - Mat stdDeviationsObjPointsMat = stdDeviationsObjPoints.getMat(); - std::memcpy( stdDeviationsObjPointsMat.ptr(), stdDeviationsM.ptr() - + ( CV_CALIB_NINTRINSIC + nimages * 6 ) * sizeof( double ), - np * 3 * sizeof( double ) ); + int s = CALIB_NINTRINSIC + nimages*6; + stdDeviationsM.rowRange(s, s + np*3).copyTo(stdDeviationsObjPoints); } // overly complicated and inefficient rvec/ tvec handling to support vector @@ -1583,22 +1491,22 @@ double cv::calibrateCameraRO(InputArrayOfArrays _objectPoints, } -void cv::calibrationMatrixValues( InputArray _cameraMatrix, Size imageSize, - double apertureWidth, double apertureHeight, - double& fovx, double& fovy, double& focalLength, - Point2d& principalPoint, double& aspectRatio ) +void calibrationMatrixValues( InputArray _cameraMatrix, Size imageSize, + double apertureWidth, double apertureHeight, + double& fovx, double& fovy, double& focalLength, + Point2d& principalPoint, double& aspectRatio ) { CV_INSTRUMENT_REGION(); if(_cameraMatrix.size() != Size(3, 3)) CV_Error(cv::Error::StsUnmatchedSizes, "Size of cameraMatrix must be 3x3!"); - Matx33d K = _cameraMatrix.getMat(); - - CV_DbgAssert(imageSize.width != 0 && imageSize.height != 0 && K(0, 0) != 0.0 && K(1, 1) != 0.0); + Matx33d A; + _cameraMatrix.getMat().convertTo(A, CV_64F); + CV_DbgAssert(imageSize.width != 0 && imageSize.height != 0 && A(0, 0) != 0.0 && A(1, 1) != 0.0); /* Calculate pixel aspect ratio. */ - aspectRatio = K(1, 1) / K(0, 0); + aspectRatio = A(1, 1) / A(0, 0); /* Calculate number of pixel per realworld unit. */ double mx, my; @@ -1611,26 +1519,26 @@ void cv::calibrationMatrixValues( InputArray _cameraMatrix, Size imageSize, } /* Calculate fovx and fovy. */ - fovx = atan2(K(0, 2), K(0, 0)) + atan2(imageSize.width - K(0, 2), K(0, 0)); - fovy = atan2(K(1, 2), K(1, 1)) + atan2(imageSize.height - K(1, 2), K(1, 1)); + fovx = atan2(A(0, 2), A(0, 0)) + atan2(imageSize.width - A(0, 2), A(0, 0)); + fovy = atan2(A(1, 2), A(1, 1)) + atan2(imageSize.height - A(1, 2), A(1, 1)); fovx *= 180.0 / CV_PI; fovy *= 180.0 / CV_PI; /* Calculate focal length. */ - focalLength = K(0, 0) / mx; + focalLength = A(0, 0) / mx; /* Calculate principle point. */ - principalPoint = Point2d(K(0, 2) / mx, K(1, 2) / my); + principalPoint = Point2d(A(0, 2) / mx, A(1, 2) / my); } -double cv::stereoCalibrate( InputArrayOfArrays _objectPoints, - InputArrayOfArrays _imagePoints1, - InputArrayOfArrays _imagePoints2, - InputOutputArray _cameraMatrix1, InputOutputArray _distCoeffs1, - InputOutputArray _cameraMatrix2, InputOutputArray _distCoeffs2, - Size imageSize, OutputArray _Rmat, OutputArray _Tmat, - OutputArray _Emat, OutputArray _Fmat, int flags, - TermCriteria criteria) +double stereoCalibrate( InputArrayOfArrays _objectPoints, + InputArrayOfArrays _imagePoints1, + InputArrayOfArrays _imagePoints2, + InputOutputArray _cameraMatrix1, InputOutputArray _distCoeffs1, + InputOutputArray _cameraMatrix2, InputOutputArray _distCoeffs2, + Size imageSize, OutputArray _Rmat, OutputArray _Tmat, + OutputArray _Emat, OutputArray _Fmat, int flags, + TermCriteria criteria) { if (flags & CALIB_USE_EXTRINSIC_GUESS) CV_Error(Error::StsBadFlag, "stereoCalibrate does not support CALIB_USE_EXTRINSIC_GUESS."); @@ -1644,30 +1552,31 @@ double cv::stereoCalibrate( InputArrayOfArrays _objectPoints, return ret; } -double cv::stereoCalibrate( InputArrayOfArrays _objectPoints, - InputArrayOfArrays _imagePoints1, - InputArrayOfArrays _imagePoints2, - InputOutputArray _cameraMatrix1, InputOutputArray _distCoeffs1, - InputOutputArray _cameraMatrix2, InputOutputArray _distCoeffs2, - Size imageSize, InputOutputArray _Rmat, InputOutputArray _Tmat, - OutputArray _Emat, OutputArray _Fmat, - OutputArray _perViewErrors, int flags, - TermCriteria criteria) +double stereoCalibrate( InputArrayOfArrays _objectPoints, + InputArrayOfArrays _imagePoints1, + InputArrayOfArrays _imagePoints2, + InputOutputArray _cameraMatrix1, InputOutputArray _distCoeffs1, + InputOutputArray _cameraMatrix2, InputOutputArray _distCoeffs2, + Size imageSize, InputOutputArray _Rmat, InputOutputArray _Tmat, + OutputArray _Emat, OutputArray _Fmat, + OutputArray _perViewErrors, int flags, + TermCriteria criteria) { return stereoCalibrate(_objectPoints, _imagePoints1, _imagePoints2, _cameraMatrix1, _distCoeffs1, - _cameraMatrix2, _distCoeffs2, imageSize, _Rmat, _Tmat, _Emat, _Fmat, - noArray(), noArray(), _perViewErrors, flags, criteria); + _cameraMatrix2, _distCoeffs2, imageSize, _Rmat, _Tmat, _Emat, _Fmat, + noArray(), noArray(), _perViewErrors, flags, criteria); } -double cv::stereoCalibrate( InputArrayOfArrays _objectPoints, - InputArrayOfArrays _imagePoints1, - InputArrayOfArrays _imagePoints2, - InputOutputArray _cameraMatrix1, InputOutputArray _distCoeffs1, - InputOutputArray _cameraMatrix2, InputOutputArray _distCoeffs2, - Size imageSize, InputOutputArray _Rmat, InputOutputArray _Tmat, - OutputArray _Emat, OutputArray _Fmat, - OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, OutputArray _perViewErrors, int flags, - TermCriteria criteria) +double stereoCalibrate( InputArrayOfArrays _objectPoints, + InputArrayOfArrays _imagePoints1, + InputArrayOfArrays _imagePoints2, + InputOutputArray _cameraMatrix1, InputOutputArray _distCoeffs1, + InputOutputArray _cameraMatrix2, InputOutputArray _distCoeffs2, + Size imageSize, InputOutputArray _Rmat, InputOutputArray _Tmat, + OutputArray _Emat, OutputArray _Fmat, + OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, + OutputArray _perViewErrors, int flags, + TermCriteria criteria) { int rtype = CV_64F; Mat cameraMatrix1 = _cameraMatrix1.getMat(); @@ -1676,18 +1585,18 @@ double cv::stereoCalibrate( InputArrayOfArrays _objectPoints, Mat distCoeffs2 = _distCoeffs2.getMat(); cameraMatrix1 = prepareCameraMatrix(cameraMatrix1, rtype, flags); cameraMatrix2 = prepareCameraMatrix(cameraMatrix2, rtype, flags); - distCoeffs1 = prepareDistCoeffs(distCoeffs1, rtype); - distCoeffs2 = prepareDistCoeffs(distCoeffs2, rtype); + distCoeffs1 = prepareDistCoeffs(distCoeffs1, rtype, 14); + distCoeffs2 = prepareDistCoeffs(distCoeffs2, rtype, 14); if( !(flags & CALIB_RATIONAL_MODEL) && (!(flags & CALIB_THIN_PRISM_MODEL)) && - (!(flags & CALIB_TILTED_MODEL)) ) + (!(flags & CALIB_TILTED_MODEL))) { distCoeffs1 = distCoeffs1.rows == 1 ? distCoeffs1.colRange(0, 5) : distCoeffs1.rowRange(0, 5); distCoeffs2 = distCoeffs2.rows == 1 ? distCoeffs2.colRange(0, 5) : distCoeffs2.rowRange(0, 5); } - if( (flags & CALIB_USE_EXTRINSIC_GUESS) == 0 ) + if((flags & CALIB_USE_EXTRINSIC_GUESS) == 0) { _Rmat.create(3, 3, rtype); _Tmat.create(3, 1, rtype); @@ -1699,27 +1608,27 @@ double cv::stereoCalibrate( InputArrayOfArrays _objectPoints, Mat objPt, imgPt, imgPt2, npoints, rvecLM, tvecLM; collectCalibrationData( _objectPoints, _imagePoints1, _imagePoints2, - objPt, imgPt, &imgPt2, npoints ); + objPt, imgPt, imgPt2, npoints ); CvMat c_objPt = cvMat(objPt), c_imgPt = cvMat(imgPt), c_imgPt2 = cvMat(imgPt2), c_npoints = cvMat(npoints); CvMat c_cameraMatrix1 = cvMat(cameraMatrix1), c_distCoeffs1 = cvMat(distCoeffs1); CvMat c_cameraMatrix2 = cvMat(cameraMatrix2), c_distCoeffs2 = cvMat(distCoeffs2); - Mat matR_ = _Rmat.getMat(), matT_ = _Tmat.getMat(); - CvMat c_matR = cvMat(matR_), c_matT = cvMat(matT_), c_matE, c_matF, c_matErr; + Mat matR = _Rmat.getMat(), matT = _Tmat.getMat(); + CvMat c_matR = cvMat(matR), c_matT = cvMat(matT); - bool E_needed = _Emat.needed(), F_needed = _Fmat.needed(), rvecs_needed = _rvecs.needed(), tvecs_needed = _tvecs.needed(), errors_needed = _perViewErrors.needed(); + bool E_needed = _Emat.needed(), F_needed = _Fmat.needed(); + bool rvecs_needed = _rvecs.needed(), tvecs_needed = _tvecs.needed(); + bool errors_needed = _perViewErrors.needed(); - Mat matE_, matF_, matErr_; + Mat matE, matF, matErr; if( E_needed ) { _Emat.create(3, 3, rtype); - matE_ = _Emat.getMat(); - c_matE = cvMat(matE_); + matE = _Emat.getMat(); } if( F_needed ) { _Fmat.create(3, 3, rtype); - matF_ = _Fmat.getMat(); - c_matF = cvMat(matF_); + matF = _Fmat.getMat(); } bool rvecs_mat_vec = _rvecs.isMatVector(); @@ -1743,21 +1652,17 @@ double cv::stereoCalibrate( InputArrayOfArrays _objectPoints, else tvecLM = _tvecs.getMat(); } - CvMat c_rvecLM = cvMat(rvecLM), c_tvecLM = cvMat(tvecLM); if( errors_needed ) { _perViewErrors.create(nimages, 2, CV_64F); - matErr_ = _perViewErrors.getMat(); - c_matErr = cvMat(matErr_); + matErr = _perViewErrors.getMat(); } - double err = cvStereoCalibrateImpl(&c_objPt, &c_imgPt, &c_imgPt2, &c_npoints, &c_cameraMatrix1, - &c_distCoeffs1, &c_cameraMatrix2, &c_distCoeffs2, cvSize(imageSize), &c_matR, - &c_matT, E_needed ? &c_matE : NULL, F_needed ? &c_matF : NULL, - rvecs_needed ? &c_rvecLM : NULL, tvecs_needed ? &c_tvecLM : NULL, - errors_needed ? &c_matErr : NULL, flags, cvTermCriteria(criteria)); - + double err = stereoCalibrateImpl(&c_objPt, &c_imgPt, &c_imgPt2, &c_npoints, &c_cameraMatrix1, + &c_distCoeffs1, &c_cameraMatrix2, &c_distCoeffs2, cvSize(imageSize), + &c_matR, &c_matT, matE, matF, rvecLM, tvecLM, + matErr, flags, cvTermCriteria(criteria)); cameraMatrix1.copyTo(_cameraMatrix1); cameraMatrix2.copyTo(_cameraMatrix2); distCoeffs1.copyTo(_distCoeffs1); @@ -1769,17 +1674,18 @@ double cv::stereoCalibrate( InputArrayOfArrays _objectPoints, { _rvecs.create(3, 1, CV_64F, i, true); Mat rv = _rvecs.getMat(i); - memcpy(rv.ptr(), rvecLM.ptr(i), 3*sizeof(double)); + Mat(rvecLM.row(i).t()).copyTo(rv); } if( tvecs_needed && tvecs_mat_vec ) { _tvecs.create(3, 1, CV_64F, i, true); Mat tv = _tvecs.getMat(i); - memcpy(tv.ptr(), tvecLM.ptr(i), 3*sizeof(double)); + Mat(tvecLM.row(i).t()).copyTo(tv); } } return err; } +} /* End of file. */ diff --git a/modules/calib3d/src/compat_ptsetreg.cpp b/modules/calib3d/src/compat_ptsetreg.cpp index fec3f3a420..eea17b19d9 100644 --- a/modules/calib3d/src/compat_ptsetreg.cpp +++ b/modules/calib3d/src/compat_ptsetreg.cpp @@ -42,7 +42,7 @@ #include "precomp.hpp" #include "opencv2/core/core_c.h" -#include "calib3d_c_api.h" +#include "opencv2/calib3d/calib3d_c.h" /************************************************************************************\ Some backward compatibility stuff, to be moved to legacy or compat module @@ -321,39 +321,3 @@ void CvLevMarq::step() for( int i = 0; i < nparams; i++ ) param->data.db[i] = prevParam->data.db[i] - (mask->data.ptr[i] ? nonzero_param(j++) : 0); } - -CV_IMPL int cvFindHomography( const CvMat* _src, const CvMat* _dst, CvMat* __H, int method, - double ransacReprojThreshold, CvMat* _mask, int maxIters, - double confidence) -{ - cv::Mat src = cv::cvarrToMat(_src), dst = cv::cvarrToMat(_dst); - - if( src.channels() == 1 && (src.rows == 2 || src.rows == 3) && src.cols > 3 ) - cv::transpose(src, src); - if( dst.channels() == 1 && (dst.rows == 2 || dst.rows == 3) && dst.cols > 3 ) - cv::transpose(dst, dst); - - if ( maxIters < 0 ) - maxIters = 0; - if ( maxIters > 2000 ) - maxIters = 2000; - - if ( confidence < 0 ) - confidence = 0; - if ( confidence > 1 ) - confidence = 1; - - const cv::Mat H = cv::cvarrToMat(__H), mask = cv::cvarrToMat(_mask); - cv::Mat H0 = cv::findHomography(src, dst, method, ransacReprojThreshold, - _mask ? cv::_OutputArray(mask) : cv::_OutputArray(), maxIters, - confidence); - - if( H0.empty() ) - { - cv::Mat Hz = cv::cvarrToMat(__H); - Hz.setTo(cv::Scalar::all(0)); - return 0; - } - H0.convertTo(H, H.type()); - return 1; -} From 21cb138be861376e2de352a4e3eeabd86131933f Mon Sep 17 00:00:00 2001 From: Rostislav Vasilikhin Date: Fri, 15 Nov 2024 19:28:16 +0100 Subject: [PATCH 07/10] warpPerspective border type test --- modules/imgproc/test/test_imgwarp.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/imgproc/test/test_imgwarp.cpp b/modules/imgproc/test/test_imgwarp.cpp index 98e790d755..3bc89b8a13 100644 --- a/modules/imgproc/test/test_imgwarp.cpp +++ b/modules/imgproc/test/test_imgwarp.cpp @@ -613,6 +613,8 @@ protected: int prepare_test_case( int test_case_idx ); void prepare_to_validation( int /*test_case_idx*/ ); double get_success_error_level( int test_case_idx, int i, int j ); + + int borderType; }; @@ -636,21 +638,24 @@ void CV_WarpPerspectiveTest::get_test_array_types_and_sizes( int test_case_idx, void CV_WarpPerspectiveTest::run_func() { - CvMat mtx = cvMat(test_mat[INPUT][1]); - cvWarpPerspective( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &mtx, interpolation ); + Mat& dst = test_mat[INPUT_OUTPUT][0]; + cv::warpPerspective(test_mat[INPUT][0], dst, test_mat[INPUT][1], dst.size(), interpolation, borderType, Scalar::all(0)); } double CV_WarpPerspectiveTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) { int depth = test_mat[INPUT][0].depth(); - return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2; + return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 0.13; } int CV_WarpPerspectiveTest::prepare_test_case( int test_case_idx ) { RNG& rng = ts->get_rng(); + + // only these two borders are declared as supported + borderType = rng() % 2 ? BORDER_REPLICATE : BORDER_CONSTANT; int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx ); const CvMat src = cvMat(test_mat[INPUT][0]); const CvMat dst = cvMat(test_mat[INPUT_OUTPUT][0]); @@ -720,7 +725,7 @@ void CV_WarpPerspectiveTest::prepare_to_validation( int /*test_case_idx*/ ) } Mat mask( dst.size(), CV_8U ); - test_remap( src, dst, mapx, mapy, &mask ); + test_remap( src, dst, mapx, mapy, &mask, interpolation); dst.setTo(Scalar::all(0), mask); dst0.setTo(Scalar::all(0), mask); } From d0c8b36de8c35a5c3c88cb994243a0164c946fcb Mon Sep 17 00:00:00 2001 From: xkszltl Date: Sun, 17 Nov 2024 18:37:13 -0800 Subject: [PATCH 08/10] Check existence of OpenEXR version macros before using. It is introduced in 2.0.1 (not even in 2.0.0) and some old system like CentOS 7 still has 1.7 in stock. - https://github.com/AcademySoftwareFoundation/openexr/commit/60cdff8a6f5c4e25a374e5f366d6e9b4efd869b3#diff-c4bae0726aebe410e407db9abd406d9cf2684f82dd8a08f46d84e8b7c35cf22aR67 --- modules/imgcodecs/src/grfmt_exr.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/imgcodecs/src/grfmt_exr.cpp b/modules/imgcodecs/src/grfmt_exr.cpp index d48e067edd..e93448e355 100644 --- a/modules/imgcodecs/src/grfmt_exr.cpp +++ b/modules/imgcodecs/src/grfmt_exr.cpp @@ -754,7 +754,10 @@ bool ExrEncoder::write( const Mat& img, const std::vector& params ) case IMWRITE_EXR_COMPRESSION_B44A: header.compression() = B44A_COMPRESSION; break; -#if ((OPENEXR_VERSION_MAJOR * 1000 + OPENEXR_VERSION_MINOR) >= (2 * 1000 + 2)) // available since version 2.2.0 +// version macros introduced in openexr 2.0.1. +// - https://github.com/AcademySoftwareFoundation/openexr/commit/60cdff8a6f5c4e25a374e5f366d6e9b4efd869b3#diff-c4bae0726aebe410e407db9abd406d9cf2684f82dd8a08f46d84e8b7c35cf22aR67 +#if defined(OPENEXR_VERSION_MAJOR) && defined(OPENEXR_VERSION_MINOR) && OPENEXR_VERSION_MAJOR * 1000 + OPENEXR_VERSION_MINOR >= 2 * 1000 + 2 + // available since version 2.2.0 case IMWRITE_EXR_COMPRESSION_DWAA: header.compression() = DWAA_COMPRESSION; break; @@ -768,10 +771,12 @@ bool ExrEncoder::write( const Mat& img, const std::vector& params ) } if (params[i] == IMWRITE_EXR_DWA_COMPRESSION_LEVEL) { -#if OPENEXR_VERSION_MAJOR >= 3 - header.dwaCompressionLevel() = params[i + 1]; -#else +#if !defined(OPENEXR_VERSION_MAJOR) + CV_LOG_ONCE_WARNING(NULL, "Setting `IMWRITE_EXR_DWA_COMPRESSION_LEVEL` not supported in unknown OpenEXR version possibly prior to 2.0.1 (version 3 is required)"); +#elif OPENEXR_VERSION_MAJOR < 3 CV_LOG_ONCE_WARNING(NULL, "Setting `IMWRITE_EXR_DWA_COMPRESSION_LEVEL` not supported in OpenEXR version " + std::to_string(OPENEXR_VERSION_MAJOR) + " (version 3 is required)"); +#else + header.dwaCompressionLevel() = params[i + 1]; #endif } } From 64d3111377ef82d73653267d5f924e6afaf966dc Mon Sep 17 00:00:00 2001 From: Rostislav Vasilikhin Date: Tue, 19 Nov 2024 08:35:49 +0100 Subject: [PATCH 09/10] Merge pull request #26459 from savuor:rv/hal_absdiff_scalar HAL added for absdiff(array, scalar) + related fixes #26459 ### This PR changes * HAL for `absdiff` when one of arguments is a scalar, including multichannel arrays and scalars * several channels support for HAL `addScalar` * proper data type check for `addScalar` when one of arguments is a scalar ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake --- modules/core/src/arithm.cpp | 107 +++++++++++++++++++++++---- modules/core/src/hal_replacement.hpp | 25 ++++++- 2 files changed, 117 insertions(+), 15 deletions(-) diff --git a/modules/core/src/arithm.cpp b/modules/core/src/arithm.cpp index aea697e762..01a1a02900 100644 --- a/modules/core/src/arithm.cpp +++ b/modules/core/src/arithm.cpp @@ -587,7 +587,7 @@ static bool ocl_arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst, typedef int (*ScalarFunc)(const uchar* src, size_t step_src, uchar* dst, size_t step_dst, int width, int height, - void* scalar, bool scalarIsFirst); + void* scalar, bool scalarIsFirst, int nChannels); typedef int (*ExtendedTypeFunc)(const uchar* src1, size_t step1, const uchar* src2, size_t step2, @@ -862,7 +862,6 @@ static void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst, for( size_t j = 0; j < total; j += blocksize ) { int bsz = (int)MIN(total - j, blocksize); - Size bszn(bsz*cn, 1); const uchar *sptr1 = ptrs[0]; const uchar* sptr2 = buf2; uchar* dptr = ptrs[1]; @@ -875,17 +874,17 @@ static void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst, // try to perform operation in 1 call, fallback to classic way if fail uchar* opconverted = haveMask ? maskbuf : dptr; if (!scalarFunc || src2.total() != 1 || - scalarFunc(extSptr1, 1, opconverted, 1, bszn.width, bszn.height, (void*)extSptr2, swapped12) != 0) + scalarFunc(extSptr1, 1, opconverted, 1, bsz, 1, (void*)extSptr2, swapped12, cn) != 0) { // try to perform operation with conversion in one call // if fail, use converter functions if (!extendedFunc || extendedFunc(extSptr1, 1, extSptr2, 1, opconverted, 1, - bszn.width, bszn.height, usrdata) != 0) + bsz*cn, 1, usrdata) != 0) { if( cvtsrc1 ) { - cvtsrc1( sptr1, 1, 0, 1, buf1, 1, bszn, 0 ); + cvtsrc1( sptr1, 1, 0, 1, buf1, 1, Size(bsz*cn, 1), 0 ); sptr1 = buf1; } @@ -893,12 +892,12 @@ static void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst, std::swap(sptr1, sptr2); uchar* fdst = ( haveMask || cvtdst ) ? wbuf : dptr; - func( sptr1, 1, sptr2, 1, fdst, 1, bszn.width, bszn.height, usrdata ); + func( sptr1, 1, sptr2, 1, fdst, 1, bsz*cn, 1, usrdata ); if (cvtdst) { uchar* cdst = haveMask ? maskbuf : dptr; - cvtdst(wbuf, 1, 0, 1, cdst, 1, bszn, 0); + cvtdst(wbuf, 1, 0, 1, cdst, 1, Size(bsz*cn, 1), 0); } opconverted = cvtdst ? maskbuf : wbuf; } @@ -931,9 +930,9 @@ static BinaryFuncC* getAddTab() } static int addScalar32f32fWrapper(const uchar* src, size_t step_src, uchar* dst, size_t step_dst, int width, int height, - void* scalar, bool /*scalarIsFirst*/) + void* scalar, bool /*scalarIsFirst*/, int nChannels) { - int res = cv_hal_addScalar32f32f((const float*)src, step_src, (float *)dst, step_dst, width, height, (const float*)scalar); + int res = cv_hal_addScalar32f32f((const float*)src, step_src, (float *)dst, step_dst, width, height, (const float*)scalar, nChannels); if (res == CV_HAL_ERROR_OK || res == CV_HAL_ERROR_NOT_IMPLEMENTED) return res; else @@ -944,9 +943,9 @@ static int addScalar32f32fWrapper(const uchar* src, size_t step_src, uchar* dst, } static int addScalar16s16sWrapper(const uchar* src, size_t step_src, uchar* dst, size_t step_dst, int width, int height, - void* scalar, bool /*scalarIsFirst*/) + void* scalar, bool /*scalarIsFirst*/, int nChannels) { - int res = cv_hal_addScalar16s16s((const int16_t*)src, step_src, (int16_t *)dst, step_dst, width, height, (const int16_t*)scalar); + int res = cv_hal_addScalar16s16s((const int16_t*)src, step_src, (int16_t *)dst, step_dst, width, height, (const int16_t*)scalar, nChannels); if (res == CV_HAL_ERROR_OK || res == CV_HAL_ERROR_NOT_IMPLEMENTED) return res; else @@ -1042,6 +1041,67 @@ static BinaryFuncC* getAbsDiffTab() return absDiffTab; } + +static int absDiffScalar32f32fWrapper(const uchar* src, size_t step_src, uchar* dst, size_t step_dst, int width, int height, + void* scalar, bool /*scalarIsFirst*/, int nChannels) +{ + int res = cv_hal_absDiffScalar32f32f((const float*)src, step_src, (float *)dst, step_dst, width, height, (const float*)scalar, nChannels); + if (res == CV_HAL_ERROR_OK || res == CV_HAL_ERROR_NOT_IMPLEMENTED) + return res; + else + { + CV_Error_(cv::Error::StsInternal, ("HAL implementation addScalar32f32f ==> " CVAUX_STR(cv_hal_addScalar32f32f) + " returned %d (0x%08x)", res, res)); + } +} + +static int absDiffScalar32s32uWrapper(const uchar* src, size_t step_src, uchar* dst, size_t step_dst, int width, int height, + void* scalar, bool /*scalarIsFirst*/, int nChannels) +{ + int res = cv_hal_absDiffScalar32s32u((const int*)src, step_src, (uint32_t*)dst, step_dst, width, height, (const int*)scalar, nChannels); + if (res == CV_HAL_ERROR_OK || res == CV_HAL_ERROR_NOT_IMPLEMENTED) + return res; + else + { + CV_Error_(cv::Error::StsInternal, ("HAL implementation addScalar32f32f ==> " CVAUX_STR(cv_hal_addScalar32f32f) + " returned %d (0x%08x)", res, res)); + } +} + +static int absDiffScalar8u8uWrapper(const uchar* src, size_t step_src, uchar* dst, size_t step_dst, int width, int height, + void* scalar, bool /*scalarIsFirst*/, int nChannels) +{ + int res = cv_hal_absDiffScalar8u8u((const uchar*)src, step_src, (uchar*)dst, step_dst, width, height, (const uchar*)scalar, nChannels); + if (res == CV_HAL_ERROR_OK || res == CV_HAL_ERROR_NOT_IMPLEMENTED) + return res; + else + { + CV_Error_(cv::Error::StsInternal, ("HAL implementation addScalar32f32f ==> " CVAUX_STR(cv_hal_addScalar32f32f) + " returned %d (0x%08x)", res, res)); + } +} + +static ScalarFunc getAbsDiffScalarFunc(int srcType, int dstType) +{ + if (srcType == CV_32F && dstType == CV_32F) + { + return absDiffScalar32f32fWrapper; + } + // resulting type is 32U in fact + else if (srcType == CV_32S && dstType == CV_32S) + { + return absDiffScalar32s32uWrapper; + } + else if (srcType == CV_8U && dstType == CV_8U) + { + return absDiffScalar8u8uWrapper; + } + else + { + return nullptr; + } +} + } void cv::add( InputArray src1, InputArray src2, OutputArray dst, @@ -1056,7 +1116,17 @@ void cv::add( InputArray src1, InputArray src2, OutputArray dst, return; } - ScalarFunc scalarFunc = getAddScalarFunc(src1.depth(), dtype < 0 ? dst.depth() : dtype); + int sdepth = src1.depth(); + if (checkScalar(src1, src1.type(), src1.kind(), _InputArray::MATX)) + { + sdepth = src2.depth(); + } + if (checkScalar(src2, src2.type(), src2.kind(), _InputArray::MATX)) + { + sdepth = src1.depth(); + } + + ScalarFunc scalarFunc = getAddScalarFunc(sdepth, dtype < 0 ? dst.depth() : dtype); arithm_op(src1, src2, dst, mask, dtype, getAddTab(), false, 0, OCL_OP_ADD, nullptr, /* scalarFunc */ scalarFunc ); } @@ -1089,7 +1159,18 @@ void cv::absdiff( InputArray src1, InputArray src2, OutputArray dst ) return; } - arithm_op(src1, src2, dst, noArray(), -1, getAbsDiffTab(), false, 0, OCL_OP_ABSDIFF); + int sdepth = src1.depth(); + if (checkScalar(src1, src1.type(), src1.kind(), _InputArray::MATX)) + { + sdepth = src2.depth(); + } + if (checkScalar(src2, src2.type(), src2.kind(), _InputArray::MATX)) + { + sdepth = src1.depth(); + } + ScalarFunc scalarFunc = getAbsDiffScalarFunc(sdepth, dst.depth()); + arithm_op(src1, src2, dst, noArray(), -1, getAbsDiffTab(), false, 0, OCL_OP_ABSDIFF, + /* extendedFunc */ nullptr, scalarFunc); } void cv::copyTo(InputArray _src, OutputArray _dst, InputArray _mask) diff --git a/modules/core/src/hal_replacement.hpp b/modules/core/src/hal_replacement.hpp index 013ca97875..474fe17393 100644 --- a/modules/core/src/hal_replacement.hpp +++ b/modules/core/src/hal_replacement.hpp @@ -109,9 +109,10 @@ Add scalar: _dst[i] = src[i] + scalar @param width width of the images @param height height of the images @param scalar_data pointer to scalar value +@param nChannels number of channels per element */ -inline int hal_ni_addScalar32f32f(const float *src_data, size_t src_step, float *dst_data, size_t dst_step, int width, int height, const float* scalar_data) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } -inline int hal_ni_addScalar16s16s(const int16_t *src_data, size_t src_step, int16_t *dst_data, size_t dst_step, int width, int height, const int16_t* scalar_data) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +inline int hal_ni_addScalar32f32f(const float* src_data, size_t src_step, float* dst_data, size_t dst_step, int width, int height, const float* scalar_data, int nChannels) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +inline int hal_ni_addScalar16s16s(const int16_t* src_data, size_t src_step, int16_t* dst_data, size_t dst_step, int width, int height, const int16_t* scalar_data, int nChannels) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } //! @} /** @@ -165,6 +166,23 @@ inline int hal_ni_absdiff16s(const short *src1_data, size_t src1_step, const sho inline int hal_ni_absdiff32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, int *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } inline int hal_ni_absdiff32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, float *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } inline int hal_ni_absdiff64f(const double *src1_data, size_t src1_step, const double *src2_data, size_t src2_step, double *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } + +/* +Absolute difference with scalar: _dst[i] = | src[i] - scalar |_ + +@param src_data source image data +@param src_step source image step +@param dst_data destination image data +@param dst_step destination image step +@param width width of the images +@param height height of the images +@param scalar_data pointer to scalar value +@param nChannels number of channels per element +*/ +inline int hal_ni_absDiffScalar32f32f(const float* src_data, size_t src_step, float* dst_data, size_t dst_step, int width, int height, const float* scalar_data, int nChannels) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +inline int hal_ni_absDiffScalar32s32u(const int* src_data, size_t src_step, uint32_t* dst_data, size_t dst_step, int width, int height, const int* scalar_data, int nChannels) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +inline int hal_ni_absDiffScalar8u8u (const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, const uchar* scalar_data, int nChannels) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } + //! @} /** @@ -229,6 +247,9 @@ inline int hal_ni_not8u(const uchar *src_data, size_t src_step, uchar *dst_data, #define cv_hal_absdiff32s hal_ni_absdiff32s #define cv_hal_absdiff32f hal_ni_absdiff32f #define cv_hal_absdiff64f hal_ni_absdiff64f +#define cv_hal_absDiffScalar32f32f hal_ni_absDiffScalar32f32f +#define cv_hal_absDiffScalar32s32u hal_ni_absDiffScalar32s32u +#define cv_hal_absDiffScalar8u8u hal_ni_absDiffScalar8u8u #define cv_hal_and8u hal_ni_and8u #define cv_hal_or8u hal_ni_or8u #define cv_hal_xor8u hal_ni_xor8u From c3ca3f4f006e7c573923be4dfdf0a2ac0dc798b4 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 21 Nov 2024 11:50:25 +0300 Subject: [PATCH 10/10] Fixed KLEIDICV_SOURCE_PATH handling for extenral KleidiCV. --- cmake/OpenCVFindLibsPerf.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/OpenCVFindLibsPerf.cmake b/cmake/OpenCVFindLibsPerf.cmake index 493f005d7a..c2bff4fb1c 100644 --- a/cmake/OpenCVFindLibsPerf.cmake +++ b/cmake/OpenCVFindLibsPerf.cmake @@ -165,6 +165,7 @@ endif(WITH_CLP) # --- ARM KleidiCV if(WITH_KLEIDICV) if(KLEIDICV_SOURCE_PATH AND EXISTS "${KLEIDICV_SOURCE_PATH}/adapters/opencv/CMakeLists.txt") + message(STATUS "Use external KleidiCV ${KLEIDICV_SOURCE_PATH}") set(HAVE_KLEIDICV ON) endif() if(NOT HAVE_KLEIDICV) @@ -173,7 +174,5 @@ if(WITH_KLEIDICV) if(KLEIDICV_SOURCE_PATH) set(HAVE_KLEIDICV ON) endif() - else() - set(HAVE_KLEIDICV OFF) endif() endif(WITH_KLEIDICV)