From 09b02b9e4eb087b39b14919d23e196fc6442ffec Mon Sep 17 00:00:00 2001 From: lianst <563052165@qq.com> Date: Wed, 30 Nov 2022 23:46:58 +0800 Subject: [PATCH 01/18] Corrected misspelling --- .../src/zxing/qrcode/detector/detector.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/wechat_qrcode/src/zxing/qrcode/detector/detector.cpp b/modules/wechat_qrcode/src/zxing/qrcode/detector/detector.cpp index e22a852f9c3..40c1f572651 100644 --- a/modules/wechat_qrcode/src/zxing/qrcode/detector/detector.cpp +++ b/modules/wechat_qrcode/src/zxing/qrcode/detector/detector.cpp @@ -117,7 +117,7 @@ Ref Detector::getResultViaAlignment(int patternIdx, int alignmen Ref bits(sampleGrid(image_, possibleDimension, transform, err_handler)); if (err_handler.ErrCode()) return Ref(); - ArrayRef > corrners(new Array >(4)); + ArrayRef > corners(new Array >(4)); vector points(8, 0.0f); points[0] = 0.0f; points[1] = possibleDimension; // bottomLeft @@ -128,12 +128,12 @@ Ref Detector::getResultViaAlignment(int patternIdx, int alignmen points[6] = possibleDimension; points[7] = possibleDimension; // bottomRight transform->transformPoints(points); - corrners[0].reset(Ref(new FinderPattern(points[0], points[1], 0))); - corrners[1].reset(Ref(new FinderPattern(points[2], points[3], 0))); - corrners[2].reset(Ref(new FinderPattern(points[4], points[5], 0))); - corrners[3].reset(Ref(new FinderPattern(points[6], points[7], 0))); + corners[0].reset(Ref(new FinderPattern(points[0], points[1], 0))); + corners[1].reset(Ref(new FinderPattern(points[2], points[3], 0))); + corners[2].reset(Ref(new FinderPattern(points[4], points[5], 0))); + corners[3].reset(Ref(new FinderPattern(points[6], points[7], 0))); - Ref result(new DetectorResult(bits, corrners, possibleDimension)); + Ref result(new DetectorResult(bits, corners, possibleDimension)); return result; } From 26a7ebb61033ef2c236581f73dbe461776e7231e Mon Sep 17 00:00:00 2001 From: kan kawabata Date: Wed, 9 Aug 2023 23:12:13 -0700 Subject: [PATCH 02/18] the landmarks_demo.py fails with an obscure error when no faces are detected in the input image. Added some error handling so that it's more transparent. --- modules/face/samples/landmarks_demo.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/face/samples/landmarks_demo.py b/modules/face/samples/landmarks_demo.py index 4c6c4935975..84893a77a25 100644 --- a/modules/face/samples/landmarks_demo.py +++ b/modules/face/samples/landmarks_demo.py @@ -18,7 +18,11 @@ print("cascade not found") exit() faces = cascade.detectMultiScale(frame, 1.05, 3, cv.CASCADE_SCALE_IMAGE, (30, 30)) -ok, landmarks = facemark.fit(frame, faces=faces) +if len(faces) == 0: + print('no faces detected') + landmarks = [] +else: + ok, landmarks = facemark.fit(frame, faces=faces) cv.imshow("Image", frame) for marks in landmarks: couleur = (random.randint(0,255), From 9279b23cc5f9984f22f6eb4aee9f9ece398bd42f Mon Sep 17 00:00:00 2001 From: Jack Chan Date: Mon, 11 Sep 2023 20:43:00 +0800 Subject: [PATCH 03/18] Merge pull request #3555 from Jack-Chan-2001:4.x Fix typing error ### 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 - [x] There is a reference to the original bug report and related work - [x] 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/ccalib/src/omnidir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ccalib/src/omnidir.cpp b/modules/ccalib/src/omnidir.cpp index ccca0b57a8f..5e5f8cc2bf4 100644 --- a/modules/ccalib/src/omnidir.cpp +++ b/modules/ccalib/src/omnidir.cpp @@ -2138,7 +2138,7 @@ void cv::omnidir::internal::flags2idxStereo(int flags, std::vector& idx, in } } -// fill in zerso for fixed parameters +// fill in zeros for fixed parameters void cv::omnidir::internal::fillFixed(Mat&G, int flags, int n) { Mat tmp = G.clone(); From 2f8938512dc12c0462c42f679b23dcf1c6d6acd8 Mon Sep 17 00:00:00 2001 From: Yuriy Chernyshov Date: Wed, 6 Sep 2023 18:04:53 +0300 Subject: [PATCH 04/18] Add missing std namespace qualifiers --- modules/ximgproc/src/find_ellipses.cpp | 34 +++++++++---------- modules/ximgproc/src/lsc.cpp | 2 +- .../ximgproc/src/run_length_morphology.cpp | 2 +- .../src/sparse_match_interpolators.cpp | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/modules/ximgproc/src/find_ellipses.cpp b/modules/ximgproc/src/find_ellipses.cpp index 66c61d7759a..de73f833b47 100644 --- a/modules/ximgproc/src/find_ellipses.cpp +++ b/modules/ximgproc/src/find_ellipses.cpp @@ -338,9 +338,9 @@ float EllipseDetectorImpl::getMedianSlope(std::vector &med, Point2f &ce slopes.push_back(num / den); } - nth_element(slopes.begin(), slopes.begin() + quarterSize, slopes.end()); - nth_element(xx.begin(), xx.begin() + halfSize, xx.end()); - nth_element(yy.begin(), yy.begin() + halfSize, yy.end()); + std::nth_element(slopes.begin(), slopes.begin() + quarterSize, slopes.end()); + std::nth_element(xx.begin(), xx.begin() + halfSize, xx.end()); + std::nth_element(yy.begin(), yy.begin() + halfSize, yy.end()); centers.x = xx[halfSize]; centers.y = yy[halfSize]; @@ -390,7 +390,7 @@ void EllipseDetectorImpl::getFastCenter(std::vector &e1, std::vector &e1, std::vector reverse 1 VP rev_i(edge_i.size()); - reverse_copy(edge_i.begin(), edge_i.end(), rev_i.begin()); + std::reverse_copy(edge_i.begin(), edge_i.end(), rev_i.begin()); // for each edge j for (ushort j = 0; j < sz_j; ++j) { @@ -936,7 +936,7 @@ void EllipseDetectorImpl::getTriplets231(VVP &pi, VVP &pj, VVP &pk, // 2 -> reverse 2 VP rev_i(edge_i.size()); - reverse_copy(edge_i.begin(), edge_i.end(), rev_i.begin()); + std::reverse_copy(edge_i.begin(), edge_i.end(), rev_i.begin()); // for each edge j for (ushort j = 0; j < sz_j; ++j) { @@ -958,7 +958,7 @@ void EllipseDetectorImpl::getTriplets231(VVP &pi, VVP &pj, VVP &pk, // 3 -> reverse 3 VP rev_j(edge_j.size()); - reverse_copy(edge_j.begin(), edge_j.end(), rev_j.begin()); + std::reverse_copy(edge_j.begin(), edge_j.end(), rev_j.begin()); uint key_ij = generateKey(PAIR_23, i, j); @@ -991,7 +991,7 @@ void EllipseDetectorImpl::getTriplets231(VVP &pi, VVP &pj, VVP &pk, if (data.count(key_ik) == 0) { // 1 -> reverse 1 VP rev_k(edge_k.size()); - reverse_copy(edge_k.begin(), edge_k.end(), rev_k.begin()); + std::reverse_copy(edge_k.begin(), edge_k.end(), rev_k.begin()); getFastCenter(edge_i, rev_k, data_ik); data.insert(std::pair(key_ik, data_ik)); @@ -1038,7 +1038,7 @@ void EllipseDetectorImpl::getTriplets342(VVP &pi, VVP &pj, VVP &pk, // 3 -> reverse 3 VP rev_i(edge_i.size()); - reverse_copy(edge_i.begin(), edge_i.end(), rev_i.begin()); + std::reverse_copy(edge_i.begin(), edge_i.end(), rev_i.begin()); // for each edge j for (ushort j = 0; j < sz_j; ++j) { @@ -1060,7 +1060,7 @@ void EllipseDetectorImpl::getTriplets342(VVP &pi, VVP &pj, VVP &pk, // 4 -> reverse 4 VP rev_j(edge_j.size()); - reverse_copy(edge_j.begin(), edge_j.end(), rev_j.begin()); + std::reverse_copy(edge_j.begin(), edge_j.end(), rev_j.begin()); uint key_ij = generateKey(PAIR_34, i, j); @@ -1093,7 +1093,7 @@ void EllipseDetectorImpl::getTriplets342(VVP &pi, VVP &pj, VVP &pk, if (data.count(key_ik) == 0) { // 2 -> reverse 2 VP rev_k(edge_k.size()); - reverse_copy(edge_k.begin(), edge_k.end(), rev_k.begin()); + std::reverse_copy(edge_k.begin(), edge_k.end(), rev_k.begin()); getFastCenter(rev_i, rev_k, data_ik); data.insert(std::pair(key_ik, data_ik)); @@ -1141,7 +1141,7 @@ void EllipseDetectorImpl::getTriplets413(VVP &pi, VVP &pj, VVP &pk, // 4 -> reverse 4 VP rev_i(edge_i.size()); - reverse_copy(edge_i.begin(), edge_i.end(), rev_i.begin()); + std::reverse_copy(edge_i.begin(), edge_i.end(), rev_i.begin()); // for each edge j for (ushort j = 0; j < sz_j; ++j) { @@ -1507,8 +1507,8 @@ void EllipseDetectorImpl::detect(Mat1b &image, std::vector &ellipses) { getTriplets342(points_3, points_4, points_2, centers, ellipses); getTriplets413(points_4, points_1, points_3, centers, ellipses); - // sort by score - sort(ellipses.begin(), ellipses.end()); + // std::sort by score + std::sort(ellipses.begin(), ellipses.end()); // free accumulator memory delete[]accN; diff --git a/modules/ximgproc/src/lsc.cpp b/modules/ximgproc/src/lsc.cpp index 9ef507c8fcd..1a5539b4fb3 100644 --- a/modules/ximgproc/src/lsc.cpp +++ b/modules/ximgproc/src/lsc.cpp @@ -821,7 +821,7 @@ inline void SuperpixelLSCImpl::PostEnforceLabelConnectivity( int threshold ) (*Stmp).Neighbor.insert( (*Stmp).Neighbor.end(), (*S).Neighbor.begin(), (*S).Neighbor.end() ); - sort( (*Stmp).Neighbor.begin(), (*Stmp).Neighbor.end() ); + std::sort( (*Stmp).Neighbor.begin(), (*Stmp).Neighbor.end() ); I = unique( (*Stmp).Neighbor.begin(), (*Stmp).Neighbor.end() ); (*Stmp).Neighbor.erase( I, (*Stmp).Neighbor.end() ); diff --git a/modules/ximgproc/src/run_length_morphology.cpp b/modules/ximgproc/src/run_length_morphology.cpp index 3cf88048469..2819f51ec4a 100644 --- a/modules/ximgproc/src/run_length_morphology.cpp +++ b/modules/ximgproc/src/run_length_morphology.cpp @@ -388,7 +388,7 @@ static void convertInputArrayToRuns(InputArray& theArray, rlVec& runs, Size& the static void sortChords(rlVec& lChords) { - sort(lChords.begin(), lChords.end()); + std::sort(lChords.begin(), lChords.end()); } static void mergeNeighbouringChords(rlVec& rlIn, rlVec& rlOut) diff --git a/modules/ximgproc/src/sparse_match_interpolators.cpp b/modules/ximgproc/src/sparse_match_interpolators.cpp index 517573946af..85261715bbb 100644 --- a/modules/ximgproc/src/sparse_match_interpolators.cpp +++ b/modules/ximgproc/src/sparse_match_interpolators.cpp @@ -198,7 +198,7 @@ void EdgeAwareInterpolatorImpl::interpolate(InputArray from_image, InputArray fr matches_vector[i] = SparseMatch(from_mat.at(i), to_mat.at(i)); - sort(matches_vector.begin(),matches_vector.end()); + std::sort(matches_vector.begin(),matches_vector.end()); match_num = (int)matches_vector.size(); CV_Assert(match_num Date: Fri, 15 Sep 2023 12:40:19 +0300 Subject: [PATCH 05/18] More fixes for iterators-are-pointers case --- modules/ximgproc/src/structured_edge_detection.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/ximgproc/src/structured_edge_detection.cpp b/modules/ximgproc/src/structured_edge_detection.cpp index ffd80660ed0..56070bef8ff 100644 --- a/modules/ximgproc/src/structured_edge_detection.cpp +++ b/modules/ximgproc/src/structured_edge_detection.cpp @@ -148,8 +148,9 @@ static cv::Mat rgb2luv(const cv::Mat &src) lTable[i] = l*maxi; } - for (int i = 0; i < 40; ++i) - lTable.push_back(*--lTable.end()); + for (int i = 0; i < 40; ++i) { + lTable.push_back(*lTable.rbegin()); + } const int nchannels = 3; From aca8759d3118ee047b8ce18bd2c853b1fdb81e5e Mon Sep 17 00:00:00 2001 From: pingplug Date: Thu, 28 Sep 2023 16:05:22 +0800 Subject: [PATCH 06/18] fix wrong detector in detectCharucoDiamond use diamond detector instead of board detector in detectCharucoDiamond() --- modules/aruco/src/charuco.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/aruco/src/charuco.cpp b/modules/aruco/src/charuco.cpp index acf691a28b0..42dbd0d4a05 100644 --- a/modules/aruco/src/charuco.cpp +++ b/modules/aruco/src/charuco.cpp @@ -39,7 +39,7 @@ void detectCharucoDiamond(InputArray _image, InputArrayOfArrays _markerCorners, vector markerCorners; _markerCorners.getMatVector(markerCorners); - detector.detectBoard(_image, _diamondCorners, _diamondIds, markerCorners, _markerIds.getMat()); + detector.detectDiamonds(_image, _diamondCorners, _diamondIds, markerCorners, _markerIds.getMat()); } From 3f3ee66ea77d35fc70fd95ff25c91f72f5c9d80b Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Fri, 29 Sep 2023 15:25:06 +0300 Subject: [PATCH 07/18] Fixed compilation with SIMD disabled or with scalable SIMD --- modules/rgbd/src/tsdf_functions.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/rgbd/src/tsdf_functions.hpp b/modules/rgbd/src/tsdf_functions.hpp index 1031474d0b7..c763f9275e6 100644 --- a/modules/rgbd/src/tsdf_functions.hpp +++ b/modules/rgbd/src/tsdf_functions.hpp @@ -16,11 +16,13 @@ namespace cv namespace kinfu { +#if USE_INTRINSICS inline v_float32x4 tsdfToFloat_INTR(const v_int32x4& num) { v_float32x4 num128 = v_setall_f32(-1.f / 128.f); return v_cvt_f32(num) * num128; } +#endif inline TsdfType floatToTsdf(float num) { From 37c7495cefdd79f069505a3e88501125ca6fced8 Mon Sep 17 00:00:00 2001 From: Zhirui Dai Date: Sun, 1 Oct 2023 17:22:19 -0700 Subject: [PATCH 08/18] fix build with GNU13 --- modules/sfm/src/libmv_light/libmv/numeric/numeric.h | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/sfm/src/libmv_light/libmv/numeric/numeric.h b/modules/sfm/src/libmv_light/libmv/numeric/numeric.h index 9e7927e0bbc..41a55634dcd 100644 --- a/modules/sfm/src/libmv_light/libmv/numeric/numeric.h +++ b/modules/sfm/src/libmv_light/libmv/numeric/numeric.h @@ -32,6 +32,7 @@ #include #include #include +#include #if !defined(__MINGW32__) # if defined(_WIN32) || defined(__APPLE__) || \ From 36bb8727192340f038e1222c7599670ebc5cd88c Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Fri, 13 Oct 2023 22:47:22 +0300 Subject: [PATCH 09/18] CI: enable RISC-V for 4.x branch --- .github/workflows/PR-4.x.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/PR-4.x.yaml b/.github/workflows/PR-4.x.yaml index 250b5e157a6..f05e94bfa32 100644 --- a/.github/workflows/PR-4.x.yaml +++ b/.github/workflows/PR-4.x.yaml @@ -26,3 +26,6 @@ jobs: macOS-X64: uses: opencv/ci-gha-workflow/.github/workflows/OCV-Contrib-PR-4.x-macOS-x86_64.yaml@main + + Linux-RISC-V-Clang: + uses: opencv/ci-gha-workflow/.github/workflows/OCV-Contrib-PR-4.x-RISCV.yaml From b9a460b85733c75a700c61b52ccee1fe653e21db Mon Sep 17 00:00:00 2001 From: Liutong HAN Date: Sun, 8 Oct 2023 16:01:23 +0800 Subject: [PATCH 10/18] Use new Universal Intrinsic API. --- modules/optflow/src/rlof/berlof_invoker.hpp | 224 +++++++++--------- modules/optflow/src/rlof/plk_invoker.hpp | 74 +++--- modules/optflow/src/rlof/rlof_invoker.hpp | 132 +++++------ modules/optflow/src/rlof/rlof_invokerbase.hpp | 76 +++--- modules/optflow/src/rlof/rlof_localflow.cpp | 8 +- modules/rgbd/src/colored_tsdf.cpp | 120 +++++----- modules/rgbd/src/fast_icp.cpp | 48 ++-- modules/rgbd/src/hash_tsdf.cpp | 32 +-- modules/rgbd/src/tsdf.cpp | 90 ++++--- modules/rgbd/src/tsdf_functions.cpp | 83 +++---- modules/rgbd/src/tsdf_functions.hpp | 2 +- modules/rgbd/src/utils.hpp | 2 +- modules/ximgproc/src/anisodiff.cpp | 20 +- modules/ximgproc/src/fgs_filter.cpp | 58 ++--- .../xphoto/src/grayworld_white_balance.cpp | 56 ++--- .../src/learning_based_color_balance.cpp | 82 +++---- 16 files changed, 549 insertions(+), 558 deletions(-) diff --git a/modules/optflow/src/rlof/berlof_invoker.hpp b/modules/optflow/src/rlof/berlof_invoker.hpp index 8fde6e457c1..e51f8091cbe 100644 --- a/modules/optflow/src/rlof/berlof_invoker.hpp +++ b/modules/optflow/src/rlof/berlof_invoker.hpp @@ -296,7 +296,7 @@ class TrackerInvoker : public cv::ParallelLoopBody v_int16x8 v01 = v_reinterpret_as_s16(v_load_expand(Jptr + x + cn)); v_int16x8 v10 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x)); v_int16x8 v11 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x + cn)); - v_int16x8 vmask = v_reinterpret_as_s16(v_load_expand(maskPtr + x)) * vmax_val_16; + v_int16x8 vmask = v_mul(v_reinterpret_as_s16(v_load_expand(maskPtr + x)), vmax_val_16); v_int32x4 t0, t1; v_int16x8 t00, t01, t10, t11; @@ -304,35 +304,35 @@ class TrackerInvoker : public cv::ParallelLoopBody v_zip(v10, v11, t10, t11); //subpixel interpolation - t0 = v_dotprod(t00, vqw0, vdelta) + v_dotprod(t10, vqw1); - t1 = v_dotprod(t01, vqw0, vdelta) + v_dotprod(t11, vqw1); - t0 = t0 >> (W_BITS - 5); - t1 = t1 >> (W_BITS - 5); + t0 = v_add(v_dotprod(t00, vqw0, vdelta), v_dotprod(t10, vqw1)); + t1 = v_add(v_dotprod(t01, vqw0, vdelta), v_dotprod(t11, vqw1)); + t0 = v_shr(t0, W_BITS - 5); + t1 = v_shr(t1, W_BITS - 5); diff0 = v_pack(t0, t1); // I*gain.x + gain.x v_int16x8 diff[4] = { - ((v11 << 5) - vI) & vmask, - ((v01 << 5) - vI) & vmask, - ((v10 << 5) - vI) & vmask, - ((v00 << 5) - vI) & vmask + v_and(v_sub(v_shl<5>(v11), vI), vmask), + v_and(v_sub(v_shl<5>(v01), vI), vmask), + v_and(v_sub(v_shl<5>(v10), vI), vmask), + v_and(v_sub(v_shl<5>(v00), vI), vmask) }; - diff0 = diff0 - vI; - diff0 = diff0 & vmask; + diff0 = v_sub(diff0, vI); + diff0 = v_and(diff0, vmask); - v_int16x8 vscale_diff_is_pos = diff0 > vscale; - veta = veta + (vscale_diff_is_pos & v_setall_s16(2)) + v_setall_s16(-1); + v_int16x8 vscale_diff_is_pos = v_gt(diff0, vscale); + veta = v_add(v_add(veta, v_and(vscale_diff_is_pos, v_setall_s16(2))), v_setall_s16(-1)); // since there is no abs vor int16x8 we have to do this hack v_int16x8 vabs_diff = v_reinterpret_as_s16(v_abs(diff0)); v_int16x8 vset2, vset1; // |It| < sigma1 ? - vset2 = vabs_diff < vparam1; + vset2 = v_lt(vabs_diff, vparam1); // It > 0 ? - v_int16x8 vdiff_is_pos = diff0 > vzero; + v_int16x8 vdiff_is_pos = v_gt(diff0, vzero); // sigma0 < |It| < sigma1 ? - vset1 = vset2 & (vabs_diff > vparam0); + vset1 = v_and(vset2, v_gt(vabs_diff, vparam0)); // val = |It| -/+ sigma1 - v_int16x8 vtmp_param1 = diff0 + v_select(vdiff_is_pos, vneg_param1, vparam1); + v_int16x8 vtmp_param1 = v_add(diff0, v_select(vdiff_is_pos, vneg_param1, vparam1)); v_int16x8 vIxy_0 = v_reinterpret_as_s16(v_load(dIptr)); // Ix0 Iy0 Ix1 Iy1 ... v_int16x8 vIxy_1 = v_reinterpret_as_s16(v_load(dIptr + 8)); @@ -342,7 +342,7 @@ class TrackerInvoker : public cv::ParallelLoopBody for (unsigned int mmi = 0; mmi < 4; mmi++) { // It == 0 ? |It| > sigma13 - diff0 = vset2 & diff[mmi]; + diff0 = v_and(vset2, diff[mmi]); // It == val ? sigma0 < |It| < sigma1 diff0 = v_select(vset1, vtmp_param1, diff0); @@ -350,16 +350,16 @@ class TrackerInvoker : public cv::ParallelLoopBody // diff = diff * sigma2 v_int32x4 diff_int_0, diff_int_1; v_mul_expand(diff0, tale_, diff_int_0, diff_int_1); - v_int32x4 diff0_0 = diff_int_0 >> s2bitShift; - v_int32x4 diff0_1 = diff_int_1 >> s2bitShift; + v_int32x4 diff0_0 = v_shr(diff_int_0, s2bitShift); + v_int32x4 diff0_1 = v_shr(diff_int_1, s2bitShift); diff0 = v_pack(diff0_0, diff0_1); v_zip(diff0, diff0, diff2, diff1); // It0 It0 It1 It1 ... v_zip(vIxy_0, vIxy_1, v10, v11); v_zip(diff2, diff1, v00, v01); - vqb0[mmi] += v_cvt_f32(v_dotprod(v00, v10)); - vqb1[mmi] += v_cvt_f32(v_dotprod(v01, v11)); + vqb0[mmi] = v_add(vqb0[mmi], v_cvt_f32(v_dotprod(v00, v10))); + vqb1[mmi] = v_add(vqb1[mmi], v_cvt_f32(v_dotprod(v01, v11))); } if (j == 0) { @@ -387,8 +387,8 @@ class TrackerInvoker : public cv::ParallelLoopBody v_float32x4 fx = v_cvt_f32(t1); // A11 - A22 - v_float32x4 fxtale = fx * vtale_0; - v_float32x4 fytale = fy * vtale_0; + v_float32x4 fxtale = v_mul(fx, vtale_0); + v_float32x4 fytale = v_mul(fy, vtale_0); vAyy = v_muladd(fy, fytale, vAyy); vAxy = v_muladd(fx, fytale, vAxy); @@ -402,8 +402,8 @@ class TrackerInvoker : public cv::ParallelLoopBody fx = v_cvt_f32(t1); // A11 - A22 - fxtale = fx * vtale_1; - fytale = fy * vtale_1; + fxtale = v_mul(fx, vtale_1); + fytale = v_mul(fy, vtale_1); vAyy = v_muladd(fy, fytale, vAyy); vAxy = v_muladd(fx, fytale, vAxy); @@ -544,7 +544,7 @@ class TrackerInvoker : public cv::ParallelLoopBody float CV_DECL_ALIGNED(16) bbuf[4]; for (int mmi = 0; mmi < 4; mmi++) { - v_store_aligned(bbuf, vqb0[mmi] + vqb1[mmi]); + v_store_aligned(bbuf, v_add(vqb0[mmi], vqb1[mmi])); _b0[mmi] = bbuf[0] + bbuf[2]; _b1[mmi] = bbuf[1] + bbuf[3]; } @@ -960,7 +960,7 @@ class TrackerInvoker : public cv::ParallelLoopBody v_int16x8 v01 = v_reinterpret_as_s16(v_load_expand(Jptr + x + cn)); v_int16x8 v10 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x)); v_int16x8 v11 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x + cn)); - v_int16x8 vmask = v_reinterpret_as_s16(v_load_expand(maskPtr + x)) * vmax_val_16; + v_int16x8 vmask = v_mul(v_reinterpret_as_s16(v_load_expand(maskPtr + x)), vmax_val_16); v_int32x4 t0, t1; v_int16x8 t00, t01, t10, t11; @@ -968,38 +968,38 @@ class TrackerInvoker : public cv::ParallelLoopBody v_zip(v10, v11, t10, t11); //subpixel interpolation - t0 = v_dotprod(t00, vqw0, vdelta) + v_dotprod(t10, vqw1); - t1 = v_dotprod(t01, vqw0, vdelta) + v_dotprod(t11, vqw1); - t0 = t0 >> (W_BITS - 5); - t1 = t1 >> (W_BITS - 5); + t0 = v_add(v_dotprod(t00, vqw0, vdelta), v_dotprod(t10, vqw1)); + t1 = v_add(v_dotprod(t01, vqw0, vdelta), v_dotprod(t11, vqw1)); + t0 = v_shr(t0, W_BITS - 5); + t1 = v_shr(t1, W_BITS - 5); diff0 = v_pack(t0, t1); // I*gain.x + gain.x v_mul_expand(vI, vgain_value, t0, t1); - v_int16x8 diff_value = v_pack(t0 >> bitShift, t1 >> bitShift) + vconst_value - vI; + v_int16x8 diff_value = v_sub(v_add(v_pack(v_shr(t0, bitShift), v_shr(t1, bitShift)), vconst_value), vI); v_int16x8 diff[4] = { - ((v11 << 5) + diff_value) & vmask, - ((v01 << 5) + diff_value) & vmask, - ((v10 << 5) + diff_value) & vmask, - ((v00 << 5) + diff_value) & vmask + v_and(v_add(v_shl<5>(v11), diff_value), vmask), + v_and(v_add(v_shl<5>(v01), diff_value), vmask), + v_and(v_add(v_shl<5>(v10), diff_value), vmask), + v_and(v_add(v_shl<5>(v00), diff_value), vmask) }; - diff0 = diff0 + diff_value; - diff0 = diff0 & vmask; + diff0 = v_add(diff0, diff_value); + diff0 = v_and(diff0, vmask); - v_int16x8 vscale_diff_is_pos = diff0 > vscale; - veta = veta + (vscale_diff_is_pos & v_setall_s16(2)) + v_setall_s16(-1); + v_int16x8 vscale_diff_is_pos = v_gt(diff0, vscale); + veta = v_add(v_add(veta, v_and(vscale_diff_is_pos, v_setall_s16(2))), v_setall_s16(-1)); // since there is no abs vor int16x8 we have to do this hack v_int16x8 vabs_diff = v_reinterpret_as_s16(v_abs(diff0)); v_int16x8 vset2, vset1; // |It| < sigma1 ? - vset2 = vabs_diff < vparam1; + vset2 = v_lt(vabs_diff, vparam1); // It > 0 ? - v_int16x8 vdiff_is_pos = diff0 > vzero; + v_int16x8 vdiff_is_pos = v_gt(diff0, vzero); // sigma0 < |It| < sigma1 ? - vset1 = vset2 & (vabs_diff > vparam0); + vset1 = v_and(vset2, v_gt(vabs_diff, vparam0)); // val = |It| -/+ sigma1 - v_int16x8 vtmp_param1 = diff0 + v_select(vdiff_is_pos, vneg_param1, vparam1); + v_int16x8 vtmp_param1 = v_add(diff0, v_select(vdiff_is_pos, vneg_param1, vparam1)); v_int16x8 vIxy_0 = v_reinterpret_as_s16(v_load(dIptr)); // Ix0 Iy0 Ix1 Iy1 ... v_int16x8 vIxy_1 = v_reinterpret_as_s16(v_load(dIptr + 8)); @@ -1009,7 +1009,7 @@ class TrackerInvoker : public cv::ParallelLoopBody for (unsigned int mmi = 0; mmi < 4; mmi++) { // It == 0 ? |It| > sigma13 - diff0 = vset2 & diff[mmi]; + diff0 = v_and(vset2, diff[mmi]); // It == val ? sigma0 < |It| < sigma1 diff0 = v_select(vset1, vtmp_param1, diff0); @@ -1017,22 +1017,22 @@ class TrackerInvoker : public cv::ParallelLoopBody // diff = diff * sigma2 v_int32x4 diff_int_0, diff_int_1; v_mul_expand(diff0, tale_, diff_int_0, diff_int_1); - v_int32x4 diff0_0 = diff_int_0 >> s2bitShift; - v_int32x4 diff0_1 = diff_int_1 >> s2bitShift; + v_int32x4 diff0_0 = v_shr(diff_int_0, s2bitShift); + v_int32x4 diff0_1 = v_shr(diff_int_1, s2bitShift); diff0 = v_pack(diff0_0, diff0_1); v_zip(diff0, diff0, diff2, diff1); // It0 It0 It1 It1 ... v_zip(vIxy_0, vIxy_1, v10, v11); v_zip(diff2, diff1, v00, v01); - vqb0[mmi] += v_cvt_f32(v_dotprod(v00, v10)); - vqb1[mmi] += v_cvt_f32(v_dotprod(v01, v11)); + vqb0[mmi] = v_add(vqb0[mmi], v_cvt_f32(v_dotprod(v00, v10))); + vqb1[mmi] = v_add(vqb1[mmi], v_cvt_f32(v_dotprod(v01, v11))); - vqb2[mmi] += v_cvt_f32(diff0_0 * vI0); - vqb2[mmi] += v_cvt_f32(diff0_1 * vI1); + vqb2[mmi] = v_add(vqb2[mmi], v_cvt_f32(v_mul(diff0_0, vI0))); + vqb2[mmi] = v_add(vqb2[mmi], v_cvt_f32(v_mul(diff0_1, vI1))); - vqb3[mmi] += v_cvt_f32(diff0_0); - vqb3[mmi] += v_cvt_f32(diff0_1); + vqb3[mmi] = v_add(vqb3[mmi], v_cvt_f32(diff0_0)); + vqb3[mmi] = v_add(vqb3[mmi], v_cvt_f32(diff0_1)); } if (j == 0) { @@ -1060,29 +1060,29 @@ class TrackerInvoker : public cv::ParallelLoopBody v_float32x4 fx = v_cvt_f32(t1); // A11 - A22 - v_float32x4 fxtale = fx * vtale_0; - v_float32x4 fytale = fy * vtale_0; + v_float32x4 fxtale = v_mul(fx, vtale_0); + v_float32x4 fytale = v_mul(fy, vtale_0); vAyy = v_muladd(fy, fytale, vAyy); vAxy = v_muladd(fx, fytale, vAxy); vAxx = v_muladd(fx, fxtale, vAxx); // sumIx und sumIy - vsumIx += fxtale; - vsumIy += fytale; + vsumIx = v_add(vsumIx, fxtale); + vsumIy = v_add(vsumIy, fytale); - vsumW1 += vI_ps * fxtale; - vsumW2 += vI_ps * fytale; + vsumW1 = v_add(vsumW1, v_mul(vI_ps, fxtale)); + vsumW2 = v_add(vsumW2, v_mul(vI_ps, fytale)); // sumI - v_float32x4 vI_tale = vI_ps * vtale_0; - vsumI += vI_tale; + v_float32x4 vI_tale = v_mul(vI_ps, vtale_0); + vsumI = v_add(vsumI, vI_tale); // sumW - vsumW += vtale_0; + vsumW = v_add(vsumW, vtale_0); // sumDI - vsumDI += vI_ps * vI_tale; + vsumDI = v_add(vsumDI, v_mul(vI_ps, vI_tale)); v01 = v_reinterpret_as_s16(v_interleave_pairs(v_reinterpret_as_s32(v_interleave_pairs(vIxy_1)))); v_expand(v01, t1, t0); @@ -1092,29 +1092,29 @@ class TrackerInvoker : public cv::ParallelLoopBody fx = v_cvt_f32(t1); // A11 - A22 - fxtale = fx * vtale_1; - fytale = fy * vtale_1; + fxtale = v_mul(fx, vtale_1); + fytale = v_mul(fy, vtale_1); vAyy = v_muladd(fy, fytale, vAyy); vAxy = v_muladd(fx, fytale, vAxy); vAxx = v_muladd(fx, fxtale, vAxx); // sumIx und sumIy - vsumIx += fxtale; - vsumIy += fytale; + vsumIx = v_add(vsumIx, fxtale); + vsumIy = v_add(vsumIy, fytale); - vsumW1 += vI_ps * fxtale; - vsumW2 += vI_ps * fytale; + vsumW1 = v_add(vsumW1, v_mul(vI_ps, fxtale)); + vsumW2 = v_add(vsumW2, v_mul(vI_ps, fytale)); // sumI - vI_tale = vI_ps * vtale_1; - vsumI += vI_tale; + vI_tale = v_mul(vI_ps, vtale_1); + vsumI = v_add(vsumI, vI_tale); // sumW - vsumW += vtale_1; + vsumW = v_add(vsumW, vtale_1); // sumDI - vsumDI += vI_ps * vI_tale; + vsumDI = v_add(vsumDI, v_mul(vI_ps, vI_tale)); } } @@ -1304,7 +1304,7 @@ class TrackerInvoker : public cv::ParallelLoopBody float CV_DECL_ALIGNED(16) bbuf[4]; for(int mmi = 0; mmi < 4; mmi++) { - v_store_aligned(bbuf, vqb0[mmi] + vqb1[mmi]); + v_store_aligned(bbuf, v_add(vqb0[mmi], vqb1[mmi])); _b0[mmi] = bbuf[0] + bbuf[2]; _b1[mmi] = bbuf[1] + bbuf[3]; _b2[mmi] = v_reduce_sum(vqb2[mmi]); @@ -1655,14 +1655,14 @@ class TrackerInvoker : public cv::ParallelLoopBody v_int16x8 v01 = v_reinterpret_as_s16(v_load_expand(Jptr + x + cn)); v_int16x8 v10 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x)); v_int16x8 v11 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x + cn)); - v_int16x8 vmask = v_reinterpret_as_s16(v_load_expand(maskPtr + x)) * vmax_val_16; + v_int16x8 vmask = v_mul(v_reinterpret_as_s16(v_load_expand(maskPtr + x)), vmax_val_16); v_int16x8 diff[4] = { - ((v00 << 5) - vI) & vmask, - ((v01 << 5) - vI) & vmask, - ((v10 << 5) - vI) & vmask, - ((v11 << 5) - vI) & vmask, + v_and(v_sub(v_shl<5>(v00), vI), vmask), + v_and(v_sub(v_shl<5>(v01), vI), vmask), + v_and(v_sub(v_shl<5>(v10), vI), vmask), + v_and(v_sub(v_shl<5>(v11), vI), vmask), }; v_int16x8 vIxy_0 = v_reinterpret_as_s16(v_load(dIptr)); // Ix0 Iy0 Ix1 Iy1 ... @@ -1672,8 +1672,8 @@ class TrackerInvoker : public cv::ParallelLoopBody v_zip(diff[mmi], diff[mmi], diff1, diff0); v_zip(vIxy_0, vIxy_1, v10, v11); v_zip(diff1, diff0, v00, v01); - vqb0[mmi] += v_cvt_f32(v_dotprod(v00, v10)); - vqb1[mmi] += v_cvt_f32(v_dotprod(v01, v11)); + vqb0[mmi] = v_add(vqb0[mmi], v_cvt_f32(v_dotprod(v00, v10))); + vqb1[mmi] = v_add(vqb1[mmi], v_cvt_f32(v_dotprod(v01, v11))); } } #else @@ -1704,7 +1704,7 @@ class TrackerInvoker : public cv::ParallelLoopBody float CV_DECL_ALIGNED(16) bbuf[4]; for (int mmi = 0; mmi < 4; mmi++) { - v_store_aligned(bbuf, vqb0[mmi] + vqb1[mmi]); + v_store_aligned(bbuf, v_add(vqb0[mmi], vqb1[mmi])); _b1[mmi] = bbuf[0] + bbuf[2]; _b2[mmi] = bbuf[1] + bbuf[3]; } @@ -2071,7 +2071,7 @@ namespace radial { v_int16x8 v01 = v_reinterpret_as_s16(v_load_expand(Jptr + x + cn)); v_int16x8 v10 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x)); v_int16x8 v11 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x + cn)); - v_int16x8 vmask = v_reinterpret_as_s16(v_load_expand(maskPtr + x)) * vmax_val_16; + v_int16x8 vmask = v_mul(v_reinterpret_as_s16(v_load_expand(maskPtr + x)), vmax_val_16); v_int32x4 t0, t1; v_int16x8 t00, t01, t10, t11; @@ -2079,21 +2079,21 @@ namespace radial { v_zip(v10, v11, t10, t11); //subpixel interpolation - t0 = v_dotprod(t00, vqw0, vdelta) + v_dotprod(t10, vqw1); - t1 = v_dotprod(t01, vqw0, vdelta) + v_dotprod(t11, vqw1); - t0 = t0 >> (W_BITS - 5); - t1 = t1 >> (W_BITS - 5); + t0 = v_add(v_dotprod(t00, vqw0, vdelta), v_dotprod(t10, vqw1)); + t1 = v_add(v_dotprod(t01, vqw0, vdelta), v_dotprod(t11, vqw1)); + t0 = v_shr(t0, W_BITS - 5); + t1 = v_shr(t1, W_BITS - 5); diff0 = v_pack(t0, t1); // I*gain.x + gain.x v_mul_expand(vI, vgain_value, t0, t1); - v_int16x8 diff_value = v_pack(t0 >> bitShift, t1 >> bitShift) + vconst_value - vI; + v_int16x8 diff_value = v_sub(v_add(v_pack(v_shr(t0, bitShift), v_shr(t1, bitShift)), vconst_value), vI); v_int16x8 diff[4] = { - ((v11 << 5) + diff_value) & vmask, - ((v01 << 5) + diff_value) & vmask, - ((v10 << 5) + diff_value) & vmask, - ((v00 << 5) + diff_value) & vmask + v_and(v_add(v_shl<5>(v11), diff_value), vmask), + v_and(v_add(v_shl<5>(v01), diff_value), vmask), + v_and(v_add(v_shl<5>(v10), diff_value), vmask), + v_and(v_add(v_shl<5>(v00), diff_value), vmask) }; v_int16x8 vIxy_0 = v_reinterpret_as_s16(v_load(dIptr)); // Ix0 Iy0 Ix1 Iy1 ... v_int16x8 vIxy_1 = v_reinterpret_as_s16(v_load(dIptr + 8)); @@ -2109,14 +2109,14 @@ namespace radial { v_zip(diff[mmi], diff[mmi], diff2, diff1); v_zip(diff2, diff1, v00, v01); - vqb0[mmi] += v_cvt_f32(v_dotprod(v00, v10)); - vqb1[mmi] += v_cvt_f32(v_dotprod(v01, v11)); + vqb0[mmi] = v_add(vqb0[mmi], v_cvt_f32(v_dotprod(v00, v10))); + vqb1[mmi] = v_add(vqb1[mmi], v_cvt_f32(v_dotprod(v01, v11))); - vqb2[mmi] += v_cvt_f32(diff0_0 * vI0); - vqb2[mmi] += v_cvt_f32(diff0_1 * vI1); + vqb2[mmi] = v_add(vqb2[mmi], v_cvt_f32(v_mul(diff0_0, vI0))); + vqb2[mmi] = v_add(vqb2[mmi], v_cvt_f32(v_mul(diff0_1, vI1))); - vqb3[mmi] += v_cvt_f32(diff0_0); - vqb3[mmi] += v_cvt_f32(diff0_1); + vqb3[mmi] = v_add(vqb3[mmi], v_cvt_f32(diff0_0)); + vqb3[mmi] = v_add(vqb3[mmi], v_cvt_f32(diff0_1)); } if (j == 0) { @@ -2133,17 +2133,17 @@ namespace radial { vAxx = v_muladd(fx, fx, vAxx); // sumIx und sumIy - vsumIx += fx; - vsumIy += fy; + vsumIx = v_add(vsumIx, fx); + vsumIy = v_add(vsumIy, fy); - vsumW1 += vI_ps * fx; - vsumW2 += vI_ps * fy; + vsumW1 = v_add(vsumW1, v_mul(vI_ps, fx)); + vsumW2 = v_add(vsumW2, v_mul(vI_ps, fy)); // sumI - vsumI += vI_ps; + vsumI = v_add(vsumI, vI_ps); // sumDI - vsumDI += vI_ps * vI_ps; + vsumDI = v_add(vsumDI, v_mul(vI_ps, vI_ps)); v01 = v_reinterpret_as_s16(v_interleave_pairs(v_reinterpret_as_s32(v_interleave_pairs(vIxy_1)))); v_expand(v01, t1, t0); @@ -2158,17 +2158,17 @@ namespace radial { vAxx = v_muladd(fx, fx, vAxx); // sumIx und sumIy - vsumIx += fx; - vsumIy += fy; + vsumIx = v_add(vsumIx, fx); + vsumIy = v_add(vsumIy, fy); - vsumW1 += vI_ps * fx; - vsumW2 += vI_ps * fy; + vsumW1 = v_add(vsumW1, v_mul(vI_ps, fx)); + vsumW2 = v_add(vsumW2, v_mul(vI_ps, fy)); // sumI - vsumI += vI_ps; + vsumI = v_add(vsumI, vI_ps); // sumDI - vsumDI += vI_ps * vI_ps; + vsumDI = v_add(vsumDI, v_mul(vI_ps, vI_ps)); } } @@ -2299,7 +2299,7 @@ namespace radial { float CV_DECL_ALIGNED(16) bbuf[4]; for (int mmi = 0; mmi < 4; mmi++) { - v_store_aligned(bbuf, vqb0[mmi] + vqb1[mmi]); + v_store_aligned(bbuf, v_add(vqb0[mmi], vqb1[mmi])); _b0[mmi] = bbuf[0] + bbuf[2]; _b1[mmi] = bbuf[1] + bbuf[3]; _b2[mmi] = v_reduce_sum(vqb2[mmi]); diff --git a/modules/optflow/src/rlof/plk_invoker.hpp b/modules/optflow/src/rlof/plk_invoker.hpp index 5ea85de889e..71cf50c8205 100644 --- a/modules/optflow/src/rlof/plk_invoker.hpp +++ b/modules/optflow/src/rlof/plk_invoker.hpp @@ -229,7 +229,7 @@ class TrackerInvoker : public cv::ParallelLoopBody v_int16x8 v01 = v_reinterpret_as_s16(v_load_expand(Jptr + x + cn)); v_int16x8 v10 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x)); v_int16x8 v11 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x + cn)); - v_int16x8 vmask = v_reinterpret_as_s16(v_load_expand(maskPtr + x)) * vmax_val_16; + v_int16x8 vmask = v_mul(v_reinterpret_as_s16(v_load_expand(maskPtr + x)), vmax_val_16); v_int32x4 t0, t1; v_int16x8 t00, t01, t10, t11; @@ -237,17 +237,17 @@ class TrackerInvoker : public cv::ParallelLoopBody v_zip(v10, v11, t10, t11); //subpixel interpolation - t0 = v_dotprod(t00, vqw0, vdelta) + v_dotprod(t10, vqw1); - t1 = v_dotprod(t01, vqw0, vdelta) + v_dotprod(t11, vqw1); - t0 = t0 >> (W_BITS - 5); - t1 = t1 >> (W_BITS - 5); + t0 = v_add(v_dotprod(t00, vqw0, vdelta), v_dotprod(t10, vqw1)); + t1 = v_add(v_dotprod(t01, vqw0, vdelta), v_dotprod(t11, vqw1)); + t0 = v_shr(t0, W_BITS - 5); + t1 = v_shr(t1, W_BITS - 5); // diff = J - I - diff0 = v_pack(t0, t1) - vI; + diff0 = v_sub(v_pack(t0, t1), vI); // I*gain.x + gain.x v_mul_expand(vI, vgain_value, t0, t1); - diff0 = diff0 + v_pack(t0 >> bitShift, t1 >> bitShift) + vconst_value; - diff0 = diff0 & vmask; + diff0 = v_add(v_add(diff0, v_pack(v_shr(t0, bitShift), v_shr(t1, bitShift))), vconst_value); + diff0 = v_and(diff0, vmask); v_zip(diff0, diff0, diff2, diff1); v_int32x4 diff0_0; @@ -259,16 +259,16 @@ class TrackerInvoker : public cv::ParallelLoopBody v_zip(vIxy_0, vIxy_1, v10, v11); v_zip(diff2, diff1, v00, v01); - vqb0 += v_cvt_f32(v_dotprod(v00, v10)); - vqb1 += v_cvt_f32(v_dotprod(v01, v11)); + vqb0 = v_add(vqb0, v_cvt_f32(v_dotprod(v00, v10))); + vqb1 = v_add(vqb1, v_cvt_f32(v_dotprod(v01, v11))); v_int32x4 vI0, vI1; v_expand(vI, vI0, vI1); - vqb2 += v_cvt_f32(diff0_0 * vI0); - vqb2 += v_cvt_f32(diff0_1 * vI1); + vqb2 = v_add(vqb2, v_cvt_f32(v_mul(diff0_0, vI0))); + vqb2 = v_add(vqb2, v_cvt_f32(v_mul(diff0_1, vI1))); - vqb3 += v_cvt_f32(diff0_0); - vqb3 += v_cvt_f32(diff0_1); + vqb3 = v_add(vqb3, v_cvt_f32(diff0_0)); + vqb3 = v_add(vqb3, v_cvt_f32(diff0_1)); if (j == 0) { @@ -285,17 +285,17 @@ class TrackerInvoker : public cv::ParallelLoopBody vAxx = v_muladd(fx, fx, vAxx); // sumIx und sumIy - vsumIx += fx; - vsumIy += fy; + vsumIx = v_add(vsumIx, fx); + vsumIy = v_add(vsumIy, fy); - vsumW1 += vI_ps * fx; - vsumW2 += vI_ps * fy; + vsumW1 = v_add(vsumW1, v_mul(vI_ps, fx)); + vsumW2 = v_add(vsumW2, v_mul(vI_ps, fy)); // sumI - vsumI += vI_ps; + vsumI = v_add(vsumI, vI_ps); // sumDI - vsumDI += vI_ps * vI_ps; + vsumDI = v_add(vsumDI, v_mul(vI_ps, vI_ps)); v01 = v_reinterpret_as_s16(v_interleave_pairs(v_reinterpret_as_s32(v_interleave_pairs(vIxy_1)))); v_expand(v01, t1, t0); @@ -309,17 +309,17 @@ class TrackerInvoker : public cv::ParallelLoopBody vAxx = v_muladd(fx, fx, vAxx); // sumIx und sumIy - vsumIx += fx; - vsumIy += fy; + vsumIx = v_add(vsumIx, fx); + vsumIy = v_add(vsumIy, fy); - vsumW1 += vI_ps * fx; - vsumW2 += vI_ps * fy; + vsumW1 = v_add(vsumW1, v_mul(vI_ps, fx)); + vsumW2 = v_add(vsumW2, v_mul(vI_ps, fy)); // sumI - vsumI += vI_ps; + vsumI = v_add(vsumI, vI_ps); // sumDI - vsumDI += vI_ps * vI_ps; + vsumDI = v_add(vsumDI, v_mul(vI_ps, vI_ps)); } } #else @@ -388,7 +388,7 @@ class TrackerInvoker : public cv::ParallelLoopBody #if CV_SIMD128 float CV_DECL_ALIGNED(16) bbuf[4]; - v_store_aligned(bbuf, vqb0 + vqb1); + v_store_aligned(bbuf, v_add(vqb0, vqb1)); b1 = bbuf[0] + bbuf[2]; b2 = bbuf[1] + bbuf[3]; b3 = v_reduce_sum(vqb2); @@ -696,19 +696,19 @@ class TrackerInvoker : public cv::ParallelLoopBody v_int16x8 v01 = v_reinterpret_as_s16(v_load_expand(Jptr + x + cn)); v_int16x8 v10 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x)); v_int16x8 v11 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x + cn)); - v_int16x8 vmask = v_reinterpret_as_s16(v_load_expand(maskPtr + x)) * vmax_val_16; + v_int16x8 vmask = v_mul(v_reinterpret_as_s16(v_load_expand(maskPtr + x)), vmax_val_16); v_int32x4 t0, t1; v_int16x8 t00, t01, t10, t11; v_zip(v00, v01, t00, t01); v_zip(v10, v11, t10, t11); - t0 = v_dotprod(t00, vqw0, vdelta) + v_dotprod(t10, vqw1); - t1 = v_dotprod(t01, vqw0, vdelta) + v_dotprod(t11, vqw1); - t0 = t0 >> (W_BITS - 5); - t1 = t1 >> (W_BITS - 5); - diff0 = v_pack(t0, t1) - diff0; - diff0 = diff0 & vmask; + t0 = v_add(v_dotprod(t00, vqw0, vdelta), v_dotprod(t10, vqw1)); + t1 = v_add(v_dotprod(t01, vqw0, vdelta), v_dotprod(t11, vqw1)); + t0 = v_shr(t0, W_BITS - 5); + t1 = v_shr(t1, W_BITS - 5); + diff0 = v_sub(v_pack(t0, t1), diff0); + diff0 = v_and(diff0, vmask); v_zip(diff0, diff0, diff2, diff1); // It0 It0 It1 It1 ... @@ -717,8 +717,8 @@ class TrackerInvoker : public cv::ParallelLoopBody v_zip(vIxy_0, vIxy_1, v10, v11); v_zip(diff2, diff1, v00, v01); - vqb0 += v_cvt_f32(v_dotprod(v00, v10)); - vqb1 += v_cvt_f32(v_dotprod(v01, v11)); + vqb0 = v_add(vqb0, v_cvt_f32(v_dotprod(v00, v10))); + vqb1 = v_add(vqb1, v_cvt_f32(v_dotprod(v01, v11))); } #else for( ; x < winSize.width*cn; x++, dIptr += 2 ) @@ -737,7 +737,7 @@ class TrackerInvoker : public cv::ParallelLoopBody #if CV_SIMD128 float CV_DECL_ALIGNED(16) bbuf[4]; - v_store_aligned(bbuf, vqb0 + vqb1); + v_store_aligned(bbuf, v_add(vqb0, vqb1)); b1 = bbuf[0] + bbuf[2]; b2 = bbuf[1] + bbuf[3]; #endif diff --git a/modules/optflow/src/rlof/rlof_invoker.hpp b/modules/optflow/src/rlof/rlof_invoker.hpp index 9bee35fc6a3..5597d882491 100644 --- a/modules/optflow/src/rlof/rlof_invoker.hpp +++ b/modules/optflow/src/rlof/rlof_invoker.hpp @@ -246,35 +246,35 @@ class TrackerInvoker : public cv::ParallelLoopBody v_int16x8 v01 = v_reinterpret_as_s16(v_load_expand(Jptr + x + cn)); v_int16x8 v10 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x)); v_int16x8 v11 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x + cn)); - v_int16x8 vmask = v_reinterpret_as_s16(v_load_expand(maskPtr + x)) * vmax_val_16; + v_int16x8 vmask = v_mul(v_reinterpret_as_s16(v_load_expand(maskPtr + x)), vmax_val_16); v_int32x4 t0, t1; v_int16x8 t00, t01, t10, t11; v_zip(v00, v01, t00, t01); v_zip(v10, v11, t10, t11); - t0 = v_dotprod(t00, vqw0, vdelta) + v_dotprod(t10, vqw1); - t1 = v_dotprod(t01, vqw0, vdelta) + v_dotprod(t11, vqw1); - t0 = t0 >> (W_BITS - 5); - t1 = t1 >> (W_BITS - 5); - diff0 = v_pack(t0, t1) - diff0; - diff0 = diff0 & vmask; + t0 = v_add(v_dotprod(t00, vqw0, vdelta), v_dotprod(t10, vqw1)); + t1 = v_add(v_dotprod(t01, vqw0, vdelta), v_dotprod(t11, vqw1)); + t0 = v_shr(t0, W_BITS - 5); + t1 = v_shr(t1, W_BITS - 5); + diff0 = v_sub(v_pack(t0, t1), diff0); + diff0 = v_and(diff0, vmask); - v_int16x8 vscale_diff_is_pos = diff0 > vscale; - veta = veta + (vscale_diff_is_pos & v_setall_s16(2)) + v_setall_s16(-1); + v_int16x8 vscale_diff_is_pos = v_gt(diff0, vscale); + veta = v_add(v_add(veta, v_and(vscale_diff_is_pos, v_setall_s16(2))), v_setall_s16(-1)); // since there is no abs vor int16x8 we have to do this hack v_int16x8 vabs_diff = v_reinterpret_as_s16(v_abs(diff0)); v_int16x8 vset2, vset1; // |It| < sigma1 ? - vset2 = vabs_diff < vparam1; + vset2 = v_lt(vabs_diff, vparam1); // It > 0 ? - v_int16x8 vdiff_is_pos = diff0 > vzero; + v_int16x8 vdiff_is_pos = v_gt(diff0, vzero); // sigma0 < |It| < sigma1 ? - vset1 = vset2 & (vabs_diff > vparam0); + vset1 = v_and(vset2, v_gt(vabs_diff, vparam0)); // val = |It| -/+ sigma1 - v_int16x8 vtmp_param1 = diff0 + v_select(vdiff_is_pos, vneg_param1, vparam1); + v_int16x8 vtmp_param1 = v_add(diff0, v_select(vdiff_is_pos, vneg_param1, vparam1)); // It == 0 ? |It| > sigma13 - diff0 = vset2 & diff0; + diff0 = v_and(vset2, diff0); // It == val ? sigma0 < |It| < sigma1 diff0 = v_select(vset1, vtmp_param1, diff0); @@ -282,7 +282,7 @@ class TrackerInvoker : public cv::ParallelLoopBody // diff = diff * sigma2 v_int32x4 diff_int_0, diff_int_1; v_mul_expand(diff0, tale_, diff_int_0, diff_int_1); - diff0 = v_pack(diff_int_0 >> s2bitShift, diff_int_1 >> s2bitShift); + diff0 = v_pack(v_shr(diff_int_0, s2bitShift), v_shr(diff_int_1, s2bitShift)); v_zip(diff0, diff0, diff2, diff1); // It0 It0 It1 It1 ... v_int16x8 vIxy_0 = v_reinterpret_as_s16(v_load(dIptr)); // Ix0 Iy0 Ix1 Iy1 ... @@ -290,8 +290,8 @@ class TrackerInvoker : public cv::ParallelLoopBody v_zip(vIxy_0, vIxy_1, v10, v11); v_zip(diff2, diff1, v00, v01); - vqb0 += v_cvt_f32(v_dotprod(v00, v10)); - vqb1 += v_cvt_f32(v_dotprod(v01, v11)); + vqb0 = v_add(vqb0, v_cvt_f32(v_dotprod(v00, v10))); + vqb1 = v_add(vqb1, v_cvt_f32(v_dotprod(v01, v11))); if (j == 0) { v_int32x4 vset1_0, vset1_1, vset2_0, vset2_1; @@ -316,8 +316,8 @@ class TrackerInvoker : public cv::ParallelLoopBody v_float32x4 fx = v_cvt_f32(t1); // A11 - A22 - v_float32x4 fxtale = fx * vtale_0; - v_float32x4 fytale = fy * vtale_0; + v_float32x4 fxtale = v_mul(fx, vtale_0); + v_float32x4 fytale = v_mul(fy, vtale_0); vAyy = v_muladd(fy, fytale, vAyy); vAxy = v_muladd(fx, fytale, vAxy); @@ -330,8 +330,8 @@ class TrackerInvoker : public cv::ParallelLoopBody fx = v_cvt_f32(t1); // A11 - A22 - fxtale = fx * vtale_1; - fytale = fy * vtale_1; + fxtale = v_mul(fx, vtale_1); + fytale = v_mul(fy, vtale_1); vAyy = v_muladd(fy, fytale, vAyy); vAxy = v_muladd(fx, fytale, vAxy); @@ -431,7 +431,7 @@ class TrackerInvoker : public cv::ParallelLoopBody #if CV_SIMD128 float CV_DECL_ALIGNED(16) bbuf[4]; - v_store_aligned(bbuf, vqb0 + vqb1); + v_store_aligned(bbuf, v_add(vqb0, vqb1)); b1 += bbuf[0] + bbuf[2]; b2 += bbuf[1] + bbuf[3]; #endif @@ -769,7 +769,7 @@ class TrackerInvoker : public cv::ParallelLoopBody v_int16x8 v01 = v_reinterpret_as_s16(v_load_expand(Jptr + x + cn)); v_int16x8 v10 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x)); v_int16x8 v11 = v_reinterpret_as_s16(v_load_expand(Jptr1 + x + cn)); - v_int16x8 vmask = v_reinterpret_as_s16(v_load_expand(maskPtr + x)) * vmax_val_16; + v_int16x8 vmask = v_mul(v_reinterpret_as_s16(v_load_expand(maskPtr + x)), vmax_val_16); v_int32x4 t0, t1; v_int16x8 t00, t01, t10, t11; @@ -777,33 +777,33 @@ class TrackerInvoker : public cv::ParallelLoopBody v_zip(v10, v11, t10, t11); //subpixel interpolation - t0 = v_dotprod(t00, vqw0, vdelta) + v_dotprod(t10, vqw1); - t1 = v_dotprod(t01, vqw0, vdelta) + v_dotprod(t11, vqw1); - t0 = t0 >> (W_BITS - 5); - t1 = t1 >> (W_BITS - 5); + t0 = v_add(v_dotprod(t00, vqw0, vdelta), v_dotprod(t10, vqw1)); + t1 = v_add(v_dotprod(t01, vqw0, vdelta), v_dotprod(t11, vqw1)); + t0 = v_shr(t0, W_BITS - 5); + t1 = v_shr(t1, W_BITS - 5); // diff = J - I - diff0 = v_pack(t0, t1) - vI; + diff0 = v_sub(v_pack(t0, t1), vI); // I*gain.x + gain.x v_mul_expand(vI, vgain_value, t0, t1); - diff0 = diff0 + v_pack(t0 >> bitShift, t1 >> bitShift) + vconst_value; - diff0 = diff0 & vmask; + diff0 = v_add(v_add(diff0, v_pack(v_shr(t0, bitShift), v_shr(t1, bitShift))), vconst_value); + diff0 = v_and(diff0, vmask); - v_int16x8 vscale_diff_is_pos = diff0 > vscale; - veta = veta + (vscale_diff_is_pos & v_setall_s16(2)) + v_setall_s16(-1); + v_int16x8 vscale_diff_is_pos = v_gt(diff0, vscale); + veta = v_add(v_add(veta, v_and(vscale_diff_is_pos, v_setall_s16(2))), v_setall_s16(-1)); // since there is no abs vor int16x8 we have to do this hack v_int16x8 vabs_diff = v_reinterpret_as_s16(v_abs(diff0)); v_int16x8 vset2, vset1; // |It| < sigma1 ? - vset2 = vabs_diff < vparam1; + vset2 = v_lt(vabs_diff, vparam1); // It > 0 ? - v_int16x8 vdiff_is_pos = diff0 > vzero; + v_int16x8 vdiff_is_pos = v_gt(diff0, vzero); // sigma0 < |It| < sigma1 ? - vset1 = vset2 & (vabs_diff > vparam0); + vset1 = v_and(vset2, v_gt(vabs_diff, vparam0)); // val = |It| -/+ sigma1 - v_int16x8 vtmp_param1 = diff0 + v_select(vdiff_is_pos, vneg_param1, vparam1); + v_int16x8 vtmp_param1 = v_add(diff0, v_select(vdiff_is_pos, vneg_param1, vparam1)); // It == 0 ? |It| > sigma13 - diff0 = vset2 & diff0; + diff0 = v_and(vset2, diff0); // It == val ? sigma0 < |It| < sigma1 diff0 = v_select(vset1, vtmp_param1, diff0); @@ -811,8 +811,8 @@ class TrackerInvoker : public cv::ParallelLoopBody // diff = diff * sigma2 v_int32x4 diff_int_0, diff_int_1; v_mul_expand(diff0, tale_, diff_int_0, diff_int_1); - v_int32x4 diff0_0 = diff_int_0 >> s2bitShift; - v_int32x4 diff0_1 = diff_int_1 >> s2bitShift; + v_int32x4 diff0_0 = v_shr(diff_int_0, s2bitShift); + v_int32x4 diff0_1 = v_shr(diff_int_1, s2bitShift); diff0 = v_pack(diff0_0, diff0_1); v_zip(diff0, diff0, diff2, diff1); // It0 It0 It1 It1 ... @@ -821,16 +821,16 @@ class TrackerInvoker : public cv::ParallelLoopBody v_zip(vIxy_0, vIxy_1, v10, v11); v_zip(diff2, diff1, v00, v01); - vqb0 += v_cvt_f32(v_dotprod(v00, v10)); - vqb1 += v_cvt_f32(v_dotprod(v01, v11)); + vqb0 = v_add(vqb0, v_cvt_f32(v_dotprod(v00, v10))); + vqb1 = v_add(vqb1, v_cvt_f32(v_dotprod(v01, v11))); v_int32x4 vI0, vI1; v_expand(vI, vI0, vI1); - vqb2 += v_cvt_f32(diff0_0 * vI0); - vqb2 += v_cvt_f32(diff0_1 * vI1); + vqb2 = v_add(vqb2, v_cvt_f32(v_mul(diff0_0, vI0))); + vqb2 = v_add(vqb2, v_cvt_f32(v_mul(diff0_1, vI1))); - vqb3 += v_cvt_f32(diff0_0); - vqb3 += v_cvt_f32(diff0_1); + vqb3 = v_add(vqb3, v_cvt_f32(diff0_0)); + vqb3 = v_add(vqb3, v_cvt_f32(diff0_1)); if (j == 0) { @@ -858,29 +858,29 @@ class TrackerInvoker : public cv::ParallelLoopBody v_float32x4 fx = v_cvt_f32(t1); // A11 - A22 - v_float32x4 fxtale = fx * vtale_0; - v_float32x4 fytale = fy * vtale_0; + v_float32x4 fxtale = v_mul(fx, vtale_0); + v_float32x4 fytale = v_mul(fy, vtale_0); vAyy = v_muladd(fy, fytale, vAyy); vAxy = v_muladd(fx, fytale, vAxy); vAxx = v_muladd(fx, fxtale, vAxx); // sumIx und sumIy - vsumIx += fxtale; - vsumIy += fytale; + vsumIx = v_add(vsumIx, fxtale); + vsumIy = v_add(vsumIy, fytale); - vsumW1 += vI_ps * fxtale; - vsumW2 += vI_ps * fytale; + vsumW1 = v_add(vsumW1, v_mul(vI_ps, fxtale)); + vsumW2 = v_add(vsumW2, v_mul(vI_ps, fytale)); // sumI - v_float32x4 vI_tale = vI_ps * vtale_0; - vsumI += vI_tale; + v_float32x4 vI_tale = v_mul(vI_ps, vtale_0); + vsumI = v_add(vsumI, vI_tale); // sumW - vsumW += vtale_0; + vsumW = v_add(vsumW, vtale_0); // sumDI - vsumDI += vI_ps * vI_tale; + vsumDI = v_add(vsumDI, v_mul(vI_ps, vI_tale)); v01 = v_reinterpret_as_s16(v_interleave_pairs(v_reinterpret_as_s32(v_interleave_pairs(vIxy_1)))); v_expand(v01, t1, t0); @@ -890,29 +890,29 @@ class TrackerInvoker : public cv::ParallelLoopBody fx = v_cvt_f32(t1); // A11 - A22 - fxtale = fx * vtale_1; - fytale = fy * vtale_1; + fxtale = v_mul(fx, vtale_1); + fytale = v_mul(fy, vtale_1); vAyy = v_muladd(fy, fytale, vAyy); vAxy = v_muladd(fx, fytale, vAxy); vAxx = v_muladd(fx, fxtale, vAxx); // sumIx und sumIy - vsumIx += fxtale; - vsumIy += fytale; + vsumIx = v_add(vsumIx, fxtale); + vsumIy = v_add(vsumIy, fytale); - vsumW1 += vI_ps * fxtale; - vsumW2 += vI_ps * fytale; + vsumW1 = v_add(vsumW1, v_mul(vI_ps, fxtale)); + vsumW2 = v_add(vsumW2, v_mul(vI_ps, fytale)); // sumI - vI_tale = vI_ps * vtale_1; - vsumI += vI_tale; + vI_tale = v_mul(vI_ps, vtale_1); + vsumI = v_add(vsumI, vI_tale); // sumW - vsumW += vtale_1; + vsumW = v_add(vsumW, vtale_1); // sumDI - vsumDI += vI_ps * vI_tale; + vsumDI = v_add(vsumDI, v_mul(vI_ps, vI_tale)); } } #else @@ -1017,7 +1017,7 @@ class TrackerInvoker : public cv::ParallelLoopBody } #if CV_SIMD128 float CV_DECL_ALIGNED(16) bbuf[4]; - v_store_aligned(bbuf, vqb0 + vqb1); + v_store_aligned(bbuf, v_add(vqb0, vqb1)); b1 = bbuf[0] + bbuf[2]; b2 = bbuf[1] + bbuf[3]; b3 = v_reduce_sum(vqb2); diff --git a/modules/optflow/src/rlof/rlof_invokerbase.hpp b/modules/optflow/src/rlof/rlof_invokerbase.hpp index c6f77f6d62c..2db4234ecd8 100644 --- a/modules/optflow/src/rlof/rlof_invokerbase.hpp +++ b/modules/optflow/src/rlof/rlof_invokerbase.hpp @@ -71,15 +71,15 @@ static inline void copyWinBuffers(int iw00, int iw01, int iw10, int iw11, for (; x <= winSize.width*cn; x += 8, dsrc += 8 * 2, dsrc1 += 8 * 2, dIptr += 8 * 2) { - v_int32x4 vmask0 = v_reinterpret_as_s32(v_load_expand_q(maskPtr + x)) * vmax_val_32; - v_int32x4 vmask1 = v_reinterpret_as_s32(v_load_expand_q(maskPtr + x + 4)) * vmax_val_32; + v_int32x4 vmask0 = v_mul(v_reinterpret_as_s32(v_load_expand_q(maskPtr + x)), vmax_val_32); + v_int32x4 vmask1 = v_mul(v_reinterpret_as_s32(v_load_expand_q(maskPtr + x + 4)), vmax_val_32); if (x + 4 > winSize.width) { - vmask0 = vmask0 & vmask_border_0; + vmask0 = v_and(vmask0, vmask_border_0); } if (x + 8 > winSize.width) { - vmask1 = vmask1 & vmask_border_1; + vmask1 = v_and(vmask1, vmask_border_1); } v_int32x4 t0, t1; @@ -91,10 +91,10 @@ static inline void copyWinBuffers(int iw00, int iw01, int iw10, int iw11, v_zip(v00, v01, t00, t01); v_zip(v10, v11, t10, t11); - t0 = v_dotprod(t00, vqw0, vdelta) + v_dotprod(t10, vqw1); - t1 = v_dotprod(t01, vqw0, vdelta) + v_dotprod(t11, vqw1); - t0 = t0 >> (W_BITS - 5) & vmask0; - t1 = t1 >> (W_BITS - 5) & vmask1; + t0 = v_add(v_dotprod(t00, vqw0, vdelta), v_dotprod(t10, vqw1)); + t1 = v_add(v_dotprod(t01, vqw0, vdelta), v_dotprod(t11, vqw1)); + t0 = v_and(v_shr(t0, W_BITS - 5), vmask0); + t1 = v_and(v_shr(t1, W_BITS - 5), vmask1); v_store(Iptr + x, v_pack(t0, t1)); v00 = v_reinterpret_as_s16(v_load(dsrc)); @@ -105,12 +105,12 @@ static inline void copyWinBuffers(int iw00, int iw01, int iw10, int iw11, v_zip(v00, v01, t00, t01); v_zip(v10, v11, t10, t11); - t0 = v_dotprod(t00, vqw0, vdelta_d) + v_dotprod(t10, vqw1); - t1 = v_dotprod(t01, vqw0, vdelta_d) + v_dotprod(t11, vqw1); - t0 = t0 >> W_BITS; - t1 = t1 >> W_BITS; + t0 = v_add(v_dotprod(t00, vqw0, vdelta_d), v_dotprod(t10, vqw1)); + t1 = v_add(v_dotprod(t01, vqw0, vdelta_d), v_dotprod(t11, vqw1)); + t0 = v_shr(t0, W_BITS); + t1 = v_shr(t1, W_BITS); v00 = v_pack(t0, t1); // Ix0 Iy0 Ix1 Iy1 ... - v00 = v00 & v_reinterpret_as_s16(vmask0); + v00 = v_and(v00, v_reinterpret_as_s16(vmask0)); v_store(dIptr, v00); v00 = v_reinterpret_as_s16(v_load(dsrc + 4 * 2)); @@ -121,12 +121,12 @@ static inline void copyWinBuffers(int iw00, int iw01, int iw10, int iw11, v_zip(v00, v01, t00, t01); v_zip(v10, v11, t10, t11); - t0 = v_dotprod(t00, vqw0, vdelta_d) + v_dotprod(t10, vqw1); - t1 = v_dotprod(t01, vqw0, vdelta_d) + v_dotprod(t11, vqw1); - t0 = t0 >> W_BITS; - t1 = t1 >> W_BITS; + t0 = v_add(v_dotprod(t00, vqw0, vdelta_d), v_dotprod(t10, vqw1)); + t1 = v_add(v_dotprod(t01, vqw0, vdelta_d), v_dotprod(t11, vqw1)); + t0 = v_shr(t0, W_BITS); + t1 = v_shr(t1, W_BITS); v00 = v_pack(t0, t1); // Ix0 Iy0 Ix1 Iy1 ... - v00 = v00 & v_reinterpret_as_s16(vmask1); + v00 = v_and(v00, v_reinterpret_as_s16(vmask1)); v_store(dIptr + 4 * 2, v00); } #else @@ -187,15 +187,15 @@ static inline void copyWinBuffers(int iw00, int iw01, int iw10, int iw11, #if CV_SIMD128 for (int x = 0; x <= winSize.width*cn; x += 8, dsrc += 8 * 2, dsrc1 += 8 * 2, dIptr += 8 * 2) { - v_int32x4 vmask0 = v_reinterpret_as_s32(v_load_expand_q(maskPtr + x)) * vmax_val_32; - v_int32x4 vmask1 = v_reinterpret_as_s32(v_load_expand_q(maskPtr + x + 4)) * vmax_val_32; + v_int32x4 vmask0 = v_mul(v_reinterpret_as_s32(v_load_expand_q(maskPtr + x)), vmax_val_32); + v_int32x4 vmask1 = v_mul(v_reinterpret_as_s32(v_load_expand_q(maskPtr + x + 4)), vmax_val_32); if (x + 4 > winSize.width) { - vmask0 = vmask0 & vmask_border0; + vmask0 = v_and(vmask0, vmask_border0); } if (x + 8 > winSize.width) { - vmask1 = vmask1 & vmask_border1; + vmask1 = v_and(vmask1, vmask_border1); } v_int32x4 t0, t1; @@ -207,12 +207,12 @@ static inline void copyWinBuffers(int iw00, int iw01, int iw10, int iw11, v_zip(v00, v01, t00, t01); v_zip(v10, v11, t10, t11); - t0 = v_dotprod(t00, vqw0, vdelta) + v_dotprod(t10, vqw1); - t1 = v_dotprod(t01, vqw0, vdelta) + v_dotprod(t11, vqw1); - t0 = t0 >> (W_BITS - 5); - t1 = t1 >> (W_BITS - 5); - t0 = t0 & vmask0; - t1 = t1 & vmask1; + t0 = v_add(v_dotprod(t00, vqw0, vdelta), v_dotprod(t10, vqw1)); + t1 = v_add(v_dotprod(t01, vqw0, vdelta), v_dotprod(t11, vqw1)); + t0 = v_shr(t0, W_BITS - 5); + t1 = v_shr(t1, W_BITS - 5); + t0 = v_and(t0, vmask0); + t1 = v_and(t1, vmask1); v_store(Iptr + x, v_pack(t0, t1)); v00 = v_reinterpret_as_s16(v_load(dsrc)); @@ -223,12 +223,12 @@ static inline void copyWinBuffers(int iw00, int iw01, int iw10, int iw11, v_zip(v00, v01, t00, t01); v_zip(v10, v11, t10, t11); - t0 = v_dotprod(t00, vqw0, vdelta_d) + v_dotprod(t10, vqw1); - t1 = v_dotprod(t01, vqw0, vdelta_d) + v_dotprod(t11, vqw1); - t0 = t0 >> W_BITS; - t1 = t1 >> W_BITS; + t0 = v_add(v_dotprod(t00, vqw0, vdelta_d), v_dotprod(t10, vqw1)); + t1 = v_add(v_dotprod(t01, vqw0, vdelta_d), v_dotprod(t11, vqw1)); + t0 = v_shr(t0, W_BITS); + t1 = v_shr(t1, W_BITS); v00 = v_pack(t0, t1); // Ix0 Iy0 Ix1 Iy1 ... - v00 = v00 & v_reinterpret_as_s16(vmask0); + v00 = v_and(v00, v_reinterpret_as_s16(vmask0)); v_store(dIptr, v00); v00 = v_reinterpret_as_s16(v_interleave_pairs(v_reinterpret_as_s32(v_interleave_pairs(v00)))); @@ -249,12 +249,12 @@ static inline void copyWinBuffers(int iw00, int iw01, int iw10, int iw11, v_zip(v00, v01, t00, t01); v_zip(v10, v11, t10, t11); - t0 = v_dotprod(t00, vqw0, vdelta_d) + v_dotprod(t10, vqw1); - t1 = v_dotprod(t01, vqw0, vdelta_d) + v_dotprod(t11, vqw1); - t0 = t0 >> W_BITS; - t1 = t1 >> W_BITS; + t0 = v_add(v_dotprod(t00, vqw0, vdelta_d), v_dotprod(t10, vqw1)); + t1 = v_add(v_dotprod(t01, vqw0, vdelta_d), v_dotprod(t11, vqw1)); + t0 = v_shr(t0, W_BITS); + t1 = v_shr(t1, W_BITS); v00 = v_pack(t0, t1); // Ix0 Iy0 Ix1 Iy1 ... - v00 = v00 & v_reinterpret_as_s16(vmask1); + v00 = v_and(v00, v_reinterpret_as_s16(vmask1)); v_store(dIptr + 4 * 2, v00); v00 = v_reinterpret_as_s16(v_interleave_pairs(v_reinterpret_as_s32(v_interleave_pairs(v00)))); diff --git a/modules/optflow/src/rlof/rlof_localflow.cpp b/modules/optflow/src/rlof/rlof_localflow.cpp index 8f3c728201a..3bc264f3e34 100644 --- a/modules/optflow/src/rlof/rlof_localflow.cpp +++ b/modules/optflow/src/rlof/rlof_localflow.cpp @@ -52,8 +52,8 @@ static void calcSharrDeriv(const cv::Mat& src, cv::Mat& dst) v_int16x8 s1 = v_reinterpret_as_s16(v_load_expand(srow1 + x)); v_int16x8 s2 = v_reinterpret_as_s16(v_load_expand(srow2 + x)); - v_int16x8 t1 = s2 - s0; - v_int16x8 t0 = v_mul_wrap(s0 + s2, c3) + v_mul_wrap(s1, c10); + v_int16x8 t1 = v_sub(s2, s0); + v_int16x8 t0 = v_add(v_mul_wrap(v_add(s0, s2), c3), v_mul_wrap(s1, c10)); v_store(trow0 + x, t0); v_store(trow1 + x, t1); @@ -90,8 +90,8 @@ static void calcSharrDeriv(const cv::Mat& src, cv::Mat& dst) v_int16x8 s3 = v_load(trow1 + x); v_int16x8 s4 = v_load(trow1 + x + cn); - v_int16x8 t0 = s1 - s0; - v_int16x8 t1 = v_mul_wrap(s2 + s4, c3) + v_mul_wrap(s3, c10); + v_int16x8 t0 = v_sub(s1, s0); + v_int16x8 t1 = v_add(v_mul_wrap(v_add(s2, s4), c3), v_mul_wrap(s3, c10)); v_store_interleave((drow + x * 2), t0, t1); } diff --git a/modules/rgbd/src/colored_tsdf.cpp b/modules/rgbd/src/colored_tsdf.cpp index 0247f66d010..7ce2c7428d0 100644 --- a/modules/rgbd/src/colored_tsdf.cpp +++ b/modules/rgbd/src/colored_tsdf.cpp @@ -194,21 +194,21 @@ inline float ColoredTSDFVolumeCPU::interpolateVoxel(const v_float32x4& p) const { // tx, ty, tz = floor(p) v_int32x4 ip = v_floor(p); - v_float32x4 t = p - v_cvt_f32(ip); - float tx = t.get0(); + v_float32x4 t = v_sub(p, v_cvt_f32(ip)); + float tx = v_get0(t); t = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(t))); - float ty = t.get0(); + float ty = v_get0(t); t = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(t))); - float tz = t.get0(); + float tz = v_get0(t); int xdim = volDims[0], ydim = volDims[1], zdim = volDims[2]; const RGBTsdfVoxel* volData = volume.ptr(); - int ix = ip.get0(); + int ix = v_get0(ip); ip = v_rotate_right<1>(ip); - int iy = ip.get0(); + int iy = v_get0(ip); ip = v_rotate_right<1>(ip); - int iz = ip.get0(); + int iz = v_get0(ip); int coordBase = ix * xdim + iy * ydim + iz * zdim; @@ -218,15 +218,15 @@ inline float ColoredTSDFVolumeCPU::interpolateVoxel(const v_float32x4& p) const v_float32x4 v0246 = tsdfToFloat_INTR(v_int32x4(vx[0], vx[2], vx[4], vx[6])); v_float32x4 v1357 = tsdfToFloat_INTR(v_int32x4(vx[1], vx[3], vx[5], vx[7])); - v_float32x4 vxx = v0246 + v_setall_f32(tz) * (v1357 - v0246); + v_float32x4 vxx = v_add(v0246, v_mul(v_setall_f32(tz), v_sub(v1357, v0246))); v_float32x4 v00_10 = vxx; v_float32x4 v01_11 = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(vxx))); - v_float32x4 v0_1 = v00_10 + v_setall_f32(ty) * (v01_11 - v00_10); - float v0 = v0_1.get0(); + v_float32x4 v0_1 = v_add(v00_10, v_mul(v_setall_f32(ty), v_sub(v01_11, v00_10))); + float v0 = v_get0(v0_1); v0_1 = v_reinterpret_as_f32(v_rotate_right<2>(v_reinterpret_as_u32(v0_1))); - float v1 = v0_1.get0(); + float v1 = v_get0(v0_1); return v0 + tx * (v1 - v0); } @@ -276,27 +276,27 @@ inline Point3f ColoredTSDFVolumeCPU::getNormalVoxel(const Point3f& _p) const inline v_float32x4 ColoredTSDFVolumeCPU::getNormalVoxel(const v_float32x4& p) const { - if (v_check_any(p < v_float32x4(1.f, 1.f, 1.f, 0.f)) || - v_check_any(p >= v_float32x4((float)(volResolution.x - 2), + if (v_check_any(v_lt(p, v_float32x4(1.f, 1.f, 1.f, 0.f))) || + v_check_any(v_ge(p, v_float32x4((float)(volResolution.x - 2), (float)(volResolution.y - 2), - (float)(volResolution.z - 2), 1.f)) + (float)(volResolution.z - 2), 1.f))) ) return nanv; v_int32x4 ip = v_floor(p); - v_float32x4 t = p - v_cvt_f32(ip); - float tx = t.get0(); + v_float32x4 t = v_sub(p, v_cvt_f32(ip)); + float tx = v_get0(t); t = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(t))); - float ty = t.get0(); + float ty = v_get0(t); t = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(t))); - float tz = t.get0(); + float tz = v_get0(t); const int xdim = volDims[0], ydim = volDims[1], zdim = volDims[2]; const RGBTsdfVoxel* volData = volume.ptr(); - int ix = ip.get0(); ip = v_rotate_right<1>(ip); - int iy = ip.get0(); ip = v_rotate_right<1>(ip); - int iz = ip.get0(); + int ix = v_get0(ip); ip = v_rotate_right<1>(ip); + int iy = v_get0(ip); ip = v_rotate_right<1>(ip); + int iz = v_get0(ip); int coordBase = ix * xdim + iy * ydim + iz * zdim; @@ -314,23 +314,23 @@ inline v_float32x4 ColoredTSDFVolumeCPU::getNormalVoxel(const v_float32x4& p) co v_float32x4 v0246(vx[0], vx[2], vx[4], vx[6]); v_float32x4 v1357(vx[1], vx[3], vx[5], vx[7]); - v_float32x4 vxx = v0246 + v_setall_f32(tz) * (v1357 - v0246); + v_float32x4 vxx = v_add(v0246, v_mul(v_setall_f32(tz), v_sub(v1357, v0246))); v_float32x4 v00_10 = vxx; v_float32x4 v01_11 = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(vxx))); - v_float32x4 v0_1 = v00_10 + v_setall_f32(ty) * (v01_11 - v00_10); - float v0 = v0_1.get0(); + v_float32x4 v0_1 = v_add(v00_10, v_mul(v_setall_f32(ty), v_sub(v01_11, v00_10))); + float v0 = v_get0(v0_1); v0_1 = v_reinterpret_as_f32(v_rotate_right<2>(v_reinterpret_as_u32(v0_1))); - float v1 = v0_1.get0(); + float v1 = v_get0(v0_1); nv = v0 + tx * (v1 - v0); } v_float32x4 n = v_load_aligned(an); - v_float32x4 Norm = v_sqrt(v_setall_f32(v_reduce_sum(n * n))); + v_float32x4 Norm = v_sqrt(v_setall_f32(v_reduce_sum(v_mul(n, n)))); - return Norm.get0() < 0.0001f ? nanv : n / Norm; + return v_get0(Norm) < 0.0001f ? nanv : v_div(n, Norm); } #else inline Point3f ColoredTSDFVolumeCPU::getNormalVoxel(const Point3f& p) const @@ -388,15 +388,15 @@ inline float ColoredTSDFVolumeCPU::interpolateColor(float tx, float ty, float tz v_float32x4 v0246, v1357; v_load_deinterleave(vx, v0246, v1357); - v_float32x4 vxx = v0246 + v_setall_f32(tz) * (v1357 - v0246); + v_float32x4 vxx = v_add(v0246, v_mul(v_setall_f32(tz), v_sub(v1357, v0246))); v_float32x4 v00_10 = vxx; v_float32x4 v01_11 = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(vxx))); - v_float32x4 v0_1 = v00_10 + v_setall_f32(ty) * (v01_11 - v00_10); - float v0 = v0_1.get0(); + v_float32x4 v0_1 = v_add(v00_10, v_mul(v_setall_f32(ty), v_sub(v01_11, v00_10))); + float v0 = v_get0(v0_1); v0_1 = v_reinterpret_as_f32(v_rotate_right<2>(v_reinterpret_as_u32(v0_1))); - float v1 = v0_1.get0(); + float v1 = v_get0(v0_1); return v0 + tx * (v1 - v0); } @@ -427,10 +427,10 @@ inline Point3f ColoredTSDFVolumeCPU::getColorVoxel(const Point3f& _p) const } inline v_float32x4 ColoredTSDFVolumeCPU::getColorVoxel(const v_float32x4& p) const { - if (v_check_any(p < v_float32x4(1.f, 1.f, 1.f, 0.f)) || - v_check_any(p >= v_float32x4((float)(volResolution.x - 2), + if (v_check_any(v_lt(p, v_float32x4(1.f, 1.f, 1.f, 0.f))) || + v_check_any(v_ge(p, v_float32x4((float)(volResolution.x - 2), (float)(volResolution.y - 2), - (float)(volResolution.z - 2), 1.f)) + (float)(volResolution.z - 2), 1.f))) ) return nanv; @@ -439,9 +439,9 @@ inline v_float32x4 ColoredTSDFVolumeCPU::getColorVoxel(const v_float32x4& p) con const int xdim = volDims[0], ydim = volDims[1], zdim = volDims[2]; const RGBTsdfVoxel* volData = volume.ptr(); - int ix = ip.get0(); ip = v_rotate_right<1>(ip); - int iy = ip.get0(); ip = v_rotate_right<1>(ip); - int iz = ip.get0(); + int ix = v_get0(ip); ip = v_rotate_right<1>(ip); + int iy = v_get0(ip); ip = v_rotate_right<1>(ip); + int iz = v_get0(ip); int coordBase = ix * xdim + iy * ydim + iz * zdim; float CV_DECL_ALIGNED(16) rgb[4]; @@ -456,12 +456,12 @@ inline v_float32x4 ColoredTSDFVolumeCPU::getColorVoxel(const v_float32x4& p) con } v_float32x4 vsi(voxelSizeInv, voxelSizeInv, voxelSizeInv, voxelSizeInv); - v_float32x4 ptVox = p * vsi; + v_float32x4 ptVox = v_mul(p, vsi); v_int32x4 iptVox = v_floor(ptVox); - v_float32x4 t = ptVox - v_cvt_f32(iptVox); - float tx = t.get0(); t = v_rotate_right<1>(t); - float ty = t.get0(); t = v_rotate_right<1>(t); - float tz = t.get0(); + v_float32x4 t = v_sub(ptVox, v_cvt_f32(iptVox)); + float tx = v_get0(t); t = v_rotate_right<1>(t); + float ty = v_get0(t); t = v_rotate_right<1>(t); + float tz = v_get0(t); rgb[0] = interpolateColor(tx, ty, tz, r); rgb[1] = interpolateColor(tx, ty, tz, g); rgb[2] = interpolateColor(tx, ty, tz, b); @@ -583,21 +583,21 @@ struct ColorRaycastInvoker : ParallelLoopBody // get direction through pixel in volume space: // 1. reproject (x, y) on projecting plane where z = 1.f - v_float32x4 planed = (v_float32x4((float)x, (float)y, 0.f, 0.f) - vcxy) * vfxy; + v_float32x4 planed = v_mul(v_sub(v_float32x4((float)x, (float)y, 0.F, 0.F), vcxy), vfxy); planed = v_combine_low(planed, v_float32x4(1.f, 0.f, 0.f, 0.f)); // 2. rotate to volume space planed = v_matmuladd(planed, camRot0, camRot1, camRot2, v_setzero_f32()); // 3. normalize - v_float32x4 invNorm = v_invsqrt(v_setall_f32(v_reduce_sum(planed * planed))); - v_float32x4 dir = planed * invNorm; + v_float32x4 invNorm = v_invsqrt(v_setall_f32(v_reduce_sum(v_mul(planed, planed)))); + v_float32x4 dir = v_mul(planed, invNorm); // compute intersection of ray with all six bbox planes - v_float32x4 rayinv = v_setall_f32(1.f) / dir; + v_float32x4 rayinv = v_div(v_setall_f32(1.F), dir); // div by zero should be eliminated by these products - v_float32x4 tbottom = rayinv * (boxDown - orig); - v_float32x4 ttop = rayinv * (boxUp - orig); + v_float32x4 tbottom = v_mul(rayinv, v_sub(boxDown, orig)); + v_float32x4 ttop = v_mul(rayinv, v_sub(boxUp, orig)); // re-order intersections to find smallest and largest on each axis v_float32x4 minAx = v_min(ttop, tbottom); @@ -618,14 +618,14 @@ struct ColorRaycastInvoker : ParallelLoopBody if (tmin < tmax) { // interpolation optimized a little - orig *= invVoxelSize; - dir *= invVoxelSize; + orig = v_mul(orig, invVoxelSize); + dir = v_mul(dir, invVoxelSize); int xdim = volume.volDims[0]; int ydim = volume.volDims[1]; int zdim = volume.volDims[2]; - v_float32x4 rayStep = dir * v_setall_f32(tstep); - v_float32x4 next = (orig + dir * v_setall_f32(tmin)); + v_float32x4 rayStep = v_mul(dir, v_setall_f32(this->tstep)); + v_float32x4 next = (v_add(orig, v_mul(dir, v_setall_f32(tmin)))); float f = volume.interpolateVoxel(next), fnext = f; //raymarch @@ -633,11 +633,11 @@ struct ColorRaycastInvoker : ParallelLoopBody int nSteps = cvFloor((tmax - tmin) / tstep); for (; steps < nSteps; steps++) { - next += rayStep; + next = v_add(next, rayStep); v_int32x4 ip = v_round(next); - int ix = ip.get0(); ip = v_rotate_right<1>(ip); - int iy = ip.get0(); ip = v_rotate_right<1>(ip); - int iz = ip.get0(); + int ix = v_get0(ip); ip = v_rotate_right<1>(ip); + int iy = v_get0(ip); ip = v_rotate_right<1>(ip); + int iz = v_get0(ip); int coord = ix * xdim + iy * ydim + iz * zdim; fnext = tsdfToFloat(volume.volume.at(coord).tsdf); @@ -657,7 +657,7 @@ struct ColorRaycastInvoker : ParallelLoopBody // linearly interpolate t between two f values if (f > 0.f && fnext < 0.f) { - v_float32x4 tp = next - rayStep; + v_float32x4 tp = v_sub(next, rayStep); float ft = volume.interpolateVoxel(tp); float ftdt = volume.interpolateVoxel(next); float ts = tmin + tstep * (steps - ft / (ftdt - ft)); @@ -665,7 +665,7 @@ struct ColorRaycastInvoker : ParallelLoopBody // avoid division by zero if (!cvIsNaN(ts) && !cvIsInf(ts)) { - v_float32x4 pv = (orig + dir * v_setall_f32(ts)); + v_float32x4 pv = (v_add(orig, v_mul(dir, v_setall_f32(ts)))); v_float32x4 nv = volume.getNormalVoxel(pv); v_float32x4 cv = volume.getColorVoxel(pv); @@ -675,9 +675,7 @@ struct ColorRaycastInvoker : ParallelLoopBody //convert pv and nv to camera space normal = v_matmuladd(nv, volRot0, volRot1, volRot2, v_setzero_f32()); // interpolation optimized a little - point = v_matmuladd(pv * v_float32x4(volume.voxelSize, - volume.voxelSize, - volume.voxelSize, 1.f), + point = v_matmuladd(v_mul(pv, v_float32x4(this->volume.voxelSize, this->volume.voxelSize, this->volume.voxelSize, 1.F)), volRot0, volRot1, volRot2, volTrans); } } diff --git a/modules/rgbd/src/fast_icp.cpp b/modules/rgbd/src/fast_icp.cpp index 07eb84d19fd..5f3ab3f0a19 100644 --- a/modules/rgbd/src/fast_icp.cpp +++ b/modules/rgbd/src/fast_icp.cpp @@ -138,7 +138,7 @@ bool ICPImpl::estimateTransformT(cv::Affine3f& transform, #if USE_INTRINSICS static inline bool fastCheck(const v_float32x4& p0, const v_float32x4& p1) { - float check = (p0.get0() + p1.get0()); + float check = (v_get0(p0) + v_get0(p1)); return !cvIsNaN(check); } @@ -160,7 +160,7 @@ static inline v_float32x4 crossProduct(const v_float32x4& a, const v_float32x4& v_float32x4 ayzx, azxy, byzx, bzxy; getCrossPerm(a, ayzx, azxy); getCrossPerm(b, byzx, bzxy); - return ayzx*bzxy - azxy*byzx; + return v_sub(v_mul(ayzx, bzxy), v_mul(azxy, byzx)); } #else static inline bool fastCheck(const Point3f& p) @@ -235,11 +235,11 @@ struct GetAbInvoker : ParallelLoopBody //find correspondence by projecting the point v_float32x4 oldCoords; - float pz = (v_reinterpret_as_f32(v_rotate_right<2>(v_reinterpret_as_u32(newP))).get0()); + float pz = v_get0(v_reinterpret_as_f32(v_rotate_right<2>(v_reinterpret_as_u32(newP)))); // x, y, 0, 0 - oldCoords = v_muladd(newP/v_setall_f32(pz), vfxy, vcxy); + oldCoords = v_muladd(v_div(newP, v_setall_f32(pz)), vfxy, vcxy); - if(!v_check_all((oldCoords >= v_setzero_f32()) & (oldCoords < vframe))) + if(!v_check_all(v_and(v_ge(oldCoords, v_setzero_f32()), v_lt(oldCoords, vframe)))) continue; // bilinearly interpolate oldPts and oldNrm under oldCoords point @@ -247,12 +247,12 @@ struct GetAbInvoker : ParallelLoopBody v_float32x4 oldN; { v_int32x4 ixy = v_floor(oldCoords); - v_float32x4 txy = oldCoords - v_cvt_f32(ixy); - int xi = ixy.get0(); - int yi = v_rotate_right<1>(ixy).get0(); - v_float32x4 tx = v_setall_f32(txy.get0()); + v_float32x4 txy = v_sub(oldCoords, v_cvt_f32(ixy)); + int xi = v_get0(ixy); + int yi = v_get0(v_rotate_right<1>(ixy)); + v_float32x4 tx = v_setall_f32(v_get0(txy)); txy = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(txy))); - v_float32x4 ty = v_setall_f32(txy.get0()); + v_float32x4 ty = v_setall_f32(v_get0(txy)); const float* prow0 = (const float*)oldPts[yi+0]; const float* prow1 = (const float*)oldPts[yi+1]; @@ -275,23 +275,23 @@ struct GetAbInvoker : ParallelLoopBody // NaN check is done later - v_float32x4 p0 = p00 + tx*(p01 - p00); - v_float32x4 p1 = p10 + tx*(p11 - p10); - oldP = p0 + ty*(p1 - p0); + v_float32x4 p0 = v_add(p00, v_mul(tx, v_sub(p01, p00))); + v_float32x4 p1 = v_add(p10, v_mul(tx, v_sub(p11, p10))); + oldP = v_add(p0, v_mul(ty, v_sub(p1, p0))); - v_float32x4 n0 = n00 + tx*(n01 - n00); - v_float32x4 n1 = n10 + tx*(n11 - n10); - oldN = n0 + ty*(n1 - n0); + v_float32x4 n0 = v_add(n00, v_mul(tx, v_sub(n01, n00))); + v_float32x4 n1 = v_add(n10, v_mul(tx, v_sub(n11, n10))); + oldN = v_add(n0, v_mul(ty, v_sub(n1, n0))); } bool oldPNcheck = fastCheck(oldP, oldN); //filter by distance - v_float32x4 diff = newP - oldP; - bool distCheck = !(v_reduce_sum(diff*diff) > sqThresh); + v_float32x4 diff = v_sub(newP, oldP); + bool distCheck = !(v_reduce_sum(v_mul(diff, diff)) > sqThresh); //filter by angle - bool angleCheck = !(abs(v_reduce_sum(newN*oldN)) < cosThresh); + bool angleCheck = !(abs(v_reduce_sum(v_mul(newN, oldN))) < cosThresh); if(!(oldPNcheck && distCheck && angleCheck)) continue; @@ -299,17 +299,17 @@ struct GetAbInvoker : ParallelLoopBody // build point-wise vector ab = [ A | b ] v_float32x4 VxNv = crossProduct(newP, oldN); Point3f VxN; - VxN.x = VxNv.get0(); - VxN.y = v_reinterpret_as_f32(v_extract<1>(v_reinterpret_as_u32(VxNv), v_setzero_u32())).get0(); - VxN.z = v_reinterpret_as_f32(v_extract<2>(v_reinterpret_as_u32(VxNv), v_setzero_u32())).get0(); + VxN.x = v_get0(VxNv); + VxN.y = v_get0(v_reinterpret_as_f32(v_extract<1>(v_reinterpret_as_u32(VxNv), v_setzero_u32()))); + VxN.z = v_get0(v_reinterpret_as_f32(v_extract<2>(v_reinterpret_as_u32(VxNv), v_setzero_u32()))); - float dotp = -v_reduce_sum(oldN*diff); + float dotp = -v_reduce_sum(v_mul(oldN, diff)); // build point-wise upper-triangle matrix [ab^T * ab] w/o last row // which is [A^T*A | A^T*b] // and gather sum - v_float32x4 vd = VxNv | v_float32x4(0, 0, 0, dotp); + v_float32x4 vd = v_or(VxNv, v_float32x4(0, 0, 0, dotp)); v_float32x4 n = oldN; v_float32x4 nyzx; { diff --git a/modules/rgbd/src/hash_tsdf.cpp b/modules/rgbd/src/hash_tsdf.cpp index 9cf05e55691..e47af731dba 100644 --- a/modules/rgbd/src/hash_tsdf.cpp +++ b/modules/rgbd/src/hash_tsdf.cpp @@ -425,15 +425,15 @@ inline float interpolate(float tx, float ty, float tz, float vx[8]) v_float32x4 v0246, v1357; v_load_deinterleave(vx, v0246, v1357); - v_float32x4 vxx = v0246 + v_setall_f32(tz) * (v1357 - v0246); + v_float32x4 vxx = v_add(v0246, v_mul(v_setall_f32(tz), v_sub(v1357, v0246))); v_float32x4 v00_10 = vxx; v_float32x4 v01_11 = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(vxx))); - v_float32x4 v0_1 = v00_10 + v_setall_f32(ty) * (v01_11 - v00_10); - float v0 = v0_1.get0(); + v_float32x4 v0_1 = v_add(v00_10, v_mul(v_setall_f32(ty), v_sub(v01_11, v00_10))); + float v0 = v_get0(v0_1); v0_1 = v_reinterpret_as_f32(v_rotate_right<2>(v_reinterpret_as_u32(v0_1))); - float v1 = v0_1.get0(); + float v1 = v_get0(v0_1); return v0 + tx * (v1 - v0); } @@ -598,9 +598,9 @@ Point3f HashTSDFVolumeCPU::getNormalVoxel(const Point3f &point) const v_float32x8 czp = v_lut(vals, idxzp); v_float32x8 czn = v_lut(vals, idxzn); - v_float32x8 vcxv = cxn - cxp; - v_float32x8 vcyv = cyn - cyp; - v_float32x8 vczv = czn - czp; + v_float32x8 vcxv = v_sub(cxn, cxp); + v_float32x8 vcyv = v_sub(cyn, cyp); + v_float32x8 vczv = v_sub(czn, czp); v_store(cxv, vcxv); v_store(cyv, vcyv); @@ -615,9 +615,9 @@ Point3f HashTSDFVolumeCPU::getNormalVoxel(const Point3f &point) const v_float32x4 czp0 = v_lut(vals, idxzp + 0); v_float32x4 czp1 = v_lut(vals, idxzp + 4); v_float32x4 czn0 = v_lut(vals, idxzn + 0); v_float32x4 czn1 = v_lut(vals, idxzn + 4); - v_float32x4 cxv0 = cxn0 - cxp0; v_float32x4 cxv1 = cxn1 - cxp1; - v_float32x4 cyv0 = cyn0 - cyp0; v_float32x4 cyv1 = cyn1 - cyp1; - v_float32x4 czv0 = czn0 - czp0; v_float32x4 czv1 = czn1 - czp1; + v_float32x4 cxv0 = v_sub(cxn0, cxp0); v_float32x4 cxv1 = v_sub(cxn1, cxp1); + v_float32x4 cyv0 = v_sub(cyn0, cyp0); v_float32x4 cyv1 = v_sub(cyn1, cyp1); + v_float32x4 czv0 = v_sub(czn0, czp0); v_float32x4 czv1 = v_sub(czn1, czp1); v_store(cxv + 0, cxv0); v_store(cxv + 4, cxv1); v_store(cyv + 0, cyv0); v_store(cyv + 4, cyv1); @@ -1523,9 +1523,9 @@ Point3f HashTSDFVolumeGPU::getNormalVoxel(const Point3f& point) const v_float32x8 czp = v_lut(vals, idxzp); v_float32x8 czn = v_lut(vals, idxzn); - v_float32x8 vcxv = cxn - cxp; - v_float32x8 vcyv = cyn - cyp; - v_float32x8 vczv = czn - czp; + v_float32x8 vcxv = v_sub(cxn, cxp); + v_float32x8 vcyv = v_sub(cyn, cyp); + v_float32x8 vczv = v_sub(czn, czp); v_store(cxv, vcxv); v_store(cyv, vcyv); @@ -1540,9 +1540,9 @@ Point3f HashTSDFVolumeGPU::getNormalVoxel(const Point3f& point) const v_float32x4 czp0 = v_lut(vals, idxzp + 0); v_float32x4 czp1 = v_lut(vals, idxzp + 4); v_float32x4 czn0 = v_lut(vals, idxzn + 0); v_float32x4 czn1 = v_lut(vals, idxzn + 4); - v_float32x4 cxv0 = cxn0 - cxp0; v_float32x4 cxv1 = cxn1 - cxp1; - v_float32x4 cyv0 = cyn0 - cyp0; v_float32x4 cyv1 = cyn1 - cyp1; - v_float32x4 czv0 = czn0 - czp0; v_float32x4 czv1 = czn1 - czp1; + v_float32x4 cxv0 = v_sub(cxn0, cxp0); v_float32x4 cxv1 = v_sub(cxn1, cxp1); + v_float32x4 cyv0 = v_sub(cyn0, cyp0); v_float32x4 cyv1 = v_sub(cyn1, cyp1); + v_float32x4 czv0 = v_sub(czn0, czp0); v_float32x4 czv1 = v_sub(czn1, czp1); v_store(cxv + 0, cxv0); v_store(cxv + 4, cxv1); v_store(cyv + 0, cyv0); v_store(cyv + 4, cyv1); diff --git a/modules/rgbd/src/tsdf.cpp b/modules/rgbd/src/tsdf.cpp index 7b76985eb43..73a39a65929 100644 --- a/modules/rgbd/src/tsdf.cpp +++ b/modules/rgbd/src/tsdf.cpp @@ -146,21 +146,21 @@ inline float TSDFVolumeCPU::interpolateVoxel(const v_float32x4& p) const { // tx, ty, tz = floor(p) v_int32x4 ip = v_floor(p); - v_float32x4 t = p - v_cvt_f32(ip); - float tx = t.get0(); + v_float32x4 t = v_sub(p, v_cvt_f32(ip)); + float tx = v_get0(t); t = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(t))); - float ty = t.get0(); + float ty = v_get0(t); t = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(t))); - float tz = t.get0(); + float tz = v_get0(t); int xdim = volDims[0], ydim = volDims[1], zdim = volDims[2]; const TsdfVoxel* volData = volume.ptr(); - int ix = ip.get0(); + int ix = v_get0(ip); ip = v_rotate_right<1>(ip); - int iy = ip.get0(); + int iy = v_get0(ip); ip = v_rotate_right<1>(ip); - int iz = ip.get0(); + int iz = v_get0(ip); int coordBase = ix*xdim + iy*ydim + iz*zdim; @@ -170,15 +170,15 @@ inline float TSDFVolumeCPU::interpolateVoxel(const v_float32x4& p) const v_float32x4 v0246 = tsdfToFloat_INTR(v_int32x4(vx[0], vx[2], vx[4], vx[6])); v_float32x4 v1357 = tsdfToFloat_INTR(v_int32x4(vx[1], vx[3], vx[5], vx[7])); - v_float32x4 vxx = v0246 + v_setall_f32(tz)*(v1357 - v0246); + v_float32x4 vxx = v_add(v0246, v_mul(v_setall_f32(tz), v_sub(v1357, v0246))); v_float32x4 v00_10 = vxx; v_float32x4 v01_11 = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(vxx))); - v_float32x4 v0_1 = v00_10 + v_setall_f32(ty)*(v01_11 - v00_10); - float v0 = v0_1.get0(); + v_float32x4 v0_1 = v_add(v00_10, v_mul(v_setall_f32(ty), v_sub(v01_11, v00_10))); + float v0 = v_get0(v0_1); v0_1 = v_reinterpret_as_f32(v_rotate_right<2>(v_reinterpret_as_u32(v0_1))); - float v1 = v0_1.get0(); + float v1 = v_get0(v0_1); return v0 + tx*(v1 - v0); } @@ -228,27 +228,27 @@ inline Point3f TSDFVolumeCPU::getNormalVoxel(const Point3f& _p) const inline v_float32x4 TSDFVolumeCPU::getNormalVoxel(const v_float32x4& p) const { - if(v_check_any (p < v_float32x4(1.f, 1.f, 1.f, 0.f)) || - v_check_any (p >= v_float32x4((float)(volResolution.x-2), + if(v_check_any (v_lt(p, v_float32x4(1.f, 1.f, 1.f, 0.f))) || + v_check_any (v_ge(p, v_float32x4((float)(volResolution.x-2), (float)(volResolution.y-2), - (float)(volResolution.z-2), 1.f)) + (float)(volResolution.z-2), 1.f))) ) return nanv; v_int32x4 ip = v_floor(p); - v_float32x4 t = p - v_cvt_f32(ip); - float tx = t.get0(); + v_float32x4 t = v_sub(p, v_cvt_f32(ip)); + float tx = v_get0(t); t = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(t))); - float ty = t.get0(); + float ty = v_get0(t); t = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(t))); - float tz = t.get0(); + float tz = v_get0(t); const int xdim = volDims[0], ydim = volDims[1], zdim = volDims[2]; const TsdfVoxel* volData = volume.ptr(); - int ix = ip.get0(); ip = v_rotate_right<1>(ip); - int iy = ip.get0(); ip = v_rotate_right<1>(ip); - int iz = ip.get0(); + int ix = v_get0(ip); ip = v_rotate_right<1>(ip); + int iy = v_get0(ip); ip = v_rotate_right<1>(ip); + int iz = v_get0(ip); int coordBase = ix*xdim + iy*ydim + iz*zdim; @@ -266,23 +266,23 @@ inline v_float32x4 TSDFVolumeCPU::getNormalVoxel(const v_float32x4& p) const v_float32x4 v0246 (vx[0], vx[2], vx[4], vx[6]); v_float32x4 v1357 (vx[1], vx[3], vx[5], vx[7]); - v_float32x4 vxx = v0246 + v_setall_f32(tz)*(v1357 - v0246); + v_float32x4 vxx = v_add(v0246, v_mul(v_setall_f32(tz), v_sub(v1357, v0246))); v_float32x4 v00_10 = vxx; v_float32x4 v01_11 = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(vxx))); - v_float32x4 v0_1 = v00_10 + v_setall_f32(ty)*(v01_11 - v00_10); - float v0 = v0_1.get0(); + v_float32x4 v0_1 = v_add(v00_10, v_mul(v_setall_f32(ty), v_sub(v01_11, v00_10))); + float v0 = v_get0(v0_1); v0_1 = v_reinterpret_as_f32(v_rotate_right<2>(v_reinterpret_as_u32(v0_1))); - float v1 = v0_1.get0(); + float v1 = v_get0(v0_1); nv = v0 + tx*(v1 - v0); } v_float32x4 n = v_load_aligned(an); - v_float32x4 Norm = v_sqrt(v_setall_f32(v_reduce_sum(n*n))); + v_float32x4 Norm = v_sqrt(v_setall_f32(v_reduce_sum(v_mul(n, n)))); - return Norm.get0() < 0.0001f ? nanv : n/Norm; + return v_get0(Norm) < 0.0001f ? nanv : v_div(n, Norm); } #else inline Point3f TSDFVolumeCPU::getNormalVoxel(const Point3f& p) const @@ -394,21 +394,21 @@ struct RaycastInvoker : ParallelLoopBody // get direction through pixel in volume space: // 1. reproject (x, y) on projecting plane where z = 1.f - v_float32x4 planed = (v_float32x4((float)x, (float)y, 0.f, 0.f) - vcxy)*vfxy; + v_float32x4 planed = v_mul(v_sub(v_float32x4((float)x, (float)y, 0.F, 0.F), vcxy), vfxy); planed = v_combine_low(planed, v_float32x4(1.f, 0.f, 0.f, 0.f)); // 2. rotate to volume space planed = v_matmuladd(planed, camRot0, camRot1, camRot2, v_setzero_f32()); // 3. normalize - v_float32x4 invNorm = v_invsqrt(v_setall_f32(v_reduce_sum(planed*planed))); - v_float32x4 dir = planed*invNorm; + v_float32x4 invNorm = v_invsqrt(v_setall_f32(v_reduce_sum(v_mul(planed, planed)))); + v_float32x4 dir = v_mul(planed, invNorm); // compute intersection of ray with all six bbox planes - v_float32x4 rayinv = v_setall_f32(1.f)/dir; + v_float32x4 rayinv = v_div(v_setall_f32(1.F), dir); // div by zero should be eliminated by these products - v_float32x4 tbottom = rayinv*(boxDown - orig); - v_float32x4 ttop = rayinv*(boxUp - orig); + v_float32x4 tbottom = v_mul(rayinv, v_sub(boxDown, orig)); + v_float32x4 ttop = v_mul(rayinv, v_sub(boxUp, orig)); // re-order intersections to find smallest and largest on each axis v_float32x4 minAx = v_min(ttop, tbottom); @@ -429,14 +429,14 @@ struct RaycastInvoker : ParallelLoopBody if(tmin < tmax) { // interpolation optimized a little - orig *= invVoxelSize; - dir *= invVoxelSize; + orig = v_mul(orig, invVoxelSize); + dir = v_mul(dir, invVoxelSize); int xdim = volume.volDims[0]; int ydim = volume.volDims[1]; int zdim = volume.volDims[2]; - v_float32x4 rayStep = dir * v_setall_f32(tstep); - v_float32x4 next = (orig + dir * v_setall_f32(tmin)); + v_float32x4 rayStep = v_mul(dir, v_setall_f32(this->tstep)); + v_float32x4 next = (v_add(orig, v_mul(dir, v_setall_f32(tmin)))); float f = volume.interpolateVoxel(next), fnext = f; //raymarch @@ -444,11 +444,11 @@ struct RaycastInvoker : ParallelLoopBody int nSteps = cvFloor((tmax - tmin)/tstep); for(; steps < nSteps; steps++) { - next += rayStep; + next = v_add(next, rayStep); v_int32x4 ip = v_round(next); - int ix = ip.get0(); ip = v_rotate_right<1>(ip); - int iy = ip.get0(); ip = v_rotate_right<1>(ip); - int iz = ip.get0(); + int ix = v_get0(ip); ip = v_rotate_right<1>(ip); + int iy = v_get0(ip); ip = v_rotate_right<1>(ip); + int iz = v_get0(ip); int coord = ix*xdim + iy*ydim + iz*zdim; fnext = tsdfToFloat(volume.volume.at(coord).tsdf); @@ -468,7 +468,7 @@ struct RaycastInvoker : ParallelLoopBody // linearly interpolate t between two f values if(f > 0.f && fnext < 0.f) { - v_float32x4 tp = next - rayStep; + v_float32x4 tp = v_sub(next, rayStep); float ft = volume.interpolateVoxel(tp); float ftdt = volume.interpolateVoxel(next); float ts = tmin + tstep*(steps - ft/(ftdt - ft)); @@ -476,7 +476,7 @@ struct RaycastInvoker : ParallelLoopBody // avoid division by zero if(!cvIsNaN(ts) && !cvIsInf(ts)) { - v_float32x4 pv = (orig + dir*v_setall_f32(ts)); + v_float32x4 pv = (v_add(orig, v_mul(dir, v_setall_f32(ts)))); v_float32x4 nv = volume.getNormalVoxel(pv); if(!isNaN(nv)) @@ -484,9 +484,7 @@ struct RaycastInvoker : ParallelLoopBody //convert pv and nv to camera space normal = v_matmuladd(nv, volRot0, volRot1, volRot2, v_setzero_f32()); // interpolation optimized a little - point = v_matmuladd(pv*v_float32x4(volume.voxelSize, - volume.voxelSize, - volume.voxelSize, 1.f), + point = v_matmuladd(v_mul(pv, v_float32x4(this->volume.voxelSize, this->volume.voxelSize, this->volume.voxelSize, 1.F)), volRot0, volRot1, volRot2, volTrans); } } diff --git a/modules/rgbd/src/tsdf_functions.cpp b/modules/rgbd/src/tsdf_functions.cpp index 3f8bc26f011..09ca986a1bf 100644 --- a/modules/rgbd/src/tsdf_functions.cpp +++ b/modules/rgbd/src/tsdf_functions.cpp @@ -235,35 +235,33 @@ void integrateVolumeUnit( // optimization of the following: //Point3f volPt = Point3f(x, y, z)*voxelSize; //Point3f camSpacePt = vol2cam * volPt; - camSpacePt += zStep; + camSpacePt = v_add(camSpacePt, zStep); - float zCamSpace = v_reinterpret_as_f32(v_rotate_right<2>(v_reinterpret_as_u32(camSpacePt))).get0(); + float zCamSpace = v_get0(v_reinterpret_as_f32(v_rotate_right<2>(v_reinterpret_as_u32(camSpacePt)))); if (zCamSpace <= 0.f) continue; - v_float32x4 camPixVec = camSpacePt / v_setall_f32(zCamSpace); + v_float32x4 camPixVec = v_div(camSpacePt, v_setall_f32(zCamSpace)); v_float32x4 projected = v_muladd(camPixVec, vfxy, vcxy); // leave only first 2 lanes - projected = v_reinterpret_as_f32(v_reinterpret_as_u32(projected) & - v_uint32x4(0xFFFFFFFF, 0xFFFFFFFF, 0, 0)); + projected = v_reinterpret_as_f32(v_and(v_reinterpret_as_u32(projected), v_uint32x4(4294967295U, 4294967295U, 0, 0))); depthType v; // bilinearly interpolate depth at projected { const v_float32x4& pt = projected; // check coords >= 0 and < imgSize - v_uint32x4 limits = v_reinterpret_as_u32(pt < v_setzero_f32()) | - v_reinterpret_as_u32(pt >= upLimits); - limits = limits | v_rotate_right<1>(limits); - if (limits.get0()) + v_uint32x4 limits = v_or(v_reinterpret_as_u32(v_lt(pt, v_setzero_f32())), v_reinterpret_as_u32(v_ge(pt, upLimits))); + limits = v_or(limits, v_rotate_right<1>(limits)); + if (v_get0(limits)) continue; // xi, yi = floor(pt) v_int32x4 ip = v_floor(pt); v_int32x4 ipshift = ip; - int xi = ipshift.get0(); + int xi = v_get0(ipshift); ipshift = v_rotate_right<1>(ipshift); - int yi = ipshift.get0(); + int yi = v_get0(ipshift); const depthType* row0 = depth[yi + 0]; const depthType* row1 = depth[yi + 1]; @@ -277,17 +275,17 @@ void integrateVolumeUnit( // assume correct depth is positive // don't fix missing data - if (v_check_all(vall > v_setzero_f32())) + if (v_check_all(v_gt(vall, v_setzero_f32()))) { - v_float32x4 t = pt - v_cvt_f32(ip); - float tx = t.get0(); + v_float32x4 t = v_sub(pt, v_cvt_f32(ip)); + float tx = v_get0(t); t = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(t))); - v_float32x4 ty = v_setall_f32(t.get0()); + v_float32x4 ty = v_setall_f32(v_get0(t)); // vx is y-interpolated between rows 0 and 1 - v_float32x4 vx = v001 + ty * (v101 - v001); - float v0 = vx.get0(); + v_float32x4 vx = v_add(v001, v_mul(ty, v_sub(v101, v001))); + float v0 = v_get0(vx); vx = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(vx))); - float v1 = vx.get0(); + float v1 = v_get0(vx); v = v0 + tx * (v1 - v0); } else @@ -295,8 +293,8 @@ void integrateVolumeUnit( } // norm(camPixVec) produces double which is too slow - int _u = (int)projected.get0(); - int _v = (int)v_rotate_right<1>(projected).get0(); + int _u = (int)v_get0(projected); + int _v = (int)v_get0(v_rotate_right<1>(projected)); if (!(_u >= 0 && _u < depth.cols && _v >= 0 && _v < depth.rows)) continue; float pixNorm = pixNorms.at(_v, _u); @@ -500,35 +498,33 @@ void integrateRGBVolumeUnit( // optimization of the following: //Point3f volPt = Point3f(x, y, z)*voxelSize; //Point3f camSpacePt = vol2cam * volPt; - camSpacePt += zStep; + camSpacePt = v_add(camSpacePt, zStep); - float zCamSpace = v_reinterpret_as_f32(v_rotate_right<2>(v_reinterpret_as_u32(camSpacePt))).get0(); + float zCamSpace = v_get0(v_reinterpret_as_f32(v_rotate_right<2>(v_reinterpret_as_u32(camSpacePt)))); if (zCamSpace <= 0.f) continue; - v_float32x4 camPixVec = camSpacePt / v_setall_f32(zCamSpace); + v_float32x4 camPixVec = v_div(camSpacePt, v_setall_f32(zCamSpace)); v_float32x4 projected = v_muladd(camPixVec, vfxy, vcxy); // leave only first 2 lanes - projected = v_reinterpret_as_f32(v_reinterpret_as_u32(projected) & - v_uint32x4(0xFFFFFFFF, 0xFFFFFFFF, 0, 0)); + projected = v_reinterpret_as_f32(v_and(v_reinterpret_as_u32(projected), v_uint32x4(4294967295U, 4294967295U, 0, 0))); depthType v; // bilinearly interpolate depth at projected { const v_float32x4& pt = projected; // check coords >= 0 and < imgSize - v_uint32x4 limits = v_reinterpret_as_u32(pt < v_setzero_f32()) | - v_reinterpret_as_u32(pt >= upLimits); - limits = limits | v_rotate_right<1>(limits); - if (limits.get0()) + v_uint32x4 limits = v_or(v_reinterpret_as_u32(v_lt(pt, v_setzero_f32())), v_reinterpret_as_u32(v_ge(pt, upLimits))); + limits = v_or(limits,v_rotate_right<1>(limits)); + if (v_get0(limits)) continue; // xi, yi = floor(pt) v_int32x4 ip = v_floor(pt); v_int32x4 ipshift = ip; - int xi = ipshift.get0(); + int xi = v_get0(ipshift); ipshift = v_rotate_right<1>(ipshift); - int yi = ipshift.get0(); + int yi = v_get0(ipshift); const depthType* row0 = depth[yi + 0]; const depthType* row1 = depth[yi + 1]; @@ -542,17 +538,17 @@ void integrateRGBVolumeUnit( // assume correct depth is positive // don't fix missing data - if (v_check_all(vall > v_setzero_f32())) + if (v_check_all(v_gt(vall, v_setzero_f32()))) { - v_float32x4 t = pt - v_cvt_f32(ip); - float tx = t.get0(); + v_float32x4 t = v_sub(pt, v_cvt_f32(ip)); + float tx = v_get0(t); t = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(t))); - v_float32x4 ty = v_setall_f32(t.get0()); + v_float32x4 ty = v_setall_f32(v_get0(t)); // vx is y-interpolated between rows 0 and 1 - v_float32x4 vx = v001 + ty * (v101 - v001); - float v0 = vx.get0(); + v_float32x4 vx = v_add(v001, v_mul(ty, v_sub(v101, v001))); + float v0 = v_get0(vx); vx = v_reinterpret_as_f32(v_rotate_right<1>(v_reinterpret_as_u32(vx))); - float v1 = vx.get0(); + float v1 = v_get0(vx); v = v0 + tx * (v1 - v0); } else @@ -561,14 +557,13 @@ void integrateRGBVolumeUnit( v_float32x4 projectedRGB = v_muladd(camPixVec, rgb_vfxy, rgb_vcxy); // leave only first 2 lanes - projectedRGB = v_reinterpret_as_f32(v_reinterpret_as_u32(projected) & - v_uint32x4(0xFFFFFFFF, 0xFFFFFFFF, 0, 0)); + projectedRGB = v_reinterpret_as_f32(v_and(v_reinterpret_as_u32(projected), v_uint32x4(0xFFFFFFFF, 0xFFFFFFFF, 0, 0))); // norm(camPixVec) produces double which is too slow - int _u = (int)projected.get0(); - int _v = (int)v_rotate_right<1>(projected).get0(); - int rgb_u = (int)projectedRGB.get0(); - int rgb_v = (int)v_rotate_right<1>(projectedRGB).get0(); + int _u = (int)v_get0(projected); + int _v = (int)v_get0(v_rotate_right<1>(projected)); + int rgb_u = (int)v_get0(projectedRGB); + int rgb_v = (int)v_get0(v_rotate_right<1>(projectedRGB)); if (!(_u >= 0 && _u < depth.cols && _v >= 0 && _v < depth.rows && rgb_v >= 0 && rgb_v < color.rows && rgb_u >= 0 && rgb_u < color.cols)) diff --git a/modules/rgbd/src/tsdf_functions.hpp b/modules/rgbd/src/tsdf_functions.hpp index c763f9275e6..6038ab60c05 100644 --- a/modules/rgbd/src/tsdf_functions.hpp +++ b/modules/rgbd/src/tsdf_functions.hpp @@ -20,7 +20,7 @@ namespace kinfu inline v_float32x4 tsdfToFloat_INTR(const v_int32x4& num) { v_float32x4 num128 = v_setall_f32(-1.f / 128.f); - return v_cvt_f32(num) * num128; + return v_mul(v_cvt_f32(num), num128); } #endif diff --git a/modules/rgbd/src/utils.hpp b/modules/rgbd/src/utils.hpp index 0b963675390..2bb69713d6a 100644 --- a/modules/rgbd/src/utils.hpp +++ b/modules/rgbd/src/utils.hpp @@ -68,7 +68,7 @@ inline bool isNaN(cv::Point3f p) #if USE_INTRINSICS static inline bool isNaN(const cv::v_float32x4& p) { - return cv::v_check_any(p != p); + return cv::v_check_any(v_ne(p, p)); } #endif diff --git a/modules/ximgproc/src/anisodiff.cpp b/modules/ximgproc/src/anisodiff.cpp index 996b4ac5b77..2b230a71242 100644 --- a/modules/ximgproc/src/anisodiff.cpp +++ b/modules/ximgproc/src/anisodiff.cpp @@ -74,8 +74,8 @@ inline v_uint8x16 v_finalize_pix_ch(const v_int16x8& c0, const v_int16x8& c1, v_expand_f32(c0, f0, f1); v_expand_f32(c1, f2, f3); - v_int16x8 d0 = v_pack(v_round(s0*alpha + f0), v_round(s1*alpha + f1)); - v_int16x8 d1 = v_pack(v_round(s2*alpha + f2), v_round(s3*alpha + f3)); + v_int16x8 d0 = v_pack(v_round(v_add(v_mul(s0, alpha), f0)), v_round(v_add(v_mul(s1, alpha), f1))); + v_int16x8 d1 = v_pack(v_round(v_add(v_mul(s2, alpha), f2)), v_round(v_add(v_mul(s3, alpha), f3))); return v_pack_u(d0, d1); } @@ -135,12 +135,12 @@ class ADBody : public ParallelLoopBody v_expand_s(p1, p10, p11); v_expand_s(p2, p20, p21); - v_int16x8 d00 = p00 - c00, d01 = p01 - c01; - v_int16x8 d10 = p10 - c10, d11 = p11 - c11; - v_int16x8 d20 = p20 - c20, d21 = p21 - c21; + v_int16x8 d00 = v_sub(p00, c00), d01 = v_sub(p01, c01); + v_int16x8 d10 = v_sub(p10, c10), d11 = v_sub(p11, c11); + v_int16x8 d20 = v_sub(p20, c20), d21 = v_sub(p21, c21); - v_uint16x8 n0 = v_abs(d00) + v_abs(d10) + v_abs(d20); - v_uint16x8 n1 = v_abs(d01) + v_abs(d11) + v_abs(d21); + v_uint16x8 n0 = v_add(v_add(v_abs(d00), v_abs(d10)), v_abs(d20)); + v_uint16x8 n1 = v_add(v_add(v_abs(d01), v_abs(d11)), v_abs(d21)); ushort CV_DECL_ALIGNED(16) nbuf[16]; v_store(nbuf, n0); @@ -153,13 +153,13 @@ class ADBody : public ParallelLoopBody v_expand_f32(d00, fd0, fd1); v_expand_f32(d01, fd2, fd3); - s00 += fd0*w0; s01 += fd1*w1; s02 += fd2*w2; s03 += fd3*w3; + s00 = v_add(s00, v_mul(fd0, w0)); s01 = v_add(s01, v_mul(fd1, w1)); s02 = v_add(s02, v_mul(fd2, w2)); s03 = v_add(s03, v_mul(fd3, w3)); v_expand_f32(d10, fd0, fd1); v_expand_f32(d11, fd2, fd3); - s10 += fd0*w0; s11 += fd1*w1; s12 += fd2*w2; s13 += fd3*w3; + s10 = v_add(s10, v_mul(fd0, w0)); s11 = v_add(s11, v_mul(fd1, w1)); s12 = v_add(s12, v_mul(fd2, w2)); s13 = v_add(s13, v_mul(fd3, w3)); v_expand_f32(d20, fd0, fd1); v_expand_f32(d21, fd2, fd3); - s20 += fd0*w0; s21 += fd1*w1; s22 += fd2*w2; s23 += fd3*w3; + s20 = v_add(s20, v_mul(fd0, w0)); s21 = v_add(s21, v_mul(fd1, w1)); s22 = v_add(s22, v_mul(fd2, w2)); s23 = v_add(s23, v_mul(fd3, w3)); } c0 = v_finalize_pix_ch(c00, c01, s00, s01, s02, s03, v_alpha); diff --git a/modules/ximgproc/src/fgs_filter.cpp b/modules/ximgproc/src/fgs_filter.cpp index 5e168da5dad..804e9f00a02 100644 --- a/modules/ximgproc/src/fgs_filter.cpp +++ b/modules/ximgproc/src/fgs_filter.cpp @@ -303,15 +303,15 @@ void FastGlobalSmootherFilterImpl::process_4row_block(Mat* cur,int i) v_float32x4 aux0,aux1,aux2,aux3; #define PROC4(Chor_in,cur_in,coef_prev_in,interD_prev_in,cur_prev_in,interD_out,cur_out,coef_cur_out)\ - coef_cur_out = lambda_reg*Chor_in;\ - aux0 = interD_prev_in*coef_prev_in;\ - aux1 = coef_cur_out+coef_prev_in;\ - aux1 = one_reg-aux1;\ - aux0 = aux1-aux0;\ - interD_out = coef_cur_out/aux0;\ - aux1 = cur_prev_in*coef_prev_in;\ - aux1 = cur_in - aux1;\ - cur_out = aux1/aux0; + coef_cur_out = v_mul(lambda_reg, Chor_in);\ + aux0 = v_mul(interD_prev_in, coef_prev_in);\ + aux1 = v_add(coef_cur_out, coef_prev_in);\ + aux1 = v_sub(one_reg, aux1);\ + aux0 = v_sub(aux1, aux0);\ + interD_out = v_div(coef_cur_out, aux0);\ + aux1 = v_mul(cur_prev_in, coef_prev_in);\ + aux1 = v_sub(cur_in, aux1);\ + cur_out = v_div(aux1, aux0); for(;j v_mul_wrap(v_thresh, v_max1)); - v_m2 = ~(v_mul_wrap(v_max2 - v_min2, v_255) > v_mul_wrap(v_thresh, v_max2)); + v_m1 = v_not(v_gt(v_mul_wrap(v_sub(v_max1, v_min1), v_255), v_mul_wrap(v_thresh, v_max1))); + v_m2 = v_not(v_gt(v_mul_wrap(v_sub(v_max2, v_min2), v_255), v_mul_wrap(v_thresh, v_max2))); // Apply masks - v_iB1 = (v_iB1 & v_m1) + (v_iB2 & v_m2); - v_iG1 = (v_iG1 & v_m1) + (v_iG2 & v_m2); - v_iR1 = (v_iR1 & v_m1) + (v_iR2 & v_m2); + v_iB1 = v_add(v_and(v_iB1, v_m1), v_and(v_iB2, v_m2)); + v_iG1 = v_add(v_and(v_iG1, v_m1), v_and(v_iG2, v_m2)); + v_iR1 = v_add(v_and(v_iR1, v_m1), v_and(v_iR2, v_m2)); // Split and add to the sums: v_expand(v_iB1, v_uint1, v_uint2); - v_SB += v_uint1 + v_uint2; + v_SB = v_add(v_SB, v_add(v_uint1, v_uint2)); v_expand(v_iG1, v_uint1, v_uint2); - v_SG += v_uint1 + v_uint2; + v_SG = v_add(v_SG, v_add(v_uint1, v_uint2)); v_expand(v_iR1, v_uint1, v_uint2); - v_SR += v_uint1 + v_uint2; + v_SR = v_add(v_SR, v_add(v_uint1, v_uint2)); } sumB = v_reduce_sum(v_SB); @@ -197,21 +197,21 @@ void calculateChannelSums(uint64 &sumB, uint64 &sumG, uint64 &sumR, ushort *src_ v_expand(v_max_val, v_max1, v_max2); // Calculate masks - v_m1 = ~((v_max1 - v_min1) * v_65535 > v_thresh * v_max1); - v_m2 = ~((v_max2 - v_min2) * v_65535 > v_thresh * v_max2); + v_m1 = v_not(v_gt(v_mul(v_sub(v_max1, v_min1), v_65535), v_mul(v_thresh, v_max1))); + v_m2 = v_not(v_gt(v_mul(v_sub(v_max2, v_min2), v_65535), v_mul(v_thresh, v_max2))); // Apply masks - v_iB1 = (v_iB1 & v_m1) + (v_iB2 & v_m2); - v_iG1 = (v_iG1 & v_m1) + (v_iG2 & v_m2); - v_iR1 = (v_iR1 & v_m1) + (v_iR2 & v_m2); + v_iB1 = v_add(v_and(v_iB1, v_m1), v_and(v_iB2, v_m2)); + v_iG1 = v_add(v_and(v_iG1, v_m1), v_and(v_iG2, v_m2)); + v_iR1 = v_add(v_and(v_iR1, v_m1), v_and(v_iR2, v_m2)); // Split and add to the sums: v_expand(v_iB1, v_u64_1, v_u64_2); - v_SB += v_u64_1 + v_u64_2; + v_SB = v_add(v_SB, v_add(v_u64_1, v_u64_2)); v_expand(v_iG1, v_u64_1, v_u64_2); - v_SG += v_u64_1 + v_u64_2; + v_SG = v_add(v_SG, v_add(v_u64_1, v_u64_2)); v_expand(v_iR1, v_u64_1, v_u64_2); - v_SR += v_u64_1 + v_u64_2; + v_SR = v_add(v_SR, v_add(v_u64_1, v_u64_2)); } // Perform final reduction @@ -282,12 +282,12 @@ void applyChannelGains(InputArray _src, OutputArray _dst, float gainB, float gai v_expand(v_inR, v_sR1, v_sR2); // Multiply by gains - v_sB1 = v_mul_wrap(v_sB1, v_gainB) >> 8; - v_sB2 = v_mul_wrap(v_sB2, v_gainB) >> 8; - v_sG1 = v_mul_wrap(v_sG1, v_gainG) >> 8; - v_sG2 = v_mul_wrap(v_sG2, v_gainG) >> 8; - v_sR1 = v_mul_wrap(v_sR1, v_gainR) >> 8; - v_sR2 = v_mul_wrap(v_sR2, v_gainR) >> 8; + v_sB1 = v_shr(v_mul_wrap(v_sB1, v_gainB), 8); + v_sB2 = v_shr(v_mul_wrap(v_sB2, v_gainB), 8); + v_sG1 = v_shr(v_mul_wrap(v_sG1, v_gainG), 8); + v_sG2 = v_shr(v_mul_wrap(v_sG2, v_gainG), 8); + v_sR1 = v_shr(v_mul_wrap(v_sR1, v_gainR), 8); + v_sR2 = v_shr(v_mul_wrap(v_sR2, v_gainR), 8); // Pack into vectors of v_uint8x16 v_store_interleave(&dst_data[i], v_pack(v_sB1, v_sB2), v_pack(v_sG1, v_sG2), v_pack(v_sR1, v_sR2)); @@ -325,12 +325,12 @@ void applyChannelGains(InputArray _src, OutputArray _dst, float gainB, float gai v_expand(v_inR, v_sR1, v_sR2); // Multiply by scaling factors - v_sB1 = (v_sB1 * v_gainB) >> 16; - v_sB2 = (v_sB2 * v_gainB) >> 16; - v_sG1 = (v_sG1 * v_gainG) >> 16; - v_sG2 = (v_sG2 * v_gainG) >> 16; - v_sR1 = (v_sR1 * v_gainR) >> 16; - v_sR2 = (v_sR2 * v_gainR) >> 16; + v_sB1 = v_shr(v_mul(v_sB1, v_gainB), 16); + v_sB2 = v_shr(v_mul(v_sB2, v_gainB), 16); + v_sG1 = v_shr(v_mul(v_sG1, v_gainG), 16); + v_sG2 = v_shr(v_mul(v_sG2, v_gainG), 16); + v_sR1 = v_shr(v_mul(v_sR1, v_gainR), 16); + v_sR2 = v_shr(v_mul(v_sR2, v_gainR), 16); // Pack into vectors of v_uint16x8 v_store_interleave(&dst_data[i], v_pack(v_sB1, v_sB2), v_pack(v_sG1, v_sG2), v_pack(v_sR1, v_sR2)); diff --git a/modules/xphoto/src/learning_based_color_balance.cpp b/modules/xphoto/src/learning_based_color_balance.cpp index bd408e6cb49..de1958dcc60 100644 --- a/modules/xphoto/src/learning_based_color_balance.cpp +++ b/modules/xphoto/src/learning_based_color_balance.cpp @@ -192,7 +192,7 @@ void LearningBasedWBImpl::preprocessing(Mat &src) v_load_deinterleave(src_ptr + 3 * i, v_inB, v_inG, v_inR); v_local_max = v_max(v_inB, v_max(v_inG, v_inR)); v_global_max = v_max(v_local_max, v_global_max); - v_mask = (v_local_max < v_thresh); + v_mask = (v_lt(v_local_max, v_thresh)); v_store(mask_ptr + i, v_mask); } uchar global_max[16]; @@ -225,7 +225,7 @@ void LearningBasedWBImpl::preprocessing(Mat &src) v_load_deinterleave(src_ptr + 3 * i, v_inB, v_inG, v_inR); v_local_max = v_max(v_inB, v_max(v_inG, v_inR)); v_global_max = v_max(v_local_max, v_global_max); - v_mask = (v_local_max < v_thresh); + v_mask = (v_lt(v_local_max, v_thresh)); v_pack_store(mask_ptr + i, v_mask); } ushort global_max[8]; @@ -270,9 +270,9 @@ void LearningBasedWBImpl::getAverageAndBrightestColorChromaticity(Vec2f &average v_load_deinterleave(src_ptr + 3 * i, v_inB, v_inG, v_inR); v_uint8x16 v_mask = v_load(mask_ptr + i); - v_inB &= v_mask; - v_inG &= v_mask; - v_inR &= v_mask; + v_inB = v_and(v_inB, v_mask); + v_inG = v_and(v_inG, v_mask); + v_inR = v_and(v_inR, v_mask); v_uint16x8 v_sR1, v_sR2, v_sG1, v_sG2, v_sB1, v_sB2; v_expand(v_inB, v_sB1, v_sB2); @@ -280,33 +280,33 @@ void LearningBasedWBImpl::getAverageAndBrightestColorChromaticity(Vec2f &average v_expand(v_inR, v_sR1, v_sR2); // update the brightest (R,G,B) tuple (process left half): - v_uint16x8 v_sum = v_sB1 + v_sG1 + v_sR1; - v_uint16x8 v_max_mask = (v_sum > v_max_sum); + v_uint16x8 v_sum = v_add(v_add(v_sB1, v_sG1), v_sR1); + v_uint16x8 v_max_mask = (v_gt(v_sum, v_max_sum)); v_max_sum = v_max(v_sum, v_max_sum); - v_brightestB = (v_sB1 & v_max_mask) + (v_brightestB & (~v_max_mask)); - v_brightestG = (v_sG1 & v_max_mask) + (v_brightestG & (~v_max_mask)); - v_brightestR = (v_sR1 & v_max_mask) + (v_brightestR & (~v_max_mask)); + v_brightestB = v_add(v_and(v_sB1, v_max_mask), v_and(v_brightestB, v_not(v_max_mask))); + v_brightestG = v_add(v_and(v_sG1, v_max_mask), v_and(v_brightestG, v_not(v_max_mask))); + v_brightestR = v_add(v_and(v_sR1, v_max_mask), v_and(v_brightestR, v_not(v_max_mask))); // update the brightest (R,G,B) tuple (process right half): - v_sum = v_sB2 + v_sG2 + v_sR2; - v_max_mask = (v_sum > v_max_sum); + v_sum = v_add(v_add(v_sB2, v_sG2), v_sR2); + v_max_mask = (v_gt(v_sum, v_max_sum)); v_max_sum = v_max(v_sum, v_max_sum); - v_brightestB = (v_sB2 & v_max_mask) + (v_brightestB & (~v_max_mask)); - v_brightestG = (v_sG2 & v_max_mask) + (v_brightestG & (~v_max_mask)); - v_brightestR = (v_sR2 & v_max_mask) + (v_brightestR & (~v_max_mask)); + v_brightestB = v_add(v_and(v_sB2, v_max_mask), v_and(v_brightestB, v_not(v_max_mask))); + v_brightestG = v_add(v_and(v_sG2, v_max_mask), v_and(v_brightestG, v_not(v_max_mask))); + v_brightestR = v_add(v_and(v_sR2, v_max_mask), v_and(v_brightestR, v_not(v_max_mask))); // update sums: - v_sB1 = v_sB1 + v_sB2; - v_sG1 = v_sG1 + v_sG2; - v_sR1 = v_sR1 + v_sR2; + v_sB1 = v_add(v_sB1, v_sB2); + v_sG1 = v_add(v_sG1, v_sG2); + v_sR1 = v_add(v_sR1, v_sR2); v_uint32x4 v_uint1, v_uint2; v_expand(v_sB1, v_uint1, v_uint2); - v_SB += v_uint1 + v_uint2; + v_SB = v_add(v_SB, v_add(v_uint1, v_uint2)); v_expand(v_sG1, v_uint1, v_uint2); - v_SG += v_uint1 + v_uint2; + v_SG = v_add(v_SG, v_add(v_uint1, v_uint2)); v_expand(v_sR1, v_uint1, v_uint2); - v_SR += v_uint1 + v_uint2; + v_SR = v_add(v_SR, v_add(v_uint1, v_uint2)); } sumB = v_reduce_sum(v_SB); sumG = v_reduce_sum(v_SG); @@ -361,11 +361,11 @@ void LearningBasedWBImpl::getAverageAndBrightestColorChromaticity(Vec2f &average v_uint16x8 v_inB, v_inG, v_inR; v_load_deinterleave(src_ptr + 3 * i, v_inB, v_inG, v_inR); v_uint16x8 v_mask = v_load_expand(mask_ptr + i); - v_mask = v_mask | ((v_mask & v_mask_lower) << 8); + v_mask = v_or(v_mask, v_shl<8>(v_and(v_mask, v_mask_lower))); - v_inB &= v_mask; - v_inG &= v_mask; - v_inR &= v_mask; + v_inB = v_and(v_inB, v_mask); + v_inG = v_and(v_inG, v_mask); + v_inR = v_and(v_inR, v_mask); v_uint32x4 v_iR1, v_iR2, v_iG1, v_iG2, v_iB1, v_iB2; v_expand(v_inB, v_iB1, v_iB2); @@ -373,32 +373,32 @@ void LearningBasedWBImpl::getAverageAndBrightestColorChromaticity(Vec2f &average v_expand(v_inR, v_iR1, v_iR2); // update the brightest (R,G,B) tuple (process left half): - v_uint32x4 v_sum = v_iB1 + v_iG1 + v_iR1; - v_uint32x4 v_max_mask = (v_sum > v_max_sum); + v_uint32x4 v_sum = v_add(v_add(v_iB1, v_iG1), v_iR1); + v_uint32x4 v_max_mask = (v_gt(v_sum, v_max_sum)); v_max_sum = v_max(v_sum, v_max_sum); - v_brightestB = (v_iB1 & v_max_mask) + (v_brightestB & (~v_max_mask)); - v_brightestG = (v_iG1 & v_max_mask) + (v_brightestG & (~v_max_mask)); - v_brightestR = (v_iR1 & v_max_mask) + (v_brightestR & (~v_max_mask)); + v_brightestB = v_add(v_and(v_iB1, v_max_mask), v_and(v_brightestB, v_not(v_max_mask))); + v_brightestG = v_add(v_and(v_iG1, v_max_mask), v_and(v_brightestG, v_not(v_max_mask))); + v_brightestR = v_add(v_and(v_iR1, v_max_mask), v_and(v_brightestR, v_not(v_max_mask))); // update the brightest (R,G,B) tuple (process right half): - v_sum = v_iB2 + v_iG2 + v_iR2; - v_max_mask = (v_sum > v_max_sum); + v_sum = v_add(v_add(v_iB2, v_iG2), v_iR2); + v_max_mask = (v_gt(v_sum, v_max_sum)); v_max_sum = v_max(v_sum, v_max_sum); - v_brightestB = (v_iB2 & v_max_mask) + (v_brightestB & (~v_max_mask)); - v_brightestG = (v_iG2 & v_max_mask) + (v_brightestG & (~v_max_mask)); - v_brightestR = (v_iR2 & v_max_mask) + (v_brightestR & (~v_max_mask)); + v_brightestB = v_add(v_and(v_iB2, v_max_mask), v_and(v_brightestB, v_not(v_max_mask))); + v_brightestG = v_add(v_and(v_iG2, v_max_mask), v_and(v_brightestG, v_not(v_max_mask))); + v_brightestR = v_add(v_and(v_iR2, v_max_mask), v_and(v_brightestR, v_not(v_max_mask))); // update sums: - v_iB1 = v_iB1 + v_iB2; - v_iG1 = v_iG1 + v_iG2; - v_iR1 = v_iR1 + v_iR2; + v_iB1 = v_add(v_iB1, v_iB2); + v_iG1 = v_add(v_iG1, v_iG2); + v_iR1 = v_add(v_iR1, v_iR2); v_uint64x2 v_uint64_1, v_uint64_2; v_expand(v_iB1, v_uint64_1, v_uint64_2); - v_SB += v_uint64_1 + v_uint64_2; + v_SB = v_add(v_SB, v_add(v_uint64_1, v_uint64_2)); v_expand(v_iG1, v_uint64_1, v_uint64_2); - v_SG += v_uint64_1 + v_uint64_2; + v_SG = v_add(v_SG, v_add(v_uint64_1, v_uint64_2)); v_expand(v_iR1, v_uint64_1, v_uint64_2); - v_SR += v_uint64_1 + v_uint64_2; + v_SR = v_add(v_SR, v_add(v_uint64_1, v_uint64_2)); } uint64 sum_arr[2]; v_store(sum_arr, v_SB); From 0bbfa6c3b21cf3c1872c6fa0152673e68820b0ff Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Tue, 17 Oct 2023 16:30:31 +0300 Subject: [PATCH 11/18] CI: fixed RISC-V workflow path --- .github/workflows/PR-4.x.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/PR-4.x.yaml b/.github/workflows/PR-4.x.yaml index f05e94bfa32..bd90f16ca28 100644 --- a/.github/workflows/PR-4.x.yaml +++ b/.github/workflows/PR-4.x.yaml @@ -28,4 +28,4 @@ jobs: uses: opencv/ci-gha-workflow/.github/workflows/OCV-Contrib-PR-4.x-macOS-x86_64.yaml@main Linux-RISC-V-Clang: - uses: opencv/ci-gha-workflow/.github/workflows/OCV-Contrib-PR-4.x-RISCV.yaml + uses: opencv/ci-gha-workflow/.github/workflows/OCV-Contrib-PR-4.x-RISCV.yaml@main From f40bc0cb4cc6b015dc9fde6a18846ade0a8e42cd Mon Sep 17 00:00:00 2001 From: cudawarped <12133430+cudawarped@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:30:21 +0300 Subject: [PATCH 12/18] cudacodec: VideoWriter add container output --- .../cudacodec/include/opencv2/cudacodec.hpp | 38 ++++----- modules/cudacodec/src/NvEncoder.cpp | 10 --- modules/cudacodec/src/NvEncoder.h | 11 +++ modules/cudacodec/src/video_writer.cpp | 82 +++++++++++++------ modules/cudacodec/test/test_video.cpp | 60 ++++++++++---- 5 files changed, 134 insertions(+), 67 deletions(-) diff --git a/modules/cudacodec/include/opencv2/cudacodec.hpp b/modules/cudacodec/include/opencv2/cudacodec.hpp index 42325c64613..d6421c2b8a4 100644 --- a/modules/cudacodec/include/opencv2/cudacodec.hpp +++ b/modules/cudacodec/include/opencv2/cudacodec.hpp @@ -184,18 +184,18 @@ struct CV_EXPORTS_W_SIMPLE EncoderParams public: CV_WRAP EncoderParams() : nvPreset(ENC_PRESET_P3), tuningInfo(ENC_TUNING_INFO_HIGH_QUALITY), encodingProfile(ENC_CODEC_PROFILE_AUTOSELECT), rateControlMode(ENC_PARAMS_RC_VBR), multiPassEncoding(ENC_MULTI_PASS_DISABLED), constQp({ 0,0,0 }), averageBitRate(0), maxBitRate(0), - targetQuality(30), gopLength(0) {}; - + targetQuality(30), gopLength(250), idrPeriod(250) {}; CV_PROP_RW EncodePreset nvPreset; CV_PROP_RW EncodeTuningInfo tuningInfo; CV_PROP_RW EncodeProfile encodingProfile; CV_PROP_RW EncodeParamsRcMode rateControlMode; CV_PROP_RW EncodeMultiPass multiPassEncoding; - CV_PROP_RW EncodeQp constQp; //!< QP's for ENC_PARAMS_RC_CONSTQP. - CV_PROP_RW int averageBitRate; //!< target bitrate for ENC_PARAMS_RC_VBR and ENC_PARAMS_RC_CBR. - CV_PROP_RW int maxBitRate; //!< upper bound on bitrate for ENC_PARAMS_RC_VBR and ENC_PARAMS_RC_CONSTQP. - CV_PROP_RW uint8_t targetQuality; //!< value 0 - 51 where video quality decreases as targetQuality increases, used with ENC_PARAMS_RC_VBR. - CV_PROP_RW int gopLength; + CV_PROP_RW EncodeQp constQp; //!< QP's for \ref ENC_PARAMS_RC_CONSTQP. + CV_PROP_RW int averageBitRate; //!< target bitrate for \ref ENC_PARAMS_RC_VBR and \ref ENC_PARAMS_RC_CBR. + CV_PROP_RW int maxBitRate; //!< upper bound on bitrate for \ref ENC_PARAMS_RC_VBR and \ref ENC_PARAMS_RC_CONSTQP. + CV_PROP_RW uint8_t targetQuality; //!< value 0 - 51 where video quality decreases as targetQuality increases, used with \ref ENC_PARAMS_RC_VBR. + CV_PROP_RW int gopLength; //!< the number of pictures in one GOP, ensuring \ref idrPeriod >= \ref gopLength. + CV_PROP_RW int idrPeriod; //!< IDR interval, ensuring \ref idrPeriod >= \ref gopLength. }; CV_EXPORTS bool operator==(const EncoderParams& lhs, const EncoderParams& rhs); @@ -209,7 +209,7 @@ class CV_EXPORTS_W EncoderCallback { @param vPacket The raw bitstream for one or more frames. */ - virtual void onEncoded(std::vector> vPacket) = 0; + virtual void onEncoded(const std::vector>& vPacket) = 0; /** @brief Callback function to that the encoding has finished. * */ @@ -218,14 +218,14 @@ class CV_EXPORTS_W EncoderCallback { virtual ~EncoderCallback() {} }; -/** @brief Video writer interface. +/** @brief Video writer interface, see createVideoWriter(). -Available when built with WITH_NVCUVENC=ON while Nvidia's Video Codec SDK is installed. +Available if Nvidia's Video Codec SDK is installed. -Encoding support is dependent on the GPU, refer to the Nvidia Video Codec SDK Video Encode and Decode GPU Support Matrix for details. +Only Codec::H264 and Codec::HEVC are supported with encoding support dependent on the GPU, refer to the Nvidia Video Codec SDK Video Encode and Decode GPU Support Matrix for details. @note - - An example on how to use the videoWriter class can be found at + - An example on how to use the VideoWriter class can be found at opencv_source_code/samples/gpu/video_writer.cpp */ class CV_EXPORTS_W VideoWriter @@ -253,9 +253,9 @@ class CV_EXPORTS_W VideoWriter /** @brief Creates video writer. -@param fileName Name of the output video file. Only raw h264 or hevc files are supported. +@param fileName Name of the output video file. @param frameSize Size of the input video frames. -@param codec Codec. +@param codec Supports Codec::H264 and Codec::HEVC. @param fps Framerate of the created video stream. @param colorFormat OpenCv color format of the frames to be encoded. @param encoderCallback Callbacks for video encoder. See cudacodec::EncoderCallback. Required for working with the encoded video stream. @@ -266,9 +266,9 @@ CV_EXPORTS_W Ptr createVideoWriter(const String& fileNam /** @brief Creates video writer. -@param fileName Name of the output video file. Only raw h264 or hevc files are supported. +@param fileName Name of the output video file. @param frameSize Size of the input video frames. -@param codec Codec. +@param codec Supports Codec::H264 and Codec::HEVC. @param fps Framerate of the created video stream. @param colorFormat OpenCv color format of the frames to be encoded. @param params Additional encoding parameters. @@ -361,14 +361,14 @@ enum class VideoReaderProps { #endif }; -/** @brief Video reader interface. +/** @brief Video reader interface, see createVideoReader(). -Available when built with WITH_NVCUVID=ON while Nvidia's Video Codec SDK is installed. +Available if Nvidia's Video Codec SDK is installed. Decoding support is dependent on the GPU, refer to the Nvidia Video Codec SDK Video Encode and Decode GPU Support Matrix for details. @note - - An example on how to use the videoReader class can be found at + - An example on how to use the VideoReader interface can be found at opencv_source_code/samples/gpu/video_reader.cpp */ class CV_EXPORTS_W VideoReader diff --git a/modules/cudacodec/src/NvEncoder.cpp b/modules/cudacodec/src/NvEncoder.cpp index 249f6f1c61e..aa9d2a67c17 100644 --- a/modules/cudacodec/src/NvEncoder.cpp +++ b/modules/cudacodec/src/NvEncoder.cpp @@ -7,16 +7,6 @@ #include "NvEncoder.h" namespace cv { namespace cudacodec { -#ifndef _WIN32 -#include -static inline bool operator==(const GUID& guid1, const GUID& guid2) { - return !memcmp(&guid1, &guid2, sizeof(GUID)); -} - -static inline bool operator!=(const GUID& guid1, const GUID& guid2) { - return !(guid1 == guid2); -} -#endif NvEncoder::NvEncoder(NV_ENC_DEVICE_TYPE eDeviceType, void* pDevice, uint32_t nWidth, uint32_t nHeight, NV_ENC_BUFFER_FORMAT eBufferFormat, uint32_t nExtraOutputDelay) : diff --git a/modules/cudacodec/src/NvEncoder.h b/modules/cudacodec/src/NvEncoder.h index dd13d2c1501..c5a53712e14 100644 --- a/modules/cudacodec/src/NvEncoder.h +++ b/modules/cudacodec/src/NvEncoder.h @@ -15,6 +15,17 @@ namespace cv { namespace cudacodec { +#ifndef _WIN32 +#include + static inline bool operator==(const GUID& guid1, const GUID& guid2) { + return !memcmp(&guid1, &guid2, sizeof(GUID)); + } + + static inline bool operator!=(const GUID& guid1, const GUID& guid2) { + return !(guid1 == guid2); + } +#endif + #define NVENC_THROW_ERROR( errorStr, errorCode ) \ do \ { \ diff --git a/modules/cudacodec/src/video_writer.cpp b/modules/cudacodec/src/video_writer.cpp index db3e2e36306..8b5c703f759 100644 --- a/modules/cudacodec/src/video_writer.cpp +++ b/modules/cudacodec/src/video_writer.cpp @@ -59,7 +59,6 @@ GUID CodecGuid(const Codec codec); void FrameRate(const double fps, uint32_t& frameRateNum, uint32_t& frameRateDen); GUID EncodingProfileGuid(const EncodeProfile encodingProfile); GUID EncodingPresetGuid(const EncodePreset nvPreset); -bool Equal(const GUID& g1, const GUID& g2); bool operator==(const EncoderParams& lhs, const EncoderParams& rhs) { @@ -68,12 +67,48 @@ bool operator==(const EncoderParams& lhs, const EncoderParams& rhs) rhs.averageBitRate, rhs.maxBitRate, rhs.targetQuality, rhs.gopLength); }; +class FFmpegVideoWriter : public EncoderCallback +{ +public: + FFmpegVideoWriter(const String& fileName, const Codec codec, const int fps, const Size sz, const int idrPeriod); + ~FFmpegVideoWriter(); + void onEncoded(const std::vector>& vPacket); + void onEncodingFinished(); +private: + cv::VideoWriter writer; +}; + +FFmpegVideoWriter::FFmpegVideoWriter(const String& fileName, const Codec codec, const int fps, const Size sz, const int idrPeriod) { + if (!videoio_registry::hasBackend(CAP_FFMPEG)) + CV_Error(Error::StsNotImplemented, "FFmpeg backend not found"); + const int fourcc = codec == Codec::H264 ? cv::VideoWriter::fourcc('a', 'v', 'c', '1') : cv::VideoWriter::fourcc('h', 'e', 'v', '1'); + writer.open(fileName, fourcc, fps, sz, { VideoWriterProperties::VIDEOWRITER_PROP_RAW_VIDEO, 1, VideoWriterProperties::VIDEOWRITER_PROP_KEY_INTERVAL, idrPeriod }); + if (!writer.isOpened()) + CV_Error(Error::StsUnsupportedFormat, "Unsupported video sink"); +} + +void FFmpegVideoWriter::onEncodingFinished() { + writer.release(); +} + +FFmpegVideoWriter::~FFmpegVideoWriter() { + onEncodingFinished(); +} + +void FFmpegVideoWriter::onEncoded(const std::vector>& vPacket) { + for (auto& packet : vPacket) { + Mat wrappedPacket(1, packet.size(), CV_8UC1, (void*)packet.data()); + writer.write(wrappedPacket); + } +} + + class RawVideoWriter : public EncoderCallback { public: - RawVideoWriter(String fileName); + RawVideoWriter(const String fileName); ~RawVideoWriter(); - void onEncoded(std::vector> vPacket); + void onEncoded(const std::vector>& vPacket); void onEncodingFinished(); private: std::ofstream fpOut; @@ -93,9 +128,9 @@ RawVideoWriter::~RawVideoWriter() { onEncodingFinished(); } -void RawVideoWriter::onEncoded(std::vector> vPacket) { +void RawVideoWriter::onEncoded(const std::vector>& vPacket) { for (auto& packet : vPacket) - fpOut.write(reinterpret_cast(packet.data()), packet.size()); + fpOut.write(reinterpret_cast(packet.data()), packet.size()); } class VideoWriterImpl : public VideoWriter @@ -172,12 +207,6 @@ VideoWriterImpl::VideoWriterImpl(const Ptr& encoderCallBack_, c Init(codec, fps, frameSz); } -VideoWriterImpl::VideoWriterImpl(const Ptr& encoderCallback, const Size frameSz, const Codec codec, const double fps, - const ColorFormat colorFormat, const Stream& stream) : - VideoWriterImpl(encoderCallback, frameSz, codec, fps, colorFormat, EncoderParams(), stream) -{ -} - void VideoWriterImpl::release() { pEnc->EndEncode(vPacket); encoderCallback->onEncoded(vPacket); @@ -271,12 +300,6 @@ GUID EncodingPresetGuid(const EncodePreset nvPreset) { CV_Error(Error::StsUnsupportedFormat, msg); } -bool Equal(const GUID& g1, const GUID& g2) { - if (std::tie(g1.Data1, g1.Data2, g1.Data3, g1.Data4) == std::tie(g2.Data1, g2.Data2, g2.Data3, g2.Data4)) - return true; - return false; -} - void VideoWriterImpl::InitializeEncoder(const GUID codec, const double fps) { NV_ENC_INITIALIZE_PARAMS initializeParams = {}; @@ -293,10 +316,10 @@ void VideoWriterImpl::InitializeEncoder(const GUID codec, const double fps) initializeParams.encodeConfig->rcParams.maxBitRate = encoderParams.maxBitRate; initializeParams.encodeConfig->rcParams.targetQuality = encoderParams.targetQuality; initializeParams.encodeConfig->gopLength = encoderParams.gopLength; - if (Equal(codec, NV_ENC_CODEC_H264_GUID)) - initializeParams.encodeConfig->encodeCodecConfig.h264Config.idrPeriod = encoderParams.gopLength; - else if (Equal(codec, NV_ENC_CODEC_HEVC_GUID)) - initializeParams.encodeConfig->encodeCodecConfig.hevcConfig.idrPeriod = encoderParams.gopLength; + if (codec == NV_ENC_CODEC_H264_GUID) + initializeParams.encodeConfig->encodeCodecConfig.h264Config.idrPeriod = encoderParams.idrPeriod; + else if (codec == NV_ENC_CODEC_HEVC_GUID) + initializeParams.encodeConfig->encodeCodecConfig.hevcConfig.idrPeriod = encoderParams.idrPeriod; pEnc->CreateEncoder(&initializeParams); } @@ -371,14 +394,25 @@ EncoderParams VideoWriterImpl::getEncoderParams() const { Ptr createVideoWriter(const String& fileName, const Size frameSize, const Codec codec, const double fps, const ColorFormat colorFormat, Ptr encoderCallback, const Stream& stream) { - encoderCallback = encoderCallback ? encoderCallback : new RawVideoWriter(fileName); - return makePtr(encoderCallback, frameSize, codec, fps, colorFormat, stream); + return createVideoWriter(fileName, frameSize, codec, fps, colorFormat, EncoderParams(), encoderCallback, stream); } Ptr createVideoWriter(const String& fileName, const Size frameSize, const Codec codec, const double fps, const ColorFormat colorFormat, const EncoderParams& params, Ptr encoderCallback, const Stream& stream) { - encoderCallback = encoderCallback ? encoderCallback : new RawVideoWriter(fileName); + CV_Assert(params.idrPeriod >= params.gopLength); + if (!encoderCallback) { + // required until PR for raw video encapsulation is merged and windows dll is updated +#ifndef WIN32 // remove #define and keep code once merged + try { + encoderCallback = new FFmpegVideoWriter(fileName, codec, fps, frameSize, params.idrPeriod); + } + catch (...) +#endif + { + encoderCallback = new RawVideoWriter(fileName); + } + } return makePtr(encoderCallback, frameSize, codec, fps, colorFormat, params, stream); } diff --git a/modules/cudacodec/test/test_video.cpp b/modules/cudacodec/test/test_video.cpp index ead5fa944ca..45365dab230 100644 --- a/modules/cudacodec/test/test_video.cpp +++ b/modules/cudacodec/test/test_video.cpp @@ -639,7 +639,13 @@ CUDA_TEST_P(TransCode, H264ToH265) constexpr cv::cudacodec::ColorFormat colorFormat = cv::cudacodec::ColorFormat::NV_NV12; constexpr double fps = 25; const cudacodec::Codec codec = cudacodec::Codec::HEVC; - const std::string ext = ".h265"; + // required until PR for raw video encapsulation is merged and windows dll is updated +#ifdef WIN32 + const std::string ext = ".hevc"; +#else + // use this after update + const std::string ext = ".mp4"; +#endif const std::string outputFile = cv::tempfile(ext.c_str()); constexpr int nFrames = 5; Size frameSz; @@ -716,7 +722,13 @@ CUDA_TEST_P(Write, Writer) const cudacodec::Codec codec = GET_PARAM(2); const double fps = GET_PARAM(3); const cv::cudacodec::ColorFormat colorFormat = GET_PARAM(4); + // required until PR for raw video encapsulation is merged and windows dll is updated +#ifdef WIN32 const std::string ext = codec == cudacodec::Codec::H264 ? ".h264" : ".hevc"; +#else + // use this after update + const std::string ext = ".mp4"; +#endif const std::string outputFile = cv::tempfile(ext.c_str()); constexpr int nFrames = 5; Size frameSz; @@ -750,7 +762,7 @@ CUDA_TEST_P(Write, Writer) const int width = static_cast(cap.get(CAP_PROP_FRAME_WIDTH)); const int height = static_cast(cap.get(CAP_PROP_FRAME_HEIGHT)); ASSERT_EQ(frameSz, Size(width, height)); - ASSERT_TRUE(abs(fps - cap.get(CAP_PROP_FPS)) < 0.5); + ASSERT_EQ(fps, cap.get(CAP_PROP_FPS)); Mat frame; for (int i = 0; i < nFrames; ++i) { cap >> frame; @@ -761,24 +773,22 @@ CUDA_TEST_P(Write, Writer) } #define DEVICE_SRC true, false -#define FPS 10, 29.7 +#define FPS 10, 29 #define CODEC cv::cudacodec::Codec::H264, cv::cudacodec::Codec::HEVC #define COLOR_FORMAT cv::cudacodec::ColorFormat::BGR, cv::cudacodec::ColorFormat::RGB, cv::cudacodec::ColorFormat::BGRA, \ cv::cudacodec::ColorFormat::RGBA, cv::cudacodec::ColorFormat::GRAY INSTANTIATE_TEST_CASE_P(CUDA_Codec, Write, testing::Combine(ALL_DEVICES, testing::Values(DEVICE_SRC), testing::Values(CODEC), testing::Values(FPS), testing::Values(COLOR_FORMAT))); - -struct EncoderParams : testing::TestWithParam +PARAM_TEST_CASE(EncoderParams, cv::cuda::DeviceInfo, int) { cv::cuda::DeviceInfo devInfo; cv::cudacodec::EncoderParams params; virtual void SetUp() { - devInfo = GetParam(); + devInfo = GET_PARAM(0); cv::cuda::setDevice(devInfo.deviceID()); // Fixed params for CBR test - params.nvPreset = cv::cudacodec::EncodePreset::ENC_PRESET_P7; params.tuningInfo = cv::cudacodec::EncodeTuningInfo::ENC_TUNING_INFO_HIGH_QUALITY; params.encodingProfile = cv::cudacodec::EncodeProfile::ENC_H264_PROFILE_MAIN; params.rateControlMode = cv::cudacodec::EncodeParamsRcMode::ENC_PARAMS_RC_CBR; @@ -787,19 +797,25 @@ struct EncoderParams : testing::TestWithParam params.maxBitRate = 0; params.targetQuality = 0; params.gopLength = 5; + params.idrPeriod = GET_PARAM(1); } }; - CUDA_TEST_P(EncoderParams, Writer) { const std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../highgui/video/big_buck_bunny.mp4"; constexpr double fps = 25.0; constexpr cudacodec::Codec codec = cudacodec::Codec::H264; + // required until PR for raw video encapsulation is merged and windows dll is updated +#ifdef WIN32 const std::string ext = ".h264"; +#else + // use this after update + const std::string ext = ".mp4"; +#endif const std::string outputFile = cv::tempfile(ext.c_str()); Size frameSz; - constexpr int nFrames = 5; + const int nFrames = max(params.gopLength, params.idrPeriod) + 1; { cv::VideoCapture reader(inputFile); ASSERT_TRUE(reader.isOpened()); @@ -829,20 +845,36 @@ CUDA_TEST_P(EncoderParams, Writer) const int height = static_cast(cap.get(CAP_PROP_FRAME_HEIGHT)); ASSERT_EQ(frameSz, Size(width, height)); ASSERT_EQ(fps, cap.get(CAP_PROP_FPS)); - const bool checkGop = videoio_registry::hasBackend(CAP_FFMPEG); - Mat frame; + const bool checkFrameType = videoio_registry::hasBackend(CAP_FFMPEG); + VideoCapture capRaw; + int idrPeriod = 0; + if (checkFrameType) { + capRaw.open(outputFile, CAP_FFMPEG, { CAP_PROP_FORMAT, -1 }); + ASSERT_TRUE(capRaw.isOpened()); + idrPeriod = params.idrPeriod == 0 ? params.gopLength : params.idrPeriod; + } + const double frameTypeIAsciiCode = 73.0; // see CAP_PROP_FRAME_TYPE + Mat frame, frameRaw; for (int i = 0; i < nFrames; ++i) { cap >> frame; ASSERT_FALSE(frame.empty()); - if (checkGop && (cap.get(CAP_PROP_FRAME_TYPE) == 73)) { - ASSERT_TRUE(i % params.gopLength == 0); + if (checkFrameType) { + capRaw >> frameRaw; + ASSERT_FALSE(frameRaw.empty()); + const bool intraFrameReference = cap.get(CAP_PROP_FRAME_TYPE) == frameTypeIAsciiCode; + const bool intraFrameActual = i % params.gopLength == 0; + ASSERT_EQ(intraFrameActual, intraFrameReference); + const bool keyFrameActual = capRaw.get(CAP_PROP_LRF_HAS_KEY_FRAME) == 1.0; + const bool keyFrameReference = i % idrPeriod == 0; + ASSERT_EQ(keyFrameActual, keyFrameReference); } } } ASSERT_EQ(0, remove(outputFile.c_str())); } -INSTANTIATE_TEST_CASE_P(CUDA_Codec, EncoderParams, ALL_DEVICES); +#define IDR_PERIOD testing::Values(5,10) +INSTANTIATE_TEST_CASE_P(CUDA_Codec, EncoderParams, testing::Combine(ALL_DEVICES, IDR_PERIOD)); #endif // HAVE_NVCUVENC From 51de5807e87bdbdaefd8a5c61dfa0bf293ecd2db Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 26 Oct 2023 13:25:50 +0300 Subject: [PATCH 13/18] Set of build fixes for ## 3580, 3574. --- modules/cudaarithm/test/test_event.cpp | 2 +- modules/datasets/src/tinyxml2/tinyxml2.h | 2 +- modules/xphoto/src/oilpainting.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/cudaarithm/test/test_event.cpp b/modules/cudaarithm/test/test_event.cpp index 375c51d0d35..ffe0f7b681e 100644 --- a/modules/cudaarithm/test/test_event.cpp +++ b/modules/cudaarithm/test/test_event.cpp @@ -91,7 +91,7 @@ CUDA_TEST_P(AsyncEvent, Timing) const double elTimeMs = Event::elapsedTime(startEvent, stopEvent); ASSERT_GT(elTimeMs, 0); } - catch (cv::Exception ex) { + catch (const cv::Exception& ex) { failed = true; } ASSERT_EQ(failed, shouldFail.at(i)); diff --git a/modules/datasets/src/tinyxml2/tinyxml2.h b/modules/datasets/src/tinyxml2/tinyxml2.h index 95ae3bcc057..89a16c65b75 100644 --- a/modules/datasets/src/tinyxml2/tinyxml2.h +++ b/modules/datasets/src/tinyxml2/tinyxml2.h @@ -212,7 +212,7 @@ template class DynArray { public: - DynArray< T, INIT >() { + DynArray() { _mem = _pool; _allocated = INIT; _size = 0; diff --git a/modules/xphoto/src/oilpainting.cpp b/modules/xphoto/src/oilpainting.cpp index 21e62414c32..daeffd386a7 100644 --- a/modules/xphoto/src/oilpainting.cpp +++ b/modules/xphoto/src/oilpainting.cpp @@ -58,7 +58,7 @@ class ParallelOilPainting : public ParallelLoopBody int dynRatio; public: - ParallelOilPainting(Mat& img, Mat &d, Mat &iLuminance, int r,int k) : + ParallelOilPainting(Mat& img, Mat &d, Mat &iLuminance, int r,int k) : imgSrc(img), dst(d), imgLuminance(iLuminance), From b2bb3d6eef661438955a97758c21df3d8f7ece41 Mon Sep 17 00:00:00 2001 From: razaq Date: Mon, 30 Oct 2023 17:24:30 +0100 Subject: [PATCH 14/18] add function to load font from buffer --- modules/freetype/include/opencv2/freetype.hpp | 13 ++++++++ modules/freetype/src/freetype.cpp | 32 ++++++++++++++++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/modules/freetype/include/opencv2/freetype.hpp b/modules/freetype/include/opencv2/freetype.hpp index e62d058a876..a1027c9f8a1 100644 --- a/modules/freetype/include/opencv2/freetype.hpp +++ b/modules/freetype/include/opencv2/freetype.hpp @@ -84,6 +84,19 @@ The function loadFontData loads font data. CV_WRAP virtual void loadFontData(String fontFileName, int idx) = 0; +/** @brief Load font data. + +The function loadFontData loads font data. +The data is not copied, the user needs to make sure the data lives at least as long as FreeType2. +After the FreeType2 object is destroyed, the buffer can be safely deallocated. + +@param pBuf pointer to buffer containing font data +@param bufSize size of buffer +@param idx face_index to select a font faces in a single file. +*/ + + CV_WRAP virtual void loadFontData(uchar* pBuf, size_t bufSize, int idx) = 0; + /** @brief Set Split Number from Bezier-curve to line The function setSplitNumber set the number of split points from bezier-curve to line. diff --git a/modules/freetype/src/freetype.cpp b/modules/freetype/src/freetype.cpp index b8e605e5104..78baf9a2dd4 100644 --- a/modules/freetype/src/freetype.cpp +++ b/modules/freetype/src/freetype.cpp @@ -67,6 +67,7 @@ class CV_EXPORTS_W FreeType2Impl CV_FINAL : public FreeType2 FreeType2Impl(); ~FreeType2Impl(); void loadFontData(String fontFileName, int idx) CV_OVERRIDE; + void loadFontData(uchar* pBuf, size_t bufSize, int idx) CV_OVERRIDE; void setSplitNumber( int num ) CV_OVERRIDE; void putText( InputOutputArray img, const String& text, Point org, @@ -181,16 +182,39 @@ FreeType2Impl::~FreeType2Impl() void FreeType2Impl::loadFontData(String fontFileName, int idx) { CV_Assert( idx >= 0 ); - if( mIsFaceAvailable == true ) + if ( mIsFaceAvailable == true ) { - hb_font_destroy (mHb_font); + hb_font_destroy(mHb_font); + CV_Assert(!FT_Done_Face(mFace)); + } + + mIsFaceAvailable = false; + CV_Assert( !FT_New_Face( mLibrary, fontFileName.c_str(), static_cast(idx), &mFace ) ); + + mHb_font = hb_ft_font_create(mFace, NULL); + if ( mHb_font == NULL ) + { + CV_Assert(!FT_Done_Face(mFace)); + return; + } + CV_Assert( mHb_font != NULL ); + mIsFaceAvailable = true; +} + +void FreeType2Impl::loadFontData(uchar* pBuf, size_t bufSize, int idx) +{ + CV_Assert( idx >= 0 ); + if ( mIsFaceAvailable == true ) + { + hb_font_destroy(mHb_font); CV_Assert(!FT_Done_Face(mFace)); } mIsFaceAvailable = false; - CV_Assert( !FT_New_Face( mLibrary, fontFileName.c_str(), static_cast(idx), &(mFace) ) ); + FT_Open_Args args{ FT_OPEN_MEMORY, (FT_Byte*)pBuf, static_cast(bufSize), nullptr, nullptr, nullptr, 0, nullptr }; + CV_Assert( !FT_Open_Face(mLibrary, &args, idx, &mFace) ); - mHb_font = hb_ft_font_create (mFace, NULL); + mHb_font = hb_ft_font_create(mFace, NULL); if ( mHb_font == NULL ) { CV_Assert(!FT_Done_Face(mFace)); From 9e71621db8cea169839620d8a04baab33d67e6a0 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 1 Nov 2023 14:19:24 +0300 Subject: [PATCH 15/18] Regression test for the new Freetype method. --- modules/freetype/test/test_basic.cpp | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/modules/freetype/test/test_basic.cpp b/modules/freetype/test/test_basic.cpp index 4c4e0c3d7ce..9dfc05795eb 100644 --- a/modules/freetype/test/test_basic.cpp +++ b/modules/freetype/test/test_basic.cpp @@ -55,6 +55,39 @@ TEST(Freetype_Basic, success ) EXPECT_NO_THROW( ft2->putText(dst, "Basic,success", Point( 0, 50), 50, col, -1, LINE_AA, true ) ); } +TEST(Freetype_Basic, in_memory_font ) +{ + const string root = cvtest::TS::ptr()->get_data_path(); + const string font_path = root + "freetype/mplus/Mplus1-Regular.ttf"; + + cv::Ptr ft2; + EXPECT_NO_THROW( ft2 = cv::freetype::createFreeType2() ); + EXPECT_NO_THROW( ft2->loadFontData( font_path, 0 ) ); + + Mat dst(600,600, CV_8UC3, Scalar::all(255) ); + Scalar col(128,64,255,192); + EXPECT_NO_THROW( ft2->putText(dst, "Basic,success", Point( 0, 50), 50, col, -1, LINE_AA, true ) ); + + FILE* fp = fopen(font_path.c_str(), "rb"); + ASSERT_TRUE(fp != NULL); + fseek(fp, 0, SEEK_END); + const size_t file_size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + std::vector font_buffer(file_size); + const size_t actual_read = fread(&font_buffer[0], 1, file_size, fp); + fclose(fp); + ASSERT_EQ(file_size, actual_read); + + cv::Ptr ft2_in_memory; + EXPECT_NO_THROW( ft2_in_memory = cv::freetype::createFreeType2() ); + EXPECT_NO_THROW( ft2_in_memory->loadFontData( &font_buffer[0], file_size, 0 ) ); + Mat dst_in_memory(600,600, CV_8UC3, Scalar::all(255) ); + EXPECT_NO_THROW( ft2_in_memory->putText(dst_in_memory, "Basic,success", Point( 0, 50), 50, col, -1, LINE_AA, true ) ); + + EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), dst, dst_in_memory); +} + /****************** * loadFontData() *****************/ From 9b32dd97e46f1d3e4953cb12550da1fb856ef17b Mon Sep 17 00:00:00 2001 From: Kumataro Date: Thu, 16 Nov 2023 20:43:47 +0900 Subject: [PATCH 16/18] fix for review --- modules/freetype/include/opencv2/freetype.hpp | 6 +-- modules/freetype/src/freetype.cpp | 49 ++++++++++++------- modules/freetype/test/test_basic.cpp | 33 ++++++++++++- 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/modules/freetype/include/opencv2/freetype.hpp b/modules/freetype/include/opencv2/freetype.hpp index a1027c9f8a1..90007badd1d 100644 --- a/modules/freetype/include/opencv2/freetype.hpp +++ b/modules/freetype/include/opencv2/freetype.hpp @@ -76,7 +76,7 @@ class CV_EXPORTS_W FreeType2 : public Algorithm public: /** @brief Load font data. -The function loadFontData loads font data. +The function loadFontData loads font data from file. @param fontFileName FontFile Name @param idx face_index to select a font faces in a single file. @@ -86,7 +86,7 @@ The function loadFontData loads font data. /** @brief Load font data. -The function loadFontData loads font data. +The function loadFontData loads font data from memory. The data is not copied, the user needs to make sure the data lives at least as long as FreeType2. After the FreeType2 object is destroyed, the buffer can be safely deallocated. @@ -95,7 +95,7 @@ After the FreeType2 object is destroyed, the buffer can be safely deallocated. @param idx face_index to select a font faces in a single file. */ - CV_WRAP virtual void loadFontData(uchar* pBuf, size_t bufSize, int idx) = 0; + CV_WRAP virtual void loadFontData(char* pBuf, size_t bufSize, int idx) = 0; /** @brief Set Split Number from Bezier-curve to line diff --git a/modules/freetype/src/freetype.cpp b/modules/freetype/src/freetype.cpp index 78baf9a2dd4..d8934e361a2 100644 --- a/modules/freetype/src/freetype.cpp +++ b/modules/freetype/src/freetype.cpp @@ -67,7 +67,7 @@ class CV_EXPORTS_W FreeType2Impl CV_FINAL : public FreeType2 FreeType2Impl(); ~FreeType2Impl(); void loadFontData(String fontFileName, int idx) CV_OVERRIDE; - void loadFontData(uchar* pBuf, size_t bufSize, int idx) CV_OVERRIDE; + void loadFontData(char* pBuf, size_t bufSize, int idx) CV_OVERRIDE; void setSplitNumber( int num ) CV_OVERRIDE; void putText( InputOutputArray img, const String& text, Point org, @@ -88,6 +88,8 @@ class CV_EXPORTS_W FreeType2Impl CV_FINAL : public FreeType2 int mCtoL; hb_font_t *mHb_font; + void loadFontData(FT_Open_Args &args, int idx); + void putTextBitmapMono( InputOutputArray img, const String& text, Point org, int fontHeight, Scalar color, @@ -181,27 +183,41 @@ FreeType2Impl::~FreeType2Impl() void FreeType2Impl::loadFontData(String fontFileName, int idx) { - CV_Assert( idx >= 0 ); - if ( mIsFaceAvailable == true ) + FT_Open_Args args { - hb_font_destroy(mHb_font); - CV_Assert(!FT_Done_Face(mFace)); - } + FT_OPEN_PATHNAME, + nullptr, // memory_base + 0, // memory_size + const_cast(fontFileName.c_str()), + nullptr, // stream + nullptr, // driver + 0, // num_params + nullptr // params + }; - mIsFaceAvailable = false; - CV_Assert( !FT_New_Face( mLibrary, fontFileName.c_str(), static_cast(idx), &mFace ) ); + this->loadFontData(args, idx); +} - mHb_font = hb_ft_font_create(mFace, NULL); - if ( mHb_font == NULL ) +void FreeType2Impl::loadFontData(char* pBuf, size_t bufSize, int idx) +{ + CV_Assert( pBuf != nullptr ); + + FT_Open_Args args { - CV_Assert(!FT_Done_Face(mFace)); - return; - } - CV_Assert( mHb_font != NULL ); - mIsFaceAvailable = true; + FT_OPEN_MEMORY, + reinterpret_cast(pBuf), + static_cast(bufSize), + nullptr, // pathname + nullptr, // stream + nullptr, // driver + 0, // num_params + nullptr // params + }; + + this->loadFontData(args, idx); } -void FreeType2Impl::loadFontData(uchar* pBuf, size_t bufSize, int idx) +void FreeType2Impl::loadFontData(FT_Open_Args &args, int idx) { CV_Assert( idx >= 0 ); if ( mIsFaceAvailable == true ) @@ -211,7 +227,6 @@ void FreeType2Impl::loadFontData(uchar* pBuf, size_t bufSize, int idx) } mIsFaceAvailable = false; - FT_Open_Args args{ FT_OPEN_MEMORY, (FT_Byte*)pBuf, static_cast(bufSize), nullptr, nullptr, nullptr, 0, nullptr }; CV_Assert( !FT_Open_Face(mLibrary, &args, idx, &mFace) ); mHb_font = hb_ft_font_create(mFace, NULL); diff --git a/modules/freetype/test/test_basic.cpp b/modules/freetype/test/test_basic.cpp index 9dfc05795eb..5a646db45f5 100644 --- a/modules/freetype/test/test_basic.cpp +++ b/modules/freetype/test/test_basic.cpp @@ -74,7 +74,7 @@ TEST(Freetype_Basic, in_memory_font ) const size_t file_size = ftell(fp); fseek(fp, 0, SEEK_SET); - std::vector font_buffer(file_size); + std::vector font_buffer(file_size); const size_t actual_read = fread(&font_buffer[0], 1, file_size, fp); fclose(fp); ASSERT_EQ(file_size, actual_read); @@ -138,6 +138,37 @@ TEST(Freetype_loadFontData, call_multiple) EXPECT_NO_THROW( ft2->putText(dst, "call_mutilple", Point( 0, 50), 50, col, -1, LINE_AA, true ) ); } +TEST(Freetype_loadFontDataMemory, nullptr ) +{ + cv::Ptr ft2; + EXPECT_NO_THROW( ft2 = cv::freetype::createFreeType2() ); + EXPECT_ANY_THROW( ft2->loadFontData( nullptr, 0, 0 ) ); +} + +TEST(Freetype_loadFontDataMemory, broken_data ) +{ + const string root = cvtest::TS::ptr()->get_data_path(); + const string font_path = root + "freetype/mplus/Mplus1-Regular.ttf"; + + FILE* fp = fopen(font_path.c_str(), "rb"); + ASSERT_TRUE(fp != NULL); + fseek(fp, 0, SEEK_END); + const size_t file_size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + std::vector font_buffer(file_size); + const size_t actual_read = fread(&font_buffer[0], 1, file_size, fp); + fclose(fp); + ASSERT_EQ(file_size, actual_read); + + cv::Ptr ft2_in_memory; + EXPECT_NO_THROW( ft2_in_memory = cv::freetype::createFreeType2() ); + + font_buffer[0] = ~font_buffer[0]; // font buffer was broken. + + EXPECT_ANY_THROW( ft2_in_memory->loadFontData( &font_buffer[0], file_size, 0 ) ); +} + typedef testing::TestWithParam idx_range; TEST_P(idx_range, failed ) From 7b9785171f7d0b149bfab97dc697f29fcefa4656 Mon Sep 17 00:00:00 2001 From: cudawarped <12133430+cudawarped@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:51:26 +0200 Subject: [PATCH 17/18] Merge pull request #3542 from cudawarped:cudacodec_videoreader_seek cudacodec::VideoReader: allow frame seek on initialization #3542 Allow seeking of video source on initialization of `cudacodec::VideoReader` when new variable `VideoReaderInitParams::iFirstFrame` != 0. Dependant on https://github.com/opencv/opencv/pull/24012 Fixes https://github.com/opencv/opencv_contrib/issues/3541. ### 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 - [x] There is a reference to the original bug report and related work - [x] 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 --- .../cudacodec/include/opencv2/cudacodec.hpp | 12 +++- modules/cudacodec/src/ffmpeg_video_source.cpp | 14 ++-- modules/cudacodec/src/ffmpeg_video_source.hpp | 5 +- modules/cudacodec/src/video_reader.cpp | 70 +++++++++++++------ modules/cudacodec/src/video_source.cpp | 4 ++ modules/cudacodec/src/video_source.hpp | 2 + modules/cudacodec/test/test_video.cpp | 59 +++++++++++----- 7 files changed, 120 insertions(+), 46 deletions(-) diff --git a/modules/cudacodec/include/opencv2/cudacodec.hpp b/modules/cudacodec/include/opencv2/cudacodec.hpp index d6421c2b8a4..163417108e7 100644 --- a/modules/cudacodec/include/opencv2/cudacodec.hpp +++ b/modules/cudacodec/include/opencv2/cudacodec.hpp @@ -544,6 +544,14 @@ class CV_EXPORTS_W RawVideoSource @return `true` unless the property is unset set or not supported. */ virtual bool get(const int propertyId, double& propertyVal) const = 0; + + /** @brief Retrieve the index of the first frame that will returned after construction. + + @return index of the index of the first frame that will returned after construction. + + @note To reduce the decoding overhead when initializing VideoReader to start its decoding from frame N, RawVideoSource should seek to the first valid key frame less than or equal to N and return that index here. + */ + virtual int getFirstFrameIdx() const = 0; }; /** @brief VideoReader initialization parameters @@ -561,9 +569,10 @@ but it cannot go below the number determined by NVDEC. @param targetRoi Region of interest (x/width should be multiples of 4 and y/height multiples of 2) within the output frame to copy and resize the decoded frame to, defaults to the full frame. @param enableHistogram Request output of decoded luma histogram \a hist from VideoReader::nextFrame(GpuMat& frame, GpuMat& hist, Stream& stream), if hardware supported. +@param firstFrameIdx Index of the first frame to seek to on initialization of the VideoReader. */ struct CV_EXPORTS_W_SIMPLE VideoReaderInitParams { - CV_WRAP VideoReaderInitParams() : udpSource(false), allowFrameDrop(false), minNumDecodeSurfaces(0), rawMode(0), enableHistogram(false){}; + CV_WRAP VideoReaderInitParams() : udpSource(false), allowFrameDrop(false), minNumDecodeSurfaces(0), rawMode(0), enableHistogram(false), firstFrameIdx(0){}; CV_PROP_RW bool udpSource; CV_PROP_RW bool allowFrameDrop; CV_PROP_RW int minNumDecodeSurfaces; @@ -572,6 +581,7 @@ struct CV_EXPORTS_W_SIMPLE VideoReaderInitParams { CV_PROP_RW cv::Rect srcRoi; CV_PROP_RW cv::Rect targetRoi; CV_PROP_RW bool enableHistogram; + CV_PROP_RW int firstFrameIdx; }; /** @brief Creates video reader. diff --git a/modules/cudacodec/src/ffmpeg_video_source.cpp b/modules/cudacodec/src/ffmpeg_video_source.cpp index 20a02f84b55..87b7ef149e2 100644 --- a/modules/cudacodec/src/ffmpeg_video_source.cpp +++ b/modules/cudacodec/src/ffmpeg_video_source.cpp @@ -169,19 +169,21 @@ bool ParamSetsExist(unsigned char* parameterSets, const int szParameterSets, uns return paramSetStartCodeLen != 0 && packetStartCodeLen != 0 && parameterSets[paramSetStartCodeLen] == data[packetStartCodeLen]; } -cv::cudacodec::detail::FFmpegVideoSource::FFmpegVideoSource(const String& fname, const std::vector& _videoCaptureParams) +cv::cudacodec::detail::FFmpegVideoSource::FFmpegVideoSource(const String& fname, const std::vector& _videoCaptureParams, const int iMaxStartFrame) : videoCaptureParams(_videoCaptureParams) { if (!videoio_registry::hasBackend(CAP_FFMPEG)) CV_Error(Error::StsNotImplemented, "FFmpeg backend not found"); - cap.open(fname, CAP_FFMPEG, videoCaptureParams); - if (!cap.isOpened()) + videoCaptureParams.push_back(CAP_PROP_FORMAT); + videoCaptureParams.push_back(-1); + if (!cap.open(fname, CAP_FFMPEG, videoCaptureParams)) CV_Error(Error::StsUnsupportedFormat, "Unsupported video source"); - - if (!cap.set(CAP_PROP_FORMAT, -1)) // turn off video decoder (extract stream) - CV_Error(Error::StsUnsupportedFormat, "Fetching of RAW video streams is not supported"); CV_Assert(cap.get(CAP_PROP_FORMAT) == -1); + if (iMaxStartFrame) { + CV_Assert(cap.set(CAP_PROP_POS_FRAMES, iMaxStartFrame)); + firstFrameIdx = static_cast(cap.get(CAP_PROP_POS_FRAMES)); + } const int codecExtradataIndex = static_cast(cap.get(CAP_PROP_CODEC_EXTRADATA_INDEX)); Mat tmpExtraData; diff --git a/modules/cudacodec/src/ffmpeg_video_source.hpp b/modules/cudacodec/src/ffmpeg_video_source.hpp index ce8582f6503..b2c25817a4c 100644 --- a/modules/cudacodec/src/ffmpeg_video_source.hpp +++ b/modules/cudacodec/src/ffmpeg_video_source.hpp @@ -51,7 +51,7 @@ namespace cv { namespace cudacodec { namespace detail { class FFmpegVideoSource : public RawVideoSource { public: - FFmpegVideoSource(const String& fname, const std::vector& params); + FFmpegVideoSource(const String& fname, const std::vector& params, const int iMaxStartFrame); ~FFmpegVideoSource(); bool getNextPacket(unsigned char** data, size_t* size) CV_OVERRIDE; @@ -66,12 +66,15 @@ class FFmpegVideoSource : public RawVideoSource bool get(const int propertyId, double& propertyVal) const; + int getFirstFrameIdx() const { return firstFrameIdx; } + private: FormatInfo format_; VideoCapture cap; Mat rawFrame, extraData, dataWithHeader; int iFrame = 0; std::vector videoCaptureParams; + int firstFrameIdx = 0; }; }}} diff --git a/modules/cudacodec/src/video_reader.cpp b/modules/cudacodec/src/video_reader.cpp index b6ef2ca5376..6d71e544fa0 100644 --- a/modules/cudacodec/src/video_reader.cpp +++ b/modules/cudacodec/src/video_reader.cpp @@ -112,7 +112,7 @@ namespace { public: explicit VideoReaderImpl(const Ptr& source, const int minNumDecodeSurfaces, const bool allowFrameDrop = false , const bool udpSource = false, - const Size targetSz = Size(), const Rect srcRoi = Rect(), const Rect targetRoi = Rect(), const bool enableHistogram = false); + const Size targetSz = Size(), const Rect srcRoi = Rect(), const Rect targetRoi = Rect(), const bool enableHistogram = false, const int firstFrameIdx = 0); ~VideoReaderImpl(); bool nextFrame(GpuMat& frame, Stream& stream) CV_OVERRIDE; @@ -135,6 +135,9 @@ namespace bool get(const int propertyId, double& propertyVal) const CV_OVERRIDE; private: + bool skipFrame(); + bool aquireFrameInfo(std::pair& frameInfo, Stream& stream = Stream::Null()); + void releaseFrameInfo(const std::pair& frameInfo); bool internalGrab(GpuMat & frame, GpuMat & histogram, Stream & stream); void waitForDecoderInit(); @@ -154,6 +157,7 @@ namespace static const int rawPacketsBaseIdx = 2; ColorFormat colorFormat = ColorFormat::BGRA; static const String errorMsg; + int iFrame = 0; }; const String VideoReaderImpl::errorMsg = "Parsing/Decoding video source failed, check GPU memory is available and GPU supports requested functionality."; @@ -173,7 +177,7 @@ namespace } VideoReaderImpl::VideoReaderImpl(const Ptr& source, const int minNumDecodeSurfaces, const bool allowFrameDrop, const bool udpSource, - const Size targetSz, const Rect srcRoi, const Rect targetRoi, const bool enableHistogram) : + const Size targetSz, const Rect srcRoi, const Rect targetRoi, const bool enableHistogram, const int firstFrameIdx) : videoSource_(source), lock_(0) { @@ -190,6 +194,8 @@ namespace videoSource_->setVideoParser(videoParser_); videoSource_->start(); waitForDecoderInit(); + for(iFrame = videoSource_->getFirstFrameIdx(); iFrame < firstFrameIdx; iFrame++) + CV_Assert(skipFrame()); videoSource_->updateFormat(videoDecoder_->format()); } @@ -209,10 +215,7 @@ namespace CUvideoctxlock m_lock; }; - bool VideoReaderImpl::internalGrab(GpuMat& frame, GpuMat& histogram, Stream& stream) { - if (videoParser_->hasError()) - CV_Error(Error::StsError, errorMsg); - cudacodec::FormatInfo fmt; + bool VideoReaderImpl::aquireFrameInfo(std::pair& frameInfo, Stream& stream) { if (frames_.empty()) { CUVIDPARSERDISPINFO displayInfo; @@ -234,8 +237,6 @@ namespace bool isProgressive = displayInfo.progressive_frame != 0; const int num_fields = isProgressive ? 1 : 2 + displayInfo.repeat_first_field; - fmt = videoDecoder_->format(); - videoSource_->updateFormat(fmt); for (int active_field = 0; active_field < num_fields; ++active_field) { @@ -243,25 +244,46 @@ namespace std::memset(&videoProcParams, 0, sizeof(CUVIDPROCPARAMS)); videoProcParams.progressive_frame = displayInfo.progressive_frame; - videoProcParams.second_field = active_field; - videoProcParams.top_field_first = displayInfo.top_field_first; - videoProcParams.unpaired_field = (num_fields == 1); + videoProcParams.second_field = active_field; + videoProcParams.top_field_first = displayInfo.top_field_first; + videoProcParams.unpaired_field = (num_fields == 1); videoProcParams.output_stream = StreamAccessor::getStream(stream); frames_.push_back(std::make_pair(displayInfo, videoProcParams)); } } + else { + for (auto& frame : frames_) + frame.second.output_stream = StreamAccessor::getStream(stream); + } if (frames_.empty()) return false; - std::pair frameInfo = frames_.front(); + frameInfo = frames_.front(); frames_.pop_front(); + return true; + } + + void VideoReaderImpl::releaseFrameInfo(const std::pair& frameInfo) { + // release the frame, so it can be re-used in decoder + if (frames_.empty()) + frameQueue_->releaseFrame(frameInfo.first); + } + + bool VideoReaderImpl::internalGrab(GpuMat& frame, GpuMat& histogram, Stream& stream) { + if (videoParser_->hasError()) + CV_Error(Error::StsError, errorMsg); + + std::pair frameInfo; + if (!aquireFrameInfo(frameInfo, stream)) + return false; { VideoCtxAutoLock autoLock(lock_); unsigned long long cuHistogramPtr = 0; + const cudacodec::FormatInfo fmt = videoDecoder_->format(); if (fmt.enableHistogram) frameInfo.second.histogram_dptr = &cuHistogramPtr; @@ -281,10 +303,16 @@ namespace videoDecoder_->unmapFrame(decodedFrame); } - // release the frame, so it can be re-used in decoder - if (frames_.empty()) - frameQueue_->releaseFrame(frameInfo.first); + releaseFrameInfo(frameInfo); + iFrame++; + return true; + } + bool VideoReaderImpl::skipFrame() { + std::pair frameInfo; + if (!aquireFrameInfo(frameInfo)) + return false; + releaseFrameInfo(frameInfo); return true; } @@ -399,6 +427,10 @@ namespace } bool VideoReaderImpl::get(const int propertyId, double& propertyVal) const { + if (propertyId == cv::VideoCaptureProperties::CAP_PROP_POS_FRAMES) { + propertyVal = static_cast(iFrame); + return true; + } return videoSource_->get(propertyId, propertyVal); } @@ -421,11 +453,10 @@ Ptr cv::cudacodec::createVideoReader(const String& filename, const CV_Assert(!filename.empty()); Ptr videoSource; - try { // prefer ffmpeg to cuvidGetSourceVideoFormat() which doesn't always return the corrct raw pixel format - Ptr source(new FFmpegVideoSource(filename, sourceParams)); + Ptr source(new FFmpegVideoSource(filename, sourceParams, params.firstFrameIdx)); videoSource.reset(new RawVideoSourceWrapper(source, params.rawMode)); } catch (...) @@ -433,16 +464,15 @@ Ptr cv::cudacodec::createVideoReader(const String& filename, const if (sourceParams.size()) throw; videoSource.reset(new CuvidVideoSource(filename)); } - return makePtr(videoSource, params.minNumDecodeSurfaces, params.allowFrameDrop, params.udpSource, params.targetSz, - params.srcRoi, params.targetRoi, params.enableHistogram); + params.srcRoi, params.targetRoi, params.enableHistogram, params.firstFrameIdx); } Ptr cv::cudacodec::createVideoReader(const Ptr& source, const VideoReaderInitParams params) { Ptr videoSource(new RawVideoSourceWrapper(source, params.rawMode)); return makePtr(videoSource, params.minNumDecodeSurfaces, params.allowFrameDrop, params.udpSource, params.targetSz, - params.srcRoi, params.targetRoi, params.enableHistogram); + params.srcRoi, params.targetRoi, params.enableHistogram, params.firstFrameIdx); } void cv::cudacodec::MapHist(const GpuMat& hist, Mat& histFull) { diff --git a/modules/cudacodec/src/video_source.cpp b/modules/cudacodec/src/video_source.cpp index a81b75e366d..169ffbb9bce 100644 --- a/modules/cudacodec/src/video_source.cpp +++ b/modules/cudacodec/src/video_source.cpp @@ -76,6 +76,10 @@ bool cv::cudacodec::detail::RawVideoSourceWrapper::get(const int propertyId, dou return source_->get(propertyId, propertyVal); } +int cv::cudacodec::detail::RawVideoSourceWrapper::getFirstFrameIdx() const { + return source_->getFirstFrameIdx(); +} + void cv::cudacodec::detail::RawVideoSourceWrapper::start() { stop_ = false; diff --git a/modules/cudacodec/src/video_source.hpp b/modules/cudacodec/src/video_source.hpp index 8c96a34f2d5..f7e4c0bd15b 100644 --- a/modules/cudacodec/src/video_source.hpp +++ b/modules/cudacodec/src/video_source.hpp @@ -58,6 +58,7 @@ class VideoSource virtual FormatInfo format() const = 0; virtual void updateFormat(const FormatInfo& videoFormat) = 0; virtual bool get(const int propertyId, double& propertyVal) const { return false; } + virtual int getFirstFrameIdx() const { return 0; } virtual void start() = 0; virtual void stop() = 0; virtual bool isStarted() const = 0; @@ -91,6 +92,7 @@ class RawVideoSourceWrapper : public VideoSource FormatInfo format() const CV_OVERRIDE; void updateFormat(const FormatInfo& videoFormat) CV_OVERRIDE; bool get(const int propertyId, double& propertyVal) const CV_OVERRIDE; + int getFirstFrameIdx() const CV_OVERRIDE; void start() CV_OVERRIDE; void stop() CV_OVERRIDE; bool isStarted() const CV_OVERRIDE; diff --git a/modules/cudacodec/test/test_video.cpp b/modules/cudacodec/test/test_video.cpp index 45365dab230..88df2fb1afb 100644 --- a/modules/cudacodec/test/test_video.cpp +++ b/modules/cudacodec/test/test_video.cpp @@ -113,6 +113,10 @@ struct CheckParams : SetDevice { }; +struct Seek : SetDevice +{ +}; + #if defined(HAVE_NVCUVID) ////////////////////////////////////////////////////// // VideoReader @@ -542,36 +546,22 @@ CUDA_TEST_P(CheckParams, Reader) ASSERT_TRUE(reader->get(cv::VideoCaptureProperties::CAP_PROP_OPEN_TIMEOUT_MSEC, msActual)); ASSERT_EQ(msActual, msReference); } - - { - std::vector exceptionsThrown = { false,true }; - std::vector capPropFormats = { -1,0 }; - for (int i = 0; i < capPropFormats.size(); i++) { - bool exceptionThrown = false; - try { - cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile, { - cv::VideoCaptureProperties::CAP_PROP_FORMAT, capPropFormats.at(i) }); - } - catch (cv::Exception &ex) { - if (ex.code == Error::StsUnsupportedFormat) - exceptionThrown = true; - } - ASSERT_EQ(exceptionThrown, exceptionsThrown.at(i)); - } - } } CUDA_TEST_P(CheckParams, CaptureProps) { std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../highgui/video/big_buck_bunny.mp4"; cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile); - double width, height, fps; + double width, height, fps, iFrame; ASSERT_TRUE(reader->get(cv::VideoCaptureProperties::CAP_PROP_FRAME_WIDTH, width)); ASSERT_EQ(672, width); ASSERT_TRUE(reader->get(cv::VideoCaptureProperties::CAP_PROP_FRAME_HEIGHT, height)); ASSERT_EQ(384, height); ASSERT_TRUE(reader->get(cv::VideoCaptureProperties::CAP_PROP_FPS, fps)); ASSERT_EQ(24, fps); + ASSERT_TRUE(reader->grab()); + ASSERT_TRUE(reader->get(cv::VideoCaptureProperties::CAP_PROP_POS_FRAMES, iFrame)); + ASSERT_EQ(iFrame, 1.); } CUDA_TEST_P(CheckDecodeSurfaces, Reader) @@ -619,6 +609,37 @@ CUDA_TEST_P(CheckInitParams, Reader) ASSERT_TRUE(reader->get(cv::cudacodec::VideoReaderProps::PROP_RAW_MODE, rawMode) && static_cast(rawMode) == params.rawMode); } +CUDA_TEST_P(Seek, Reader) +{ +#if defined(WIN32) + throw SkipTestException("Test disabled on Windows until the FFMpeg wrapper is updated to include PR24012."); +#endif + std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../highgui/video/big_buck_bunny.mp4"; + // seek to a non key frame + const int firstFrameIdx = 18; + + GpuMat frameGs; + { + cv::Ptr readerGs = cv::cudacodec::createVideoReader(inputFile); + ASSERT_TRUE(readerGs->set(cudacodec::ColorFormat::GRAY)); + for (int i = 0; i <= firstFrameIdx; i++) + ASSERT_TRUE(readerGs->nextFrame(frameGs)); + } + + cudacodec::VideoReaderInitParams params; + params.firstFrameIdx = firstFrameIdx; + cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile, {}, params); + double iFrame = 0.; + ASSERT_TRUE(reader->get(cv::VideoCaptureProperties::CAP_PROP_POS_FRAMES, iFrame)); + ASSERT_EQ(iFrame, static_cast(firstFrameIdx)); + ASSERT_TRUE(reader->set(cudacodec::ColorFormat::GRAY)); + GpuMat frame; + ASSERT_TRUE(reader->nextFrame(frame)); + ASSERT_EQ(cuda::norm(frameGs, frame, NORM_INF), 0.0); + ASSERT_TRUE(reader->get(cv::VideoCaptureProperties::CAP_PROP_POS_FRAMES, iFrame)); + ASSERT_EQ(iFrame, static_cast(firstFrameIdx+1)); +} + #endif // HAVE_NVCUVID #if defined(HAVE_NVCUVID) && defined(HAVE_NVCUVENC) @@ -958,5 +979,7 @@ INSTANTIATE_TEST_CASE_P(CUDA_Codec, CheckInitParams, testing::Combine( testing::Values("highgui/video/big_buck_bunny.mp4"), testing::Values(true,false), testing::Values(true,false), testing::Values(true,false))); +INSTANTIATE_TEST_CASE_P(CUDA_Codec, Seek, ALL_DEVICES); + #endif // HAVE_NVCUVID || HAVE_NVCUVENC }} // namespace From 3c5635eacfe6b97a8fd26cf94899aa977fceb16b Mon Sep 17 00:00:00 2001 From: hipudding Date: Tue, 21 Nov 2023 14:44:57 +0800 Subject: [PATCH 18/18] Add operators support for Ascend NPU (CANN backend) (#3552) CANN (Compute Architecture of Neural Networks), developped by Huawei, is a heterogeneous computing architecture for AI. Opencv DNN has already suppoted CANN backend [#22634](https://github.com/opencv/opencv/pull/22634). There are more and more users using [Ascend NPU](https://www.hiascend.com/) and programming with CANN, and the number is still growing rapidly. AI training and inference are inseparable from data preprocessing. When users use OpenCV to work with CANN backend, data preprocessing can only run on CPUs, resulting in inefficiency. The purpose of this commit is to enable OpenCV operators on CANN backend. The usage of CANN backend is consistent, Please refer to OpenCV DNN: [CANN backend manual] (https://gist.github.com/fengyuentau/083f7f339592545c1f1d2c1fde6a53dc#file-a_ocv_cann-md): 1. [Install dependencies] (https://gist.github.com/fengyuentau/083f7f339592545c1f1d2c1fde6a53dc#install-dependencies) 2. [Install CANN] (https://gist.github.com/fengyuentau/083f7f339592545c1f1d2c1fde6a53dc#install-cann) 3. [Compile OpenCV with CANN] (https://gist.github.com/fengyuentau/083f7f339592545c1f1d2c1fde6a53dc#build-opencv-with-cann) The CANN backend is used in a similar way to CUDA: | Object | CANN | CUDA | | --------- | ------------ | -------- | | Namespace | cv::cann | cv::cuda | | Matrix | AscendMat | GpuMat | | Stream | AscendStream | Stream | | Event | AscendEvent | Event | The current commit provides CANN backend operator support framework, In order to make code viewing easy, only a few basic interfaces are implemented, all of the following operators are tested and compared result with CPU backend. More operators will continue implement in new independent commits. Co-authored-by: CaoMengqing --- .github/workflows/PR-4.x.yaml | 4 + modules/cannops/CMakeLists.txt | 17 + modules/cannops/Dockerfile | 67 ++ modules/cannops/include/opencv2/cann.hpp | 328 ++++++++ modules/cannops/include/opencv2/cann.inl.hpp | 97 +++ modules/cannops/include/opencv2/cann_call.hpp | 157 ++++ .../include/opencv2/cann_interface.hpp | 516 ++++++++++++ .../cannops/include/opencv2/cann_private.hpp | 33 + .../include/opencv2/stream_accessor.hpp | 39 + modules/cannops/misc/python/pyopencv_cann.hpp | 28 + .../cannops/misc/python/test/test_cannops.py | 281 +++++++ modules/cannops/perf/perf_core.cpp | 161 ++++ modules/cannops/perf/perf_cvtcolor.cpp | 69 ++ .../cannops/perf/perf_element_operations.cpp | 211 +++++ modules/cannops/perf/perf_main.cpp | 23 + modules/cannops/perf/perf_precomp.hpp | 19 + modules/cannops/samples/image_processing.cpp | 60 ++ modules/cannops/samples/image_processing.py | 42 + modules/cannops/src/ascend_mat.cpp | 232 ++++++ modules/cannops/src/cann_call.cpp | 524 ++++++++++++ modules/cannops/src/color.cpp | 777 ++++++++++++++++++ modules/cannops/src/core.cpp | 310 +++++++ modules/cannops/src/element_operations.cpp | 499 +++++++++++ modules/cannops/src/precomp.hpp | 14 + modules/cannops/test/test_core.cpp | 217 +++++ modules/cannops/test/test_cvtcolor.cpp | 89 ++ .../cannops/test/test_element_operations.cpp | 697 ++++++++++++++++ modules/cannops/test/test_main.cpp | 21 + modules/cannops/test/test_npumat.cpp | 146 ++++ modules/cannops/test/test_precomp.hpp | 28 + modules/cannops/test/test_utils.cpp | 49 ++ .../ascend_npu_image_processing.markdown | 130 +++ modules/cannops/tutorials/puppy.jpg | Bin 0 -> 49852 bytes modules/cannops/tutorials/puppy_noisy.jpg | Bin 0 -> 168316 bytes .../cannops/tutorials/puppy_noisy_rotate.jpg | Bin 0 -> 168174 bytes modules/cannops/tutorials/puppy_processed.jpg | Bin 0 -> 168163 bytes 36 files changed, 5885 insertions(+) create mode 100644 modules/cannops/CMakeLists.txt create mode 100644 modules/cannops/Dockerfile create mode 100644 modules/cannops/include/opencv2/cann.hpp create mode 100644 modules/cannops/include/opencv2/cann.inl.hpp create mode 100644 modules/cannops/include/opencv2/cann_call.hpp create mode 100644 modules/cannops/include/opencv2/cann_interface.hpp create mode 100644 modules/cannops/include/opencv2/cann_private.hpp create mode 100644 modules/cannops/include/opencv2/stream_accessor.hpp create mode 100644 modules/cannops/misc/python/pyopencv_cann.hpp create mode 100644 modules/cannops/misc/python/test/test_cannops.py create mode 100644 modules/cannops/perf/perf_core.cpp create mode 100644 modules/cannops/perf/perf_cvtcolor.cpp create mode 100644 modules/cannops/perf/perf_element_operations.cpp create mode 100644 modules/cannops/perf/perf_main.cpp create mode 100644 modules/cannops/perf/perf_precomp.hpp create mode 100644 modules/cannops/samples/image_processing.cpp create mode 100644 modules/cannops/samples/image_processing.py create mode 100644 modules/cannops/src/ascend_mat.cpp create mode 100644 modules/cannops/src/cann_call.cpp create mode 100644 modules/cannops/src/color.cpp create mode 100644 modules/cannops/src/core.cpp create mode 100644 modules/cannops/src/element_operations.cpp create mode 100644 modules/cannops/src/precomp.hpp create mode 100644 modules/cannops/test/test_core.cpp create mode 100644 modules/cannops/test/test_cvtcolor.cpp create mode 100644 modules/cannops/test/test_element_operations.cpp create mode 100644 modules/cannops/test/test_main.cpp create mode 100644 modules/cannops/test/test_npumat.cpp create mode 100644 modules/cannops/test/test_precomp.hpp create mode 100644 modules/cannops/test/test_utils.cpp create mode 100644 modules/cannops/tutorials/ascend_npu_image_processing.markdown create mode 100644 modules/cannops/tutorials/puppy.jpg create mode 100644 modules/cannops/tutorials/puppy_noisy.jpg create mode 100644 modules/cannops/tutorials/puppy_noisy_rotate.jpg create mode 100644 modules/cannops/tutorials/puppy_processed.jpg diff --git a/.github/workflows/PR-4.x.yaml b/.github/workflows/PR-4.x.yaml index bd90f16ca28..f33cc37d5d5 100644 --- a/.github/workflows/PR-4.x.yaml +++ b/.github/workflows/PR-4.x.yaml @@ -29,3 +29,7 @@ jobs: Linux-RISC-V-Clang: uses: opencv/ci-gha-workflow/.github/workflows/OCV-Contrib-PR-4.x-RISCV.yaml@main + + openEuler2203-x64: + if: "${{ contains(github.event.pull_request.labels.*.name, 'category: cann') }}" + uses: opencv/ci-gha-workflow/.github/workflows/OCV-Contrib-PR-4.x-O22-CANN.yaml@main diff --git a/modules/cannops/CMakeLists.txt b/modules/cannops/CMakeLists.txt new file mode 100644 index 00000000000..0c16c5eb143 --- /dev/null +++ b/modules/cannops/CMakeLists.txt @@ -0,0 +1,17 @@ + if(IOS OR WINRT OR ANDROID OR APPLE OR WIN32 OR (NOT HAVE_CANN)) + ocv_module_disable(cannops) + endif() + +set(the_description "Ascend-accelerated Operations on Matrices") + +ocv_add_module(cannops opencv_core WRAP python) +ocv_module_include_directories(${CANN_INCLUDE_DIRS}) +ocv_glob_module_sources() +ocv_install_used_external_targets(${CANN_LIBRARIES}) +ocv_create_module(${CANN_LIBRARIES}) + +ocv_include_directories(${CMAKE_SOURCE_DIR}/modules/ts/include) + +ocv_add_accuracy_tests(DEPENDS_ON opencv_cannops) +ocv_add_perf_tests(DEPENDS_ON opencv_cannops) +ocv_add_samples(opencv_cannops) diff --git a/modules/cannops/Dockerfile b/modules/cannops/Dockerfile new file mode 100644 index 00000000000..939999eed4f --- /dev/null +++ b/modules/cannops/Dockerfile @@ -0,0 +1,67 @@ +# User guides +# +# 0. Install Ascend driver on host. +# (https://www.hiascend.com/en/hardware/firmware-drivers) +# +# 1. Run docker container. +# docker run -it \ +# --name opencv \ +# --device /dev/davinci0 \ +# --device /dev/davinci_manager \ +# --device /dev/devmm_svm \ +# --device /dev/hisi_hdc \ +# -v /usr/local/dcmi:/usr/local/dcmi \ +# -v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \ +# -v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \ +# opencv bash +# +# 2. Check environment. +# npu-smi info +# +# 3. Compile opencv with Ascend NPU backend. +# cmake -DWITH_CANN=1 +# +# 4. Run opencv_test_cannops. +# ./bin/opencv_test_cannops + +FROM openeuler/openeuler:22.03-lts-sp2 + +RUN yum install -y \ + git \ + wget \ + gcc \ + g++ \ + cmake \ + make \ + python-pip \ + python3-devel + +RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple \ + numpy \ + sympy \ + decorator \ + scipy \ + attrs \ + psutil + +# Install CANN +RUN wget https://ascend-repo.obs.cn-east-2.myhuaweicloud.com/CANN/CANN%207.0.RC1/Ascend-cann-toolkit_7.0.RC1_linux-"$(uname -i)".run && \ + chmod +x Ascend-cann-toolkit_7.0.RC1_linux-"$(uname -i)".run && \ + ./Ascend-cann-toolkit_7.0.RC1_linux-"$(uname -i)".run --quiet --install && \ + rm -f ./Ascend-cann-toolkit_7.0.RC1_linux-"$(uname -i)".run + +# Install kernel +RUN wget https://ascend-repo.obs.cn-east-2.myhuaweicloud.com/CANN/CANN%207.0.RC1/Ascend-cann-kernels-310p_7.0.RC1_linux.run && \ + chmod +x Ascend-cann-kernels-310p_7.0.RC1_linux.run && \ + ./Ascend-cann-kernels-310p_7.0.RC1_linux.run --quiet --install && \ + rm -f ./Ascend-cann-kernels-310p_7.0.RC1_linux.run + +ENV LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64:/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver:$LD_LIBRARY_PATH:/usr/lib64 +ENV ASCEND_TOOLKIT_HOME=/usr/local/Ascend/ascend-toolkit/latest +ENV LD_LIBRARY_PATH=${ASCEND_TOOLKIT_HOME}/lib64:${ASCEND_TOOLKIT_HOME}/lib64/plugin/opskernel:${ASCEND_TOOLKIT_HOME}/lib64/plugin/nnengine:${ASCEND_TOOLKIT_HOME}/opp/built-in/op_impl/ai_core/tbe/op_tiling:$LD_LIBRARY_PATH +ENV PYTHONPATH=${ASCEND_TOOLKIT_HOME}/python/site-packages:${ASCEND_TOOLKIT_HOME}/opp/built-in/op_impl/ai_core/tbe:$PYTHONPATH +ENV PATH=${ASCEND_TOOLKIT_HOME}/bin:${ASCEND_TOOLKIT_HOME}/compiler/ccec_compiler/bin:$PATH +ENV ASCEND_AICPU_PATH=${ASCEND_TOOLKIT_HOME} +ENV ASCEND_OPP_PATH=${ASCEND_TOOLKIT_HOME}/opp +ENV TOOLCHAIN_HOME=${ASCEND_TOOLKIT_HOME}/toolkit +ENV ASCEND_HOME_PATH=${ASCEND_TOOLKIT_HOME} diff --git a/modules/cannops/include/opencv2/cann.hpp b/modules/cannops/include/opencv2/cann.hpp new file mode 100644 index 00000000000..30555dd8257 --- /dev/null +++ b/modules/cannops/include/opencv2/cann.hpp @@ -0,0 +1,328 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CANNOPS_CANN_HPP +#define OPENCV_CANNOPS_CANN_HPP + +#include "opencv2/core.hpp" + +/** + @defgroup cann Ascend-accelerated Computer Vision + @{ + @defgroup canncore Core part + @{ + @defgroup cann_struct Data Structures + @defgroup cann_init Initializeation and Information + @} + @} + */ + +namespace cv +{ +namespace cann +{ +class AscendStream; + +//! @addtogroup cann_struct +//! @{ + +//=================================================================================== +// AscendMat +//=================================================================================== + +/** @brief Base storage class for NPU memory with reference counting. + * AscendMat class has a similar interface with Mat and AscendMat, and work on [Ascend + * NPU](https://www.hiascend.com/) backend. + * @sa Mat cuda::GpuMat + */ +class AscendStream; +class CV_EXPORTS_W AscendMat +{ +public: + class CV_EXPORTS_W Allocator + { + public: + virtual ~Allocator() {} + // basic allocator + virtual std::shared_ptr allocate(size_t size) = 0; + // allocator must fill data, step and refcount fields + virtual bool allocate(AscendMat* mat, int rows, int cols, size_t elemSize) = 0; + }; + + /** + * @brief Create default allocator for AscendMat. This allocator alloc memory from device for + * specific size. + */ + CV_WRAP static AscendMat::Allocator* defaultAllocator(); + + /** + * @brief Set allocator for AscendMat. + * @param allocator + */ + CV_WRAP static void setDefaultAllocator(AscendMat::Allocator* allocator); + + //! default constructor + CV_WRAP explicit AscendMat(AscendMat::Allocator* allocator_ = AscendMat::defaultAllocator()); + + //! constructs AscendMat of the specified size and type + CV_WRAP AscendMat(int rows, int cols, int type, + AscendMat::Allocator* allocator = AscendMat::defaultAllocator()); + //! constructs AscendMat of the specified size and type + CV_WRAP AscendMat(Size size, int type, + AscendMat::Allocator* allocator = AscendMat::defaultAllocator()); + + //! constructs AscendMat and fills it with the specified value s + CV_WRAP AscendMat(int rows, int cols, int type, Scalar& s, + AscendMat::Allocator* allocator = AscendMat::defaultAllocator()); + //! constructs AscendMat and fills it with the specified value s + CV_WRAP AscendMat(Size size, int type, Scalar& s, + AscendMat::Allocator* allocator = AscendMat::defaultAllocator()); + + //! copy constructor + CV_WRAP AscendMat(const AscendMat& m); + + //! constructs AscendMat by crop a certain area from another + CV_WRAP AscendMat(InputArray _m, const Rect& roi); + CV_WRAP AscendMat(InputArray _m, const Rect& roi, AscendStream& stream); + + //! builds AscendMat from host memory (Blocking call) + CV_WRAP explicit AscendMat(InputArray arr, AscendStream& stream, + AscendMat::Allocator* allocator = AscendMat::defaultAllocator()); + + //! assignment operators + AscendMat& operator=(const AscendMat& m); + + //! sets some of the AscendMat elements to s (Blocking call) + CV_WRAP AscendMat& setTo(const Scalar& s); + //! sets some of the AscendMat elements to s (Non-Blocking call) + CV_WRAP AscendMat& setTo(const Scalar& s, AscendStream& stream); + + //! sets all of the AscendMat elements to float (Blocking call) + CV_WRAP AscendMat& setTo(float sc); + + //! sets all of the AscendMat elements to float (Non-Blocking call) + CV_WRAP AscendMat& setTo(float sc, AscendStream& stream); + + //! swaps with other smart pointer + CV_WRAP void swap(AscendMat& mat); + + //! allocates new AscendMat data unless the AscendMat already has specified size and type + CV_WRAP void create(int rows, int cols, int type); + + //! upload host memory data to AscendMat (Blocking call) + CV_WRAP void upload(InputArray arr); + //! upload host memory data to AscendMat (Non-Blocking call) + CV_WRAP void upload(InputArray arr, AscendStream& stream); + + //! download data from AscendMat to host (Blocking call) + CV_WRAP void download(OutputArray dst) const; + //! download data from AscendMat to host (Non-Blocking call) + CV_WRAP void download(OutputArray dst, AscendStream& stream) const; + + //! converts AscendMat to another datatype (Blocking call) + CV_WRAP void convertTo(CV_OUT AscendMat& dst, int rtype) const; + + //! converts AscendMat to another datatype (Non-Blocking call) + CV_WRAP void convertTo(CV_OUT AscendMat& dst, int rtype, AscendStream& stream) const; + + //! converts AscendMat to another datatype, dst mat is allocated. (Non-Blocking call) + CV_WRAP void convertTo(CV_OUT AscendMat& dst, AscendStream& stream) const; + + //! returns true iff the AscendMat data is continuous + //! (i.e. when there are no gaps between successive rows) + CV_WRAP bool isContinuous() const; + + //! returns element size in bytes + CV_WRAP size_t elemSize() const; + + //! returns the size of element channel in bytes + CV_WRAP size_t elemSize1() const; + + //! returns element type + CV_WRAP int type() const; + + //! returns element type + CV_WRAP int depth() const; + + //! returns number of channels + CV_WRAP int channels() const; + + //! returns step/elemSize1() + CV_WRAP size_t step1() const; + + //! returns AscendMat size : width == number of columns, height == number of rows + CV_WRAP Size size() const; + + //! returns true if AscendMat data is NULL + CV_WRAP bool empty() const; + + //! internal use method: updates the continuity flag + CV_WRAP void updateContinuityFlag(); + + /*! includes several bit-fields: + - the magic signature + - continuity flag + - depth + - number of channels + */ + int flags; + + //! the number of rows and columns + int rows, cols; + + //! a distance between successive rows in bytes; includes the gap if any + CV_PROP size_t step; + + //! pointer to the data + std::shared_ptr data; + + //! helper fields used in locateROI and adjustROI + uchar* datastart; + const uchar* dataend; + + //! allocator + Allocator* allocator; +}; + +class AscendStream; +class AscendStreamAccessor; +class AscendEvent; +class AscendEventAccessor; +class DefaultDeviceInitializer; + +//=================================================================================== +// AscendStream +//=================================================================================== + +/** @brief In AscendCL Stream(AscendStream) is a task queue. Stream is used to manage the + * parallelism of tasks. The tasks inside a Stream are executed sequentially, that is, the Stream + * executes sequentially according to the sent tasks; the tasks in different Streams are executed in + * parallel. + * + * All Non-blocking functions should pass parameter stream, These function returns immediately after + * the task is submitted. Caller should wait stream until completion. + * + * Blocking functions implicityly use the default stream, and synchronize stream before function + * return. + * @sa cuda::Stream + */ + +// TODO: Stream is defined in namespace cuda, and pybind code does not use a namespace of stream, +// change stream name to AscendStream to avoid confilct. +class CV_EXPORTS_W AscendStream +{ +public: + CV_WRAP AscendStream(); + + //! blocks the current CPU thread until all operations in the stream are complete. + CV_WRAP void waitForCompletion(); + + //! blocks the current CPU thread until event trigger. + CV_WRAP void waitAscendEvent(const cv::cann::AscendEvent& event); + + /** + * @brief return default AscendStream object for default Acl stream. + */ + CV_WRAP static AscendStream& Null(); + + // acl symbols CANNOT used in any hpp files. Use a inner class to avoid acl symbols defined in + // hpp. + class Impl; + + void addTensorHolder(const std::shared_ptr& holder); + +private: + Ptr impl_; + AscendStream(const Ptr& impl); + + friend class AscendStreamAccessor; + friend class DefaultDeviceInitializer; +}; + +/** + * @brief AscendEvent to synchronize between different streams. + */ +class CV_EXPORTS_W AscendEvent +{ +public: + CV_WRAP AscendEvent(); + + //! records an event + CV_WRAP void record(AscendStream& stream); + + //! waits for an event to complete + CV_WRAP void waitForComplete() const; + + class Impl; + +private: + Ptr impl_; + AscendEvent(const Ptr& impl); + + friend class AscendEventAccessor; +}; + +/** @brief Bindings overload to create a Stream object from the address stored in an existing CANN + * Runtime API stream pointer (aclrtStream). + * @param AscendStreamAddress Memory address stored in a CANN Runtime API stream pointer + * (aclrtStream). The created Stream object does not perform any allocation or deallocation and + * simply wraps existing raw CANN Runtime API stream pointer. + * @note Overload for generation of bindings only, not exported or intended for use internally fro + * C++. + */ +CV_EXPORTS_W AscendStream wrapStream(size_t AscendStreamAddress); + +//! @} cann_struct + +//=================================================================================== +// Initialization & Info +//=================================================================================== + +//! @addtogroup cann_init +//! @{ + +//! Get Ascend matrix object from Input array, upload matrix memory if need. (Non-Blocking call) +AscendMat getInputMat(InputArray src, AscendStream& stream); + +//! Get Ascend matrix object from Output array, upload matrix memory if need. +AscendMat getOutputMat(OutputArray dst, int rows, int cols, int type, AscendStream& stream); + +//! Sync output matrix to Output array, download matrix memory if need. +void syncOutput(const AscendMat& dst, OutputArray _dst, AscendStream& stream); + +/** + * @brief Choose Ascend npu device. + */ +CV_EXPORTS_W void setDevice(int device); + +/** + * @brief Clear all context created in current Ascend device. + */ +CV_EXPORTS_W void resetDevice(); + +/** + * @brief Get current Ascend device. + */ +CV_EXPORTS_W int32_t getDevice(); + +/** + * @brief init AscendCL. + */ +CV_EXPORTS_W void initAcl(); + +/** + * @brief finalize AscendCL. + * @note finalizeAcl only can be called once for a process. Call this function after all AscendCL + * options finished. + */ +CV_EXPORTS_W void finalizeAcl(); + +//! @} cann_init + +} // namespace cann +} // namespace cv + +#include "opencv2/cann.inl.hpp" + +#endif // OPENCV_CANNOPS_CANN_HPP diff --git a/modules/cannops/include/opencv2/cann.inl.hpp b/modules/cannops/include/opencv2/cann.inl.hpp new file mode 100644 index 00000000000..4a97466b375 --- /dev/null +++ b/modules/cannops/include/opencv2/cann.inl.hpp @@ -0,0 +1,97 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CANNOPS_CANN_INL_HPP +#define OPENCV_CANNOPS_CANN_INL_HPP + +#include "opencv2/cann.hpp" + +namespace cv +{ +namespace cann +{ +inline AscendMat::AscendMat(AscendMat::Allocator* allocator_) + : flags(0), rows(0), cols(0), step(0), datastart(0), dataend(0), + allocator(allocator_) +{ + // Empty mat is also continuous. + flags |= Mat::CONTINUOUS_FLAG; +} + +inline AscendMat::AscendMat(int rows_, int cols_, int type_, AscendMat::Allocator* allocator_) + : flags(0), rows(0), cols(0), step(0), datastart(0), dataend(0), + allocator(allocator_) +{ + if (rows_ > 0 && cols_ > 0) + create(rows_, cols_, type_); +} + +inline AscendMat::AscendMat(Size size_, int type_, AscendMat::Allocator* allocator_) + : flags(0), rows(0), cols(0), step(0), datastart(0), dataend(0), + allocator(allocator_) +{ + if (size_.height > 0 && size_.width > 0) + create(size_.height, size_.width, type_); +} + +inline AscendMat::AscendMat(InputArray arr, AscendStream& stream, AscendMat::Allocator* allocator_) + : flags(0), rows(0), cols(0), step(0), datastart(0), dataend(0), + allocator(allocator_) +{ + upload(arr, stream); +} + +inline AscendMat::AscendMat(const AscendMat& m) + : flags(m.flags), rows(m.rows), cols(m.cols), step(m.step), data(m.data), + datastart(m.datastart), dataend(m.dataend), allocator(m.allocator) +{} + +inline AscendMat& AscendMat::operator=(const AscendMat& m) +{ + if (this != &m) + { + AscendMat temp(m); + swap(temp); + } + + return *this; +} + +inline void AscendMat::swap(AscendMat& b) +{ + std::swap(flags, b.flags); + std::swap(rows, b.rows); + std::swap(cols, b.cols); + std::swap(step, b.step); + std::swap(data, b.data); + std::swap(datastart, b.datastart); + std::swap(dataend, b.dataend); + std::swap(allocator, b.allocator); +} + +inline bool AscendMat::isContinuous() const { return (flags & Mat::CONTINUOUS_FLAG) != 0; } + +inline size_t AscendMat::elemSize() const { return CV_ELEM_SIZE(flags); } + +inline size_t AscendMat::elemSize1() const { return CV_ELEM_SIZE1(flags); } + +inline int AscendMat::type() const { return CV_MAT_TYPE(flags); } + +inline int AscendMat::depth() const { return CV_MAT_DEPTH(flags); } + +inline int AscendMat::channels() const { return CV_MAT_CN(flags); } + +inline size_t AscendMat::step1() const { return step / elemSize1(); } + +inline Size AscendMat::size() const { return Size(cols, rows); } + +inline bool AscendMat::empty() const { return data == 0; } + +inline AscendStream::AscendStream(const Ptr& impl) : impl_(impl) {} + +inline AscendEvent::AscendEvent(const Ptr& impl) : impl_(impl) {} +} // namespace cann +} // namespace cv + +#endif // OPENCV_CANNOPS_CANN_INL_HPP diff --git a/modules/cannops/include/opencv2/cann_call.hpp b/modules/cannops/include/opencv2/cann_call.hpp new file mode 100644 index 00000000000..651bff8bba0 --- /dev/null +++ b/modules/cannops/include/opencv2/cann_call.hpp @@ -0,0 +1,157 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CANNOPS_CANN_CALL_HPP +#define OPENCV_CANNOPS_CANN_CALL_HPP + +#include +#include +#include +#include +#include "opencv2/cann.hpp" + +class aclopAttr; + +namespace cv +{ +namespace cann +{ +// Warpper for functions in CANN, callers should not call CANN's api directly, but should call the +// function provided in cann_call. +void aclrtMallocWarpper(void** data, size_t size); +void aclrtFreeWarpper(void* data); +void aclrtMemcpyWarpper(std::shared_ptr& dst, size_t offset, const void* src, size_t size, + AscendStream& stream); +void aclrtMemcpyWarpper(void* dst, const std::shared_ptr& src, size_t offset, size_t size, + AscendStream& stream); +void aclrtMemcpyWarpper(std::shared_ptr& dst, size_t dstOffset, + const std::shared_ptr& src, size_t srcOffset, size_t size, + AscendStream& stream); +void aclrtMemcpy2dWarpper(std::shared_ptr& dst, size_t offset, size_t dpitch, + const void* src, size_t spitch, size_t width, size_t length, + AscendStream& stream); +void aclrtMemcpy2dWarpper(void* dst, size_t dpitch, const std::shared_ptr& src, + size_t offset, size_t spitch, size_t width, size_t length, + AscendStream& stream); +void aclrtMemsetWarpper(std::shared_ptr& ptr, int32_t value, size_t count, + AscendStream& stream); +//! Type mapping between opencv and cann. +aclDataType getACLType(int opencvdepth); +//! Malloc and upload raw data to devices. +std::shared_ptr mallocAndUpload(const void* data, size_t size, AscendStream& stream, + AscendMat::Allocator* allocator); +/** + * @brief Warpper of CANN streams. + */ +class AscendStream::Impl +{ +public: + aclrtStream stream; + bool ownStream; + /** + * @brief Ascend and CANN use stream to implement asynchronous calls. Which means when function + * returns, operator may not finish, even not start. If caller free any tensors that participate + * in this operatation, it have a chance to access invalid memory. + * All tensors should add to holder, holder will be cleaned by waitForCompletion function, or when + * the stream is destructing. + */ + std::set> tensorHolders; + Impl(); + explicit Impl(aclrtStream stream); + void AddTensorHolder(const std::shared_ptr& tensorData); +}; + +/** + * @brief Warpper of CANN event. + */ +class AscendEvent::Impl +{ +public: + aclrtEvent event; + bool ownEvent; + + Impl(); + explicit Impl(aclrtEvent event); + ~Impl(); +}; + +/** + * @brief Parameter type for call_call interfaces. + */ +struct AscendTensor +{ + const char* name; + std::shared_ptr data; + size_t dataSize; + std::vector dims; + aclDataType dtype; + aclFormat format; + AscendTensor(){}; + AscendTensor(std::shared_ptr _data, size_t _dataSize, int64_t* _dims, size_t _dimSize, + aclDataType _dtype, const char* _name = "", aclFormat _format = ACL_FORMAT_ND); + AscendTensor(std::shared_ptr _data, size_t _dataSize, std::vector& _dims, + aclDataType _dtype, const char* _name = "", aclFormat _format = ACL_FORMAT_ND) + : name(_name), data(_data), dataSize(_dataSize), dims(_dims), dtype(_dtype), + format(_format){}; + AscendTensor(const AscendMat& ascendMat, const char* _name = "", + aclFormat format = ACL_FORMAT_ND); +}; + +/** + * @brief Interface to call operators in CANN package. + */ +class OperatorRunner +{ +private: + std::vector inputBuffers_; + std::vector outputBuffers_; + std::vector inputDesc_; + std::vector outputDesc_; + aclopAttr* opAttr_; + bool opAttrInit; + std::string op; + + std::set> holder; + + OperatorRunner& addInput(AscendTensor& mat); + OperatorRunner& addOutput(AscendTensor& mat); + +public: + OperatorRunner() : opAttrInit(false) {} + virtual ~OperatorRunner() { reset(); } + OperatorRunner& setOp(const char* op); + OperatorRunner& addInput(const AscendMat& mat); + OperatorRunner& addOutput(AscendMat& mat); + OperatorRunner& addAttr(float value, const char* name); + OperatorRunner& addAttr(const char* value, const char* name); + OperatorRunner& addAttr(int value, const char* name); + OperatorRunner& addAttr(bool value, const char* name); + OperatorRunner& addAttr(const int64_t* value, int size, const char* name); + OperatorRunner& addInput(const AscendMat& mat, const char* name); + OperatorRunner& addInput(const Scalar& sc, int type, const char* name); + + template + OperatorRunner& addInput(const T* value, int64_t* dims, size_t dimSize, aclDataType type, + const char* name) + { + int64_t size = dims[0]; + for (size_t i = 1; i < dimSize; i++) + size *= dims[i]; + + size_t dataSize = size * sizeof(T); + std::shared_ptr ptr = + mallocAndUpload(value, dataSize, AscendStream::Null(), AscendMat::defaultAllocator()); + + AscendTensor tensor(ptr, dataSize, dims, dimSize, type, name); + return addInput(tensor); + } + OperatorRunner& addOutput(AscendMat& mat, const char* name); + OperatorRunner& reset(); + OperatorRunner& run(AscendStream& stream); +}; + +} // namespace cann +} // namespace cv + +#endif // OPENCV_CANNOPS_CANN_CALL_HPP diff --git a/modules/cannops/include/opencv2/cann_interface.hpp b/modules/cannops/include/opencv2/cann_interface.hpp new file mode 100644 index 00000000000..6667eb58519 --- /dev/null +++ b/modules/cannops/include/opencv2/cann_interface.hpp @@ -0,0 +1,516 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CANNOPS_CANN_INTERFACE_HPP +#define OPENCV_CANNOPS_CANN_INTERFACE_HPP + +#include "opencv2/cann.hpp" + +namespace cv +{ +namespace cann +{ + +/** + @addtogroup cann + @{ + @defgroup cannops Operations for Ascend Backend. + @{ + @defgroup cannops_elem Per-element Operations + @defgroup cannops_core Core Operations on Matrices + @defgroup cannimgproc Image Processing + @} + @} + */ + +//! @addtogroup cannops_elem +//! @{ + +/** @brief Computes a matrix-matrix or matrix-scalar sum. + * @param src1 First source matrix or scalar. + * @param src2 Second source matrix or scalar. Matrix should have the same size and type as src1 . + * @param dst Destination matrix that has the same size and number of channels as the input + * array(s). The depth is defined by dtype or src1 depth. + * @param mask Optional operation mask, 8-bit single channel array, that specifies elements of the + * destination array to be changed. The mask can be used only with single channel images. + * @param dtype Optional depth of the output array. + * @param stream AscendStream for the asynchronous version. + * @sa cv::add cuda::add + */ +CV_EXPORTS_W void add(const InputArray src1, const InputArray src2, OutputArray dst, + const InputArray mask = noArray(), int dtype = -1, + AscendStream& stream = AscendStream::Null()); +// This code should not be compiled nor analyzed by doxygen. This interface only for python binding +// code generation. add(InputArray, InputArray ...) can accept Scalar as its parametr.(Scalar -> Mat +// -> InputArray) +#ifdef NEVER_DEFINED +CV_EXPORTS_W void add(const InputArray src1, const Scalar& src2, OutputArray dst, + const InputArray mask = noArray(), int dtype = -1, + AscendStream& stream = AscendStream::Null()); +CV_EXPORTS_W void add(const Scalar& src1, const InputArray src2, OutputArray dst, + const InputArray mask = noArray(), int dtype = -1, + AscendStream& stream = AscendStream::Null()); +#endif +// More overload functions. In order to decouple from the main opencv repository and simplify +// user calling methods, besides the traditional Input/OutputArray parameters, some +// overloaded functions for the AcendMat parameter is also provided. +/** @overload */ +CV_EXPORTS_W void add(const AscendMat& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), int dtype = -1, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void add(const AscendMat& src1, const Scalar& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), int dtype = -1, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void add(const Scalar& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), int dtype = -1, + AscendStream& stream = AscendStream::Null()); + +/** @brief Computes a matrix-matrix or matrix-scalar difference. + * @param src1 First source matrix or scalar. + * @param src2 Second source matrix or scalar. Matrix should have the same size and type as src1 . + * @param dst Destination matrix that has the same size and number of channels as the input + * array(s). The depth is defined by dtype or src1 depth. + * @param mask Optional operation mask, 8-bit single channel array, that specifies elements of the + * destination array to be changed. The mask can be used only with single channel images. + * @param dtype Optional depth of the output array. + * @param stream AscendStream for the asynchronous version. + * @sa cv::subtract cuda::subtract + */ +CV_EXPORTS_W void subtract(const InputArray src1, const InputArray src2, OutputArray dst, + const InputArray mask = noArray(), int dtype = -1, + AscendStream& stream = AscendStream::Null()); +#ifdef NEVER_DEFINED +CV_EXPORTS_W void subtract(const InputArray src1, const Scalar& src2, OutputArray dst, + const InputArray mask = noArray(), int dtype = -1, + AscendStream& stream = AscendStream::Null()); +CV_EXPORTS_W void subtract(const Scalar& src1, const InputArray src2, OutputArray dst, + const InputArray mask = noArray(), int dtype = -1, + AscendStream& stream = AscendStream::Null()); +#endif +/** @overload */ +CV_EXPORTS_W void subtract(const AscendMat& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), int dtype = -1, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void subtract(const AscendMat& src1, const Scalar& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), int dtype = -1, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void subtract(const Scalar& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), int dtype = -1, + AscendStream& stream = AscendStream::Null()); + +/** @brief Computes a matrix-matrix or matrix-scalar per-element product. + * @param src1 First source matrix or scalar. + * @param src2 Second source matrix or scalar. Matrix should have the same size and type as src1 . + * @param dst Destination matrix that has the same size and number of channels as the input + * array(s). The depth is defined by dtype or src1 depth. + * @param scale Optional scale factor. + * @param dtype Optional depth of the output array. + * @param stream AscendStream for the asynchronous version. + * @sa cv::multiply cuda::multiply + */ +CV_EXPORTS_W void multiply(const InputArray src1, const InputArray src2, OutputArray dst, + float scale = 1, int dtype = -1, + AscendStream& stream = AscendStream::Null()); +#ifdef NEVER_DEFINED +CV_EXPORTS_W void multiply(const InputArray src1, const Scalar& src2, OutputArray dst, + float scale = 1, int dtype = -1, + AscendStream& stream = AscendStream::Null()); +CV_EXPORTS_W void multiply(const Scalar& src1, const InputArray src2, OutputArray dst, + float scale = 1, int dtype = -1, + AscendStream& stream = AscendStream::Null()); +#endif +/** @overload */ +CV_EXPORTS_W void multiply(const AscendMat& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + float scale = 1, int dtype = -1, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void multiply(const AscendMat& src1, const Scalar& src2, CV_OUT AscendMat& dst, + float scale = 1, int dtype = -1, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void multiply(const Scalar& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + float scale = 1, int dtype = -1, + AscendStream& stream = AscendStream::Null()); + +/** @brief Computes a matrix-matrix or matrix-scalar division. + * @param src1 First source matrix or scalar. + * @param src2 Second source matrix or scalar. Matrix should have the same size and type as src1 . + * @param dst Destination matrix that has the same size and number of channels as the input + * array(s). The depth is defined by dtype or src1 depth. + * @param scale Optional scale factor. + * @param dtype Optional depth of the output array. + * @param stream AscendStream for the asynchronous version. + * @sa cv::divide cuda::divide + */ +CV_EXPORTS_W void divide(const InputArray src1, const InputArray src2, OutputArray dst, + float scale = 1, int dtype = -1, + AscendStream& stream = AscendStream::Null()); +#ifdef NEVER_DEFINED +CV_EXPORTS_W void divide(const InputArray src1, const Scalar& src2, OutputArray dst, + float scale = 1, int dtype = -1, + AscendStream& stream = AscendStream::Null()); +CV_EXPORTS_W void divide(const Scalar& src1, const InputArray src2, OutputArray dst, + float scale = 1, int dtype = -1, + AscendStream& stream = AscendStream::Null()); +#endif +CV_EXPORTS_W void divide(const AscendMat& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + float scale = 1, int dtype = -1, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void divide(const AscendMat& src1, const Scalar& src2, CV_OUT AscendMat& dst, + float scale = 1, int dtype = -1, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void divide(const Scalar& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + float scale = 1, int dtype = -1, + AscendStream& stream = AscendStream::Null()); + +/** @brief Performs a per-element bitwise conjunction of two matrices (or of matrix and scalar). + * @param src1 First source matrix or scalar. + * @param src2 Second source matrix or scalar. + * @param dst Destination matrix that has the same size and number of channels as the input + * array(s). The depth is defined by dtype or src1 depth. + * @param mask Optional operation mask, 8-bit single channel array, that specifies elements of the + * destination array to be changed. The mask can be used only with single channel images. + * @param stream AscendStream for the asynchronous version. + * @sa cv::bitwise_and cuda::bitwise_and + */ +CV_EXPORTS_W void bitwise_and(const InputArray src1, const InputArray src2, OutputArray dst, + const InputArray mask = noArray(), + AscendStream& stream = AscendStream::Null()); +#ifdef NEVER_DEFINED +CV_EXPORTS_W void bitwise_and(const InputArray src1, const Scalar& src2, OutputArray dst, + const InputArray mask = noArray(), + AscendStream& stream = AscendStream::Null()); +CV_EXPORTS_W void bitwise_and(const Scalar& src1, const InputArray src2, OutputArray dst, + const InputArray mask = noArray(), + AscendStream& stream = AscendStream::Null()); +#endif +CV_EXPORTS_W void bitwise_and(const AscendMat& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void bitwise_and(const AscendMat& src1, const Scalar& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void bitwise_and(const Scalar& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), + AscendStream& stream = AscendStream::Null()); + +/** @brief Performs a per-element bitwise disjunction of two matrices (or of matrix and scalar). + * @param src1 First source matrix or scalar. + * @param src2 Second source matrix or scalar. + * @param dst Destination matrix that has the same size and number of channels as the input + * array(s). The depth is defined by dtype or src1 depth. + * @param mask Optional operation mask, 8-bit single channel array, that specifies elements of the + * destination array to be changed. The mask can be used only with single channel images. + * @param stream AscendStream for the asynchronous version. + * @sa cv::bitwise_or cuda::bitwise_or + */ +CV_EXPORTS_W void bitwise_or(const InputArray src1, const InputArray src2, OutputArray dst, + const InputArray mask = noArray(), + AscendStream& stream = AscendStream::Null()); +#ifdef NEVER_DEFINED +CV_EXPORTS_W void bitwise_or(const InputArray src1, const Scalar& src2, OutputArray dst, + const InputArray mask = noArray(), + AscendStream& stream = AscendStream::Null()); +CV_EXPORTS_W void bitwise_or(const Scalar& src1, const InputArray src2, OutputArray dst, + const InputArray mask = noArray(), + AscendStream& stream = AscendStream::Null()); +#endif +CV_EXPORTS_W void bitwise_or(const AscendMat& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void bitwise_or(const AscendMat& src1, const Scalar& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void bitwise_or(const Scalar& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), + AscendStream& stream = AscendStream::Null()); + +/** @brief Performs a per-element bitwise exclusive or operation of two matrices (or of matrix and + * scalar). + * @param src1 First source matrix or scalar. + * @param src2 Second source matrix or scalar. + * @param dst Destination matrix that has the same size and number of channels as the input + * array(s). The depth is defined by dtype or src1 depth. + * @param mask Optional operation mask, 8-bit single channel array, that specifies elements of the + * destination array to be changed. The mask can be used only with single channel images. + * @param stream AscendStream for the asynchronous version. + * @sa cv::bitwise_xor cuda::bitwise_xor + */ +CV_EXPORTS_W void bitwise_xor(const InputArray src1, const InputArray src2, OutputArray dst, + const InputArray mask = noArray(), + AscendStream& stream = AscendStream::Null()); +#ifdef NEVER_DEFINED +CV_EXPORTS_W void bitwise_xor(const InputArray src1, const Scalar& src2, OutputArray dst, + const InputArray mask = noArray(), + AscendStream& stream = AscendStream::Null()); +CV_EXPORTS_W void bitwise_xor(const Scalar& src1, const InputArray src2, OutputArray dst, + const InputArray mask = noArray(), + AscendStream& stream = AscendStream::Null()); +#endif +CV_EXPORTS_W void bitwise_xor(const AscendMat& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void bitwise_xor(const AscendMat& src1, const Scalar& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void bitwise_xor(const Scalar& src1, const AscendMat& src2, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), + AscendStream& stream = AscendStream::Null()); + +/** @brief Performs a per-element bitwise inversion. + * @param src First source matrix. + * @param dst Destination matrix that has the same size and number of channels as the input + * array(s). The depth is defined by dtype or src1 depth. + * @param mask Optional operation mask, 8-bit single channel array, that specifies elements of the + * destination array to be changed. The mask can be used only with single channel images. + * @param stream AscendStream for the asynchronous version. + * @sa cv::bitwise_not cuda::bitwise_not + */ +CV_EXPORTS_W void bitwise_not(const InputArray src, OutputArray dst, + const InputArray mask = noArray(), + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void bitwise_not(const AscendMat& src, CV_OUT AscendMat& dst, + const AscendMat& mask = AscendMat(), + AscendStream& stream = AscendStream::Null()); + +/** @brief Computes the weighted sum of two arrays. + +@param src1 First source array. +@param alpha Weight for the first array elements. +@param src2 Second source array of the same size and channel number as src1 . +@param beta Weight for the second array elements. +@param dst Destination array that has the same size and number of channels as the input arrays. +@param gamma Scalar added to each sum. +@param dtype Optional depth of the destination array. When both input arrays have the same depth, +dtype can be set to -1, which will be equivalent to src1.depth(). +@param stream Stream for the asynchronous version. + +The function addWeighted calculates the weighted sum of two arrays as follows: + +\f[\texttt{dst} (I)= \texttt{saturate} ( \texttt{src1} (I)* \texttt{alpha} + \texttt{src2} (I)* +\texttt{beta} + \texttt{gamma} )\f] + +where I is a multi-dimensional index of array elements. In case of multi-channel arrays, each +channel is processed independently. + +@sa cv::addWeighted cv::cuda::addWeighted + */ +CV_EXPORTS_W void addWeighted(const InputArray src1, double alpha, const InputArray src2, + double beta, double gamma, OutputArray dst, int dtype = -1, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void addWeighted(const AscendMat& src1, double alpha, const AscendMat& src2, + double beta, double gamma, CV_OUT AscendMat& dst, int dtype = -1, + AscendStream& stream = AscendStream::Null()); + +/** @brief Applies a fixed-level threshold to each array element. + +@param src Source array (single-channel). +@param dst Destination array with the same size and type as src . +@param thresh Threshold value. +@param maxval Maximum value to use with THRESH_BINARY and THRESH_BINARY_INV threshold types. +@param type Threshold type. For details, see threshold . The THRESH_MASK, THRESH_OTSU and +THRESH_TRIANGLE threshold types are not supported. +@param stream AscendStream for the asynchronous version. + +@sa cv::threshold cv::cuda::threshold +*/ +CV_EXPORTS_W double threshold(const InputArray src, OutputArray dst, double thresh, double maxval, + int type, AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W double threshold(const AscendMat& src, CV_OUT AscendMat& dst, double thresh, + double maxval, int type, AscendStream& stream = AscendStream::Null()); + +//! @} cannops_elem + +//! @addtogroup cannops_core +//! @{ + +/** @brief Makes a multi-channel matrix out of several single-channel matrices. + +@param src Array/vector of source matrices. +@param n Number of source matrices. +@param dst Destination matrix. +@param stream AscendStream for the asynchronous version. + +@sa cv::merge cv::cuda::merge + */ +CV_EXPORTS_W void merge(const AscendMat* src, size_t n, CV_OUT AscendMat& dst, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void merge(const std::vector& src, CV_OUT AscendMat& dst, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void merge(const AscendMat* src, size_t n, OutputArray& dst, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void merge(const std::vector& src, OutputArray& dst, + AscendStream& stream = AscendStream::Null()); + +/** @brief Copies each plane of a multi-channel matrix into an array. + +@param src Source matrix. +@param dst Destination array/vector of single-channel matrices. +@param stream AscendStream for the asynchronous version. + +@sa cv::split cv::cuda::split + */ +CV_EXPORTS_W void split(const AscendMat& src, AscendMat* dst, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void split(const AscendMat& src, CV_OUT std::vector& dst, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void split(const InputArray src, AscendMat* dst, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void split(const InputArray src, CV_OUT std::vector& dst, + AscendStream& stream = AscendStream::Null()); + +/** @brief Transposes a matrix. + +@param src Source matrix. +@param dst Destination matrix. +@param stream AscendStream for the asynchronous version. + +@sa cv::transpose cv::cuda::transpose + */ +CV_EXPORTS_W void transpose(InputArray src, OutputArray dst, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void transpose(const AscendMat& src, CV_OUT AscendMat& dst, + AscendStream& stream = AscendStream::Null()); +/** @brief Flips a 2D matrix around vertical, horizontal, or both axes. + +@param src Source matrix. +@param dst Destination matrix. +@param flipCode Flip mode for the source: +- 0 Flips around x-axis. +- \> 0 Flips around y-axis. +- \< 0 Flips around both axes. +@param stream AscendStream for the asynchronous version. + +@sa cv::flip cv::cuda::flip + */ +CV_EXPORTS_W void flip(InputArray src, OutputArray dst, int flipCode, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void flip(const AscendMat& src, CV_OUT AscendMat& dst, int flipCode, + AscendStream& stream = AscendStream::Null()); +/** @brief Rotates a 2D array in multiples of 90 degrees. +The function cv::rotate rotates the array in one of three different ways: +* Rotate by 90 degrees clockwise (rotateCode = ROTATE_90_CLOCKWISE). +* Rotate by 180 degrees clockwise (rotateCode = ROTATE_180). +* Rotate by 270 degrees clockwise (rotateCode = ROTATE_90_COUNTERCLOCKWISE). +@param src input array. +@param dst output array of the same type as src. The size is the same with ROTATE_180, +and the rows and cols are switched for ROTATE_90_CLOCKWISE and ROTATE_90_COUNTERCLOCKWISE. +@param rotateCode an enum to specify how to rotate the array; see the enum #RotateFlags +@param stream AscendStream for the asynchronous version. + +@sa cv::rotate +*/ +CV_EXPORTS_W void rotate(InputArray src, OutputArray dst, int rotateCode, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void rotate(const AscendMat& src, CV_OUT AscendMat& dst, int rotateMode, + AscendStream& stream = AscendStream::Null()); + +/** @brief crop a 2D array. +The function crops the matrix by given cv::Rect. +Output matrix must be of the same depth as input one, size is specified by given rect size. + +@param src input array. +@param rect a rect to crop a array to +@param stream AscendStream for the asynchronous version. + +@sa cv::gapi::crop +*/ +CV_EXPORTS_W AscendMat crop(InputArray src, const Rect& rect, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W AscendMat crop(const AscendMat& src, const Rect& rect, + AscendStream& stream = AscendStream::Null()); +/** @brief Resizes an image src down to or up to the specified size. +@param src input image +@param dst output image; it has the size dsize (when it is non-zero) or the size computed from +src.size(), fx, and fy; the type of dst is the same as of src. +@param dsize output image size; if it equals zero, it is computed as: + \f[𝚍𝚜𝚒𝚣𝚎 = 𝚂𝚒𝚣𝚎(𝚛𝚘𝚞𝚗𝚍(𝚏𝚡*𝚜𝚛𝚌.𝚌𝚘𝚕𝚜), 𝚛𝚘𝚞𝚗𝚍(𝚏𝚢*𝚜𝚛𝚌.𝚛𝚘𝚠𝚜))\f] + Either dsize or both fx and fy must be non-zero. +@param fx scale factor along the horizontal axis; when it equals 0, it is computed as +\f[(𝚍𝚘𝚞𝚋𝚕𝚎)𝚍𝚜𝚒𝚣𝚎.𝚠𝚒𝚍𝚝𝚑/𝚜𝚛𝚌.𝚌𝚘𝚕𝚜\f] + +@param fy scale factor along the vertical axis; when it equals 0, it is computed as +\f[(𝚍𝚘𝚞𝚋𝚕𝚎)𝚍𝚜𝚒𝚣𝚎.𝚑𝚎𝚒𝚐𝚑𝚝/𝚜𝚛𝚌.𝚛𝚘𝚠𝚜\f] +@param interpolation interpolation method(see **cv.cann.InterpolationFlags**) +@sa cv::resize +*/ + +//! interpolation algorithm +enum InterpolationFlags +{ + /** nearest neighbor interpolation */ + INTER_NEAREST = 0, + /** bilinear interpolation */ + INTER_LINEAR = 1, + /** bicubic interpolation */ + INTER_CUBIC = 2, + /** resampling using pixel area relation. It may be a preferred method for image decimation, as + it gives moire'-free results. But when the image is zoomed, it is similar to the INTER_NEAREST + method. */ + INTER_AREA = 3, + /** mask for interpolation codes */ + INTER_MAX = 7, +}; + +CV_EXPORTS_W void resize(InputArray _src, OutputArray _dst, Size dsize, double inv_scale_x, + double inv_scale_y, int interpolation, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void resize(const AscendMat& src, CV_OUT AscendMat& dst, Size dsize, double inv_scale_x, + double inv_scale_y, int interpolation, + AscendStream& stream = AscendStream::Null()); + +//! @} cannops_core + +//! @addtogroup cannimgproc +//! @{ + +/** @brief Converts an image from one color space to another. + +@param src Source image with CV_8U , CV_16U , or CV_32F depth and 1, 3, or 4 channels. +@param dst Destination image. +@param code Color space conversion code. For details, see cvtColor . +@param dstCn Number of channels in the destination image. If the parameter is 0, the number of the +channels is derived automatically from src and the code . +@param stream AscendStream for the asynchronous version. + +@sa cv::cvtColor cv::cuda::cvtColor + */ +CV_EXPORTS_W void cvtColor(const InputArray src, OutputArray dst, int code, int dstCn = 0, + AscendStream& stream = AscendStream::Null()); +/** @overload */ +CV_EXPORTS_W void cvtColor(const AscendMat& src, CV_OUT AscendMat& dst, int code, int dstCn = 0, + AscendStream& stream = AscendStream::Null()); + +//! @} cannimgproc + +} // namespace cann +} // namespace cv + +#endif // OPENCV_CANNOPS_CANN_INTERFACE_HPP diff --git a/modules/cannops/include/opencv2/cann_private.hpp b/modules/cannops/include/opencv2/cann_private.hpp new file mode 100644 index 00000000000..bcbe33feb19 --- /dev/null +++ b/modules/cannops/include/opencv2/cann_private.hpp @@ -0,0 +1,33 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CANNOPS_CANN_PRIVATE_HPP +#define OPENCV_CANNOPS_CANN_PRIVATE_HPP +#include "opencv2/cann.hpp" + +namespace cv +{ +namespace cann +{ +void arithm_op(const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const char* op, + AscendStream& stream); +void arithm_op(const AscendMat& src, const Scalar& sc, AscendMat& dst, const char* op, + AscendStream& stream); +void arithm_op(const Scalar& sc, const AscendMat& src, AscendMat& dst, const char* op, + AscendStream& stream); +void arithm_op(const AscendMat& src, AscendMat& dst, const char* op, AscendStream& stream); +void arithm_op(const AscendMat& src, float scalar, AscendMat& dst, const char* op, + AscendStream& stream); +void transpose(const AscendMat& src, int64_t* perm, AscendMat& dst, AscendStream& stream); +void flip(const AscendMat& src, std::vector& asixs, AscendMat& dst, AscendStream& stream); +void crop(const AscendMat& src, AscendMat& dst, const AscendMat& sizeSrcNpu, int64_t* offset, + AscendStream& stream); +void transData(const AscendMat& src, AscendMat& dst, const char* from, const char* to, + AscendStream& stream); +void resize(const AscendMat& src, AscendMat& dst, int32_t* dstSize, int interpolation, + AscendStream& stream); +} // namespace cann +} // namespace cv + +#endif // OPENCV_CANNOPS_CANN_PRIVATE_HPP diff --git a/modules/cannops/include/opencv2/stream_accessor.hpp b/modules/cannops/include/opencv2/stream_accessor.hpp new file mode 100644 index 00000000000..ff64d7dcbc0 --- /dev/null +++ b/modules/cannops/include/opencv2/stream_accessor.hpp @@ -0,0 +1,39 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CANNOPS_STREAM_ACCESSOR_HPP +#define OPENCV_CANNOPS_STREAM_ACCESSOR_HPP + +#include +#include "opencv2/cann.hpp" + +namespace cv +{ +namespace cann +{ +//! @addtogroup cann_struct +//! @{ + +/** @brief Class that enables getting aclrtAscendStream from cann::AscendStream + */ +struct AscendStreamAccessor +{ + CV_EXPORTS static aclrtStream getStream(const AscendStream& stream); + CV_EXPORTS static AscendStream wrapStream(aclrtStream stream); +}; + +/** @brief Class that enables getting aclrtAscendEvent from cann::AscendEvent + */ +struct AscendEventAccessor +{ + CV_EXPORTS static aclrtEvent getEvent(const AscendEvent& event); + CV_EXPORTS static AscendEvent wrapEvent(aclrtEvent event); +}; + +//! @} cann_struct + +} // namespace cann +} // namespace cv + +#endif // OPENCV_CANNOPS_STREAM_ACCESSOR_HPP diff --git a/modules/cannops/misc/python/pyopencv_cann.hpp b/modules/cannops/misc/python/pyopencv_cann.hpp new file mode 100644 index 00000000000..02d62487c6a --- /dev/null +++ b/modules/cannops/misc/python/pyopencv_cann.hpp @@ -0,0 +1,28 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CANNOPS_PYOPENCV_CANN_HPP +#define OPENCV_CANNOPS_PYOPENCV_CANN_HPP + +#ifdef HAVE_OPENCV_CORE + +#include "opencv2/cann.hpp" + +typedef std::vector vector_AscendMat; +typedef cann::AscendMat::Allocator AscendMat_Allocator; + +CV_PY_TO_CLASS(cann::AscendMat); +CV_PY_TO_CLASS(cann::AscendStream); + +CV_PY_TO_CLASS_PTR(cann::AscendMat); +CV_PY_TO_CLASS_PTR(cann::AscendMat::Allocator); + +CV_PY_FROM_CLASS(cann::AscendMat); +CV_PY_FROM_CLASS(cann::AscendStream); + +CV_PY_FROM_CLASS_PTR(cann::AscendMat::Allocator); + +#endif // HAVE_OPENCV_CORE + +#endif // OPENCV_CANNOPS_PYOPENCV_CANN_HPP diff --git a/modules/cannops/misc/python/test/test_cannops.py b/modules/cannops/misc/python/test/test_cannops.py new file mode 100644 index 00000000000..f1b53bc192c --- /dev/null +++ b/modules/cannops/misc/python/test/test_cannops.py @@ -0,0 +1,281 @@ +# 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. + +import cv2 as cv +from tests_common import NewOpenCVTests +import numpy as np + +def genMask(mask, listx, listy): + for row in range(mask.shape[0]): + for col in range(mask.shape[1]): + if (row in listx and col in listx) or (row in listy and col in listy): + mask[row][col] = 1 + mask = mask.astype(np.uint8) + return mask + + +mask = np.zeros((5, 5)) +listx = [0, 1] +listy = [1, 2] +mask = genMask(mask, listx, listy) + + +class cannop_test(NewOpenCVTests): + def test_ascend(self): + cv.cann.initAcl() + cv.cann.getDevice() + cv.cann.setDevice(0) + stream = cv.cann.AscendStream_Null() + cv.cann.wrapStream(id(stream)) + cv.cann.resetDevice() + + def test_arithmetic(self): + # input data + npMat1 = np.random.random((5, 5, 3)).astype(int) + npMat2 = np.random.random((5, 5, 3)).astype(int) + cv.cann.setDevice(0) + + # ACLMat input data + aclMat1 = cv.cann.AscendMat() + aclMat1.upload(npMat1) + aclMat2 = cv.cann.AscendMat() + aclMat2.upload(npMat2) + aclMask = cv.cann.AscendMat() + aclMask.upload(mask) + aclMatDst = cv.cann.AscendMat(aclMat1.size(), aclMat1.type()) + + # InputArray interface test + self.assertTrue(np.allclose(cv.cann.add( + npMat1, npMat2), cv.add(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.subtract( + npMat1, npMat2), cv.subtract(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.multiply( + npMat1, npMat2, scale=2), cv.multiply(npMat1, npMat2, scale=2))) + self.assertTrue(np.allclose(cv.cann.divide( + npMat1, npMat2, scale=2), cv.divide(npMat1, npMat2, scale=2))) + + # AscendMat interface test + self.assertTrue(np.allclose(cv.cann.add(aclMat1, aclMat2).download(), + cv.add(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.subtract(aclMat1, aclMat2).download(), + cv.subtract(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.multiply(aclMat1, aclMat2, scale=2).download(), + cv.multiply(npMat1, npMat2, scale=2))) + self.assertTrue(np.allclose(cv.cann.divide(aclMat1, aclMat2, scale=2).download(), + cv.divide(npMat1, npMat2, scale=2))) + + # mask + self.assertTrue(np.allclose(cv.cann.add( + npMat1, npMat2, mask=mask), cv.add(npMat1, npMat2, mask=mask))) + self.assertTrue(np.allclose(cv.cann.subtract( + npMat1, npMat2, mask=mask), cv.subtract(npMat1, npMat2, mask=mask))) + self.assertTrue(np.allclose(cv.cann.multiply(npMat1, npMat2, scale=2), + cv.multiply(npMat1, npMat2, scale=2))) + self.assertTrue(np.allclose(cv.cann.divide(npMat1, npMat2, scale=2), + cv.divide(npMat1, npMat2, scale=2))) + self.assertTrue(np.allclose(cv.cann.addWeighted(npMat1, 2, npMat2, 4, 3), + cv.addWeighted(npMat1, 2, npMat2, 4, 3))) + + self.assertTrue(np.allclose(cv.cann.add(aclMat1, aclMat2, mask=aclMask).download(), + cv.add(npMat1, npMat2, mask=mask))) + self.assertTrue(np.allclose(cv.cann.subtract(aclMat1, aclMat2, mask=aclMask).download(), + cv.subtract(npMat1, npMat2, mask=mask))) + self.assertTrue(np.allclose(cv.cann.multiply(aclMat1, aclMat2, scale=2).download(), + cv.multiply(npMat1, npMat2, scale=2))) + self.assertTrue(np.allclose(cv.cann.divide(aclMat1, aclMat2, scale=2).download(), + cv.divide(npMat1, npMat2, scale=2))) + self.assertTrue(np.allclose(cv.cann.addWeighted(aclMat1, 2, aclMat2, 4, 3).download(), + cv.addWeighted(npMat1, 2, npMat2, 4, 3))) + + # stream + stream = cv.cann.AscendStream() + matDst = cv.cann.add(npMat1, npMat2, stream=stream) + stream.waitForCompletion() + self.assertTrue(np.allclose(matDst, cv.add(npMat1, npMat2))) + matDst = cv.cann.add(npMat1, npMat2, mask=mask, stream=stream) + stream.waitForCompletion() + self.assertTrue(np.allclose(matDst, cv.add(npMat1, npMat2, mask=mask))) + matDst = cv.cann.subtract(npMat1, npMat2, mask=mask, stream=stream) + stream.waitForCompletion() + self.assertTrue(np.allclose( + matDst, cv.subtract(npMat1, npMat2, mask=mask))) + + # stream AsceendMat + aclMatDst = cv.cann.add(aclMat1, aclMat2, stream=stream) + stream.waitForCompletion() + self.assertTrue(np.allclose(aclMatDst.download(), + cv.add(npMat1, npMat2))) + + aclMatDst = cv.cann.add(aclMat1, aclMat2, mask=aclMask, stream=stream) + stream.waitForCompletion() + self.assertTrue(np.allclose(aclMatDst.download(), + cv.add(npMat1, npMat2, mask=mask))) + + aclMatDst = cv.cann.subtract(aclMat1, aclMat2, mask=aclMask, stream=stream) + stream.waitForCompletion() + self.assertTrue(np.allclose(aclMatDst.download(), + cv.subtract(npMat1, npMat2, mask=mask))) + + cv.cann.resetDevice() + + def test_logical(self): + npMat1 = np.random.random((5, 5, 3)).astype(np.uint16) + npMat2 = np.random.random((5, 5, 3)).astype(np.uint16) + cv.cann.setDevice(0) + + # ACLMat input data + aclMat1 = cv.cann.AscendMat() + aclMat1.upload(npMat1) + aclMat2 = cv.cann.AscendMat() + aclMat2.upload(npMat2) + aclMask = cv.cann.AscendMat() + aclMask.upload(mask) + + self.assertTrue(np.allclose(cv.cann.bitwise_or(npMat1, npMat2), + cv.bitwise_or(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.bitwise_or( + npMat1, npMat2), cv.bitwise_or(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.bitwise_and(npMat1, npMat2), + cv.bitwise_and(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.bitwise_and( + npMat1, npMat2), cv.bitwise_and(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.bitwise_xor(npMat1, npMat2), + cv.bitwise_xor(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.bitwise_xor( + npMat1, npMat2), cv.bitwise_xor(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.bitwise_not(npMat1), + cv.bitwise_not(npMat1))) + self.assertTrue(np.allclose( + cv.cann.bitwise_not(npMat1), cv.bitwise_not(npMat1))) + self.assertTrue(np.allclose(cv.cann.bitwise_and(npMat1, npMat2, mask=mask), + cv.bitwise_and(npMat1, npMat2, mask=mask))) + self.assertTrue(np.allclose(cv.cann.bitwise_or(npMat1, npMat2, mask=mask), + cv.bitwise_or(npMat1, npMat2, mask=mask))) + self.assertTrue(np.allclose(cv.cann.bitwise_not(npMat1, mask=mask), + cv.bitwise_not(npMat1, mask=mask))) + self.assertTrue(np.allclose(cv.cann.bitwise_xor(npMat1, npMat2, mask=mask), + cv.bitwise_xor(npMat1, npMat2, mask=mask))) + + # AscendMat interface + self.assertTrue(np.allclose(cv.cann.bitwise_or(aclMat1, aclMat2).download(), + cv.bitwise_or(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.bitwise_or(aclMat1, aclMat2).download(), + cv.bitwise_or(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.bitwise_and(aclMat1, aclMat2).download(), + cv.bitwise_and(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.bitwise_and( + aclMat1, aclMat2).download(), cv.bitwise_and(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.bitwise_xor(aclMat1, aclMat2).download(), + cv.bitwise_xor(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.bitwise_xor( + aclMat1, aclMat2).download(), cv.bitwise_xor(npMat1, npMat2))) + self.assertTrue(np.allclose(cv.cann.bitwise_not(aclMat1).download(), + cv.bitwise_not(npMat1))) + self.assertTrue(np.allclose(cv.cann.bitwise_not(aclMat1).download(), + cv.bitwise_not(npMat1))) + self.assertTrue(np.allclose(cv.cann.bitwise_and(aclMat1, aclMat2, mask=aclMask).download(), + cv.bitwise_and(npMat1, npMat2, mask=mask))) + self.assertTrue(np.allclose(cv.cann.bitwise_or(aclMat1, aclMat2, mask=aclMask).download(), + cv.bitwise_or(npMat1, npMat2, mask=mask))) + self.assertTrue(np.allclose(cv.cann.bitwise_not(aclMat1, mask=aclMask).download(), + cv.bitwise_not(npMat1, mask=mask))) + self.assertTrue(np.allclose(cv.cann.bitwise_xor(aclMat1, aclMat2, mask=aclMask).download(), + cv.bitwise_xor(npMat1, npMat2, mask=mask))) + cv.cann.resetDevice() + + def test_imgproc(self): + npMat = (np.random.random((128, 128, 3)) * 255).astype(np.uint8) + cv.cann.setDevice(0) + aclMat = cv.cann.AscendMat() + aclMatDst = aclMat + aclMat.upload(npMat) + + # TODO try pass out param, not use return value. + # merge & split + self.assertTrue(np.allclose( + cv.cann.merge(cv.cann.split(npMat)).download(), npMat)) + self.assertTrue(np.allclose( + cv.cann.merge(cv.cann.split(aclMat)).download(), npMat)) + + # transpose + self.assertTrue(np.allclose( + cv.cann.transpose(npMat), cv.transpose(npMat))) + self.assertTrue(np.allclose( + cv.cann.transpose(aclMat).download(), cv.transpose(npMat))) + + # crop + w_off, h_off, crop_w, crop_h = 0, 0, 64, 64 + roi = [w_off, h_off, crop_w, crop_h] + self.assertTrue(np.allclose( + cv.cann.crop(npMat, roi).download(), npMat[w_off:crop_w, h_off:crop_h])) + self.assertTrue(np.allclose( + cv.cann.crop(aclMat, roi).download(), npMat[w_off:crop_w, h_off:crop_h])) + + # resize + dstSize = np.array([crop_w, crop_h]) + aclMat32F = cv.cann.AscendMat() + aclMat32F.upload(npMat.astype(np.float32)) + self.assertTrue(np.allclose(cv.cann.resize(npMat.astype(np.float32), dstSize, 0, 0, 3), + cv.resize(npMat.astype(np.float32), dstSize, 0, 0, 3))) + self.assertTrue(np.allclose(cv.cann.resize(aclMat32F, dstSize, 0, 0, 3).download(), + cv.resize(npMat.astype(np.float32), dstSize, 0, 0, 3))) + # flip + flipMode = [0, 1, -1] + for fMode in flipMode: + self.assertTrue(np.allclose(cv.cann.flip( + npMat, fMode), cv.flip(npMat, fMode))) + self.assertTrue(np.allclose(cv.cann.flip( + aclMat, fMode).download(), cv.flip(npMat, fMode))) + + # rotate + rotateMode = [0, 1, 2] + for rMode in rotateMode: + self.assertTrue(np.allclose(cv.cann.rotate( + npMat, rMode), cv.rotate(npMat, rMode))) + self.assertTrue(np.allclose(cv.cann.rotate( + aclMat, rMode).download(), cv.rotate(npMat, rMode))) + + # cvtColcor + cvtModeC1 = [cv.COLOR_GRAY2BGR, cv.COLOR_GRAY2BGRA] + cvtModeC3 = [cv.COLOR_BGR2GRAY, cv.COLOR_BGRA2BGR, cv.COLOR_BGR2RGBA, cv.COLOR_RGBA2BGR, + cv.COLOR_BGR2RGB, cv.COLOR_BGRA2RGBA, cv.COLOR_RGB2GRAY, cv.COLOR_BGRA2GRAY, + cv.COLOR_RGBA2GRAY, cv.COLOR_BGR2BGRA, cv.COLOR_BGR2YUV, cv.COLOR_RGB2YUV, + cv.COLOR_YUV2BGR, cv.COLOR_YUV2RGB, cv.COLOR_BGR2YCrCb, cv.COLOR_RGB2YCrCb, + cv.COLOR_YCrCb2BGR, cv.COLOR_YCrCb2RGB, cv.COLOR_BGR2XYZ, cv.COLOR_RGB2XYZ, + cv.COLOR_XYZ2BGR, cv.COLOR_XYZ2RGB,] + for cvtM in cvtModeC3: + self.assertTrue(np.allclose(cv.cann.cvtColor( + npMat, cvtM), cv.cvtColor(npMat, cvtM), 1)) + self.assertTrue(np.allclose(cv.cann.cvtColor( + aclMat, cvtM).download(), cv.cvtColor(npMat, cvtM), 1)) + + npMatC1 = (np.random.random((128, 128, 1)) * 255).astype(np.uint8) + aclMatC1 = cv.cann.AscendMat() + aclMatC1.upload(npMatC1) + for cvtM in cvtModeC1: + self.assertTrue(np.allclose(cv.cann.cvtColor( + npMatC1, cvtM), cv.cvtColor(npMatC1, cvtM), 1)) + self.assertTrue(np.allclose(cv.cann.cvtColor( + aclMatC1, cvtM).download(), cv.cvtColor(npMatC1, cvtM), 1)) + + # threshold + threshType = [cv.THRESH_BINARY, cv.THRESH_BINARY_INV, + cv.THRESH_TRUNC, cv.THRESH_TOZERO, cv.THRESH_TOZERO_INV] + for tType in threshType: + cvRet, cvThresh = cv.threshold( + npMat.astype(np.uint8), 127, 255, tType) + cannRet, cannThresh = cv.cann.threshold( + npMat.astype(np.float32), 127, 255, tType) + self.assertTrue(np.allclose(cvThresh, cannThresh)) + self.assertTrue(np.allclose(cvRet, cannRet)) + + aclMat.upload(npMat.astype(np.float32)) + cannRet, cannThresh = cv.cann.threshold( + aclMat, 127, 255, tType) + self.assertTrue(np.allclose(cvThresh, cannThresh.download())) + self.assertTrue(np.allclose(cvRet, cannRet)) + cv.cann.resetDevice() + +if __name__ == '__main__': + NewOpenCVTests.bootstrap() diff --git a/modules/cannops/perf/perf_core.cpp b/modules/cannops/perf/perf_core.cpp new file mode 100644 index 00000000000..a9d86fca881 --- /dev/null +++ b/modules/cannops/perf/perf_core.cpp @@ -0,0 +1,161 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "perf_precomp.hpp" +#include "opencv2/cann_interface.hpp" + +namespace opencv_test +{ +namespace +{ +#define TYPICAL_ASCEND_MAT_SIZES \ + Values(::perf::sz1080p, ::perf::sz2K, ::perf::sz2160p, ::perf::sz4320p) +#define DEF_PARAM_TEST(name, ...) \ + typedef ::perf::TestBaseWithParam> name + +DEF_PARAM_TEST(NPU, Size); +DEF_PARAM_TEST(CPU, Size); + +PERF_TEST_P(NPU, MERGE, TYPICAL_ASCEND_MAT_SIZES) +{ + Mat mat(GET_PARAM(0), CV_8UC1); + Mat dst; + declare.in(mat, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + AscendMat ascendMat[3]; + ascendMat[0].upload(mat); + ascendMat[1].upload(mat); + ascendMat[2].upload(mat); + + TEST_CYCLE() { cv::cann::merge(&ascendMat[0], 3, dst); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, MERGE, TYPICAL_ASCEND_MAT_SIZES) +{ + Mat mat(GET_PARAM(0), CV_8UC1); + Mat dst; + declare.in(mat, WARMUP_RNG); + Mat mats[3] = {mat, mat, mat}; + TEST_CYCLE() { cv::merge(&mats[0], 3, dst); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, SPLIT, TYPICAL_ASCEND_MAT_SIZES) +{ + Mat mat(GET_PARAM(0), CV_8UC3); + declare.in(mat, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + AscendMat ascendMat[3]; + + TEST_CYCLE() { cv::cann::split(mat, &ascendMat[0]); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, SPLIT, TYPICAL_ASCEND_MAT_SIZES) +{ + Mat mat(GET_PARAM(0), CV_8UC3); + declare.in(mat, WARMUP_RNG); + Mat mats[3] = {mat, mat, mat}; + TEST_CYCLE() { cv::split(mat, &mats[0]); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, TRANSPOSE, TYPICAL_ASCEND_MAT_SIZES) +{ + Mat mat(GET_PARAM(0), CV_8UC3); + Mat dst; + declare.in(mat, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::transpose(mat, dst); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, TRANSPOSE, TYPICAL_ASCEND_MAT_SIZES) +{ + Mat mat(GET_PARAM(0), CV_8UC3); + Mat dst; + declare.in(mat, WARMUP_RNG); + TEST_CYCLE() { cv::transpose(mat, dst); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, FLIP, TYPICAL_ASCEND_MAT_SIZES) +{ + Mat mat(GET_PARAM(0), CV_8UC3); + Mat dst; + declare.in(mat, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::flip(mat, dst, -1); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, FLIP, TYPICAL_ASCEND_MAT_SIZES) +{ + Mat mat(GET_PARAM(0), CV_8UC3); + Mat dst; + declare.in(mat, WARMUP_RNG); + TEST_CYCLE() { cv::flip(mat, dst, -1); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, ROTATE, TYPICAL_ASCEND_MAT_SIZES) +{ + Mat mat(GET_PARAM(0), CV_8UC3); + Mat dst; + declare.in(mat, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::rotate(mat, dst, 1); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, ROTATE, TYPICAL_ASCEND_MAT_SIZES) +{ + Mat mat(GET_PARAM(0), CV_8UC3); + Mat dst; + declare.in(mat, WARMUP_RNG); + TEST_CYCLE() { cv::rotate(mat, dst, 1); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, CROP, TYPICAL_ASCEND_MAT_SIZES) +{ + Mat mat(GET_PARAM(0), CV_8UC3); + Mat dst; + declare.in(mat, WARMUP_RNG); + Rect b(1, 2, 4, 4); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { AscendMat cropped_cann(mat, b); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, CROP, TYPICAL_ASCEND_MAT_SIZES) +{ + Mat mat(GET_PARAM(0), CV_8UC3); + Mat dst; + declare.in(mat, WARMUP_RNG); + Rect b(1, 2, 4, 4); + TEST_CYCLE() { Mat cropped_cv(mat, b); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, CROP_OVERLOAD, TYPICAL_ASCEND_MAT_SIZES) +{ + Mat mat(GET_PARAM(0), CV_8UC3); + Mat dst; + declare.in(mat, WARMUP_RNG); + Rect b(1, 2, 4, 4); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::crop(mat, b); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} +} // namespace +} // namespace opencv_test diff --git a/modules/cannops/perf/perf_cvtcolor.cpp b/modules/cannops/perf/perf_cvtcolor.cpp new file mode 100644 index 00000000000..c868d4fec04 --- /dev/null +++ b/modules/cannops/perf/perf_cvtcolor.cpp @@ -0,0 +1,69 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "perf_precomp.hpp" +#include "opencv2/cann_interface.hpp" + +namespace opencv_test +{ +namespace +{ + +#define CVT_COLORS_3 \ + Values(COLOR_BGR2BGRA, COLOR_BGRA2BGR, COLOR_BGR2RGBA, COLOR_RGBA2BGR, COLOR_BGR2RGB, \ + COLOR_BGRA2RGBA, COLOR_BGR2GRAY, COLOR_BGRA2GRAY, COLOR_RGBA2GRAY, COLOR_BGR2XYZ, \ + COLOR_RGB2XYZ, COLOR_XYZ2BGR, COLOR_XYZ2RGB, COLOR_BGR2YCrCb, COLOR_RGB2YCrCb, \ + COLOR_YCrCb2BGR, COLOR_YCrCb2RGB, COLOR_BGR2YUV, COLOR_RGB2YUV, COLOR_YUV2BGR, \ + COLOR_YUV2RGB) +#define CVT_COLORS_1 Values(COLOR_GRAY2BGR, COLOR_GRAY2BGRA) +#define TYPICAL_ASCEND_MAT_SIZES \ + Values(::perf::sz1080p, ::perf::sz2K) +#define DEF_PARAM_TEST(name, ...) \ + typedef ::perf::TestBaseWithParam> name + +DEF_PARAM_TEST(NPU, Size, ColorConversionCodes); +DEF_PARAM_TEST(CPU, Size, ColorConversionCodes); + +PERF_TEST_P(NPU, CVT_COLOR_3, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, CVT_COLORS_3)) +{ + Mat mat(GET_PARAM(0), CV_32FC3); + Mat dst; + declare.in(mat, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::cvtColor(mat, dst, GET_PARAM(1)); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, CVT_COLOR_3, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, CVT_COLORS_3)) +{ + Mat mat(GET_PARAM(0), CV_32FC3); + Mat dst; + declare.in(mat, WARMUP_RNG); + TEST_CYCLE() { cv::cvtColor(mat, dst, GET_PARAM(1)); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, CVT_COLOR_1, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, CVT_COLORS_1)) +{ + Mat mat(GET_PARAM(0), CV_32FC1); + Mat dst; + declare.in(mat, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::cvtColor(mat, dst, GET_PARAM(1)); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, CVT_COLOR_1, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, CVT_COLORS_1)) +{ + Mat mat(GET_PARAM(0), CV_32FC1); + Mat dst; + declare.in(mat, WARMUP_RNG); + TEST_CYCLE() { cv::cvtColor(mat, dst, GET_PARAM(1)); } + SANITY_CHECK_NOTHING(); +} + +} // namespace +} // namespace opencv_test diff --git a/modules/cannops/perf/perf_element_operations.cpp b/modules/cannops/perf/perf_element_operations.cpp new file mode 100644 index 00000000000..0612abe6085 --- /dev/null +++ b/modules/cannops/perf/perf_element_operations.cpp @@ -0,0 +1,211 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "perf_precomp.hpp" +#include "opencv2/cann_interface.hpp" + +namespace opencv_test +{ +namespace +{ + +#define ARITHM_MAT_DEPTH Values(CV_32S, CV_32SC3) +#define TYPICAL_ASCEND_MAT_SIZES \ + Values(::perf::sz1080p, ::perf::sz2K, ::perf::sz2160p, ::perf::sz4320p) +#define DEF_PARAM_TEST(name, ...) \ + typedef ::perf::TestBaseWithParam> name + +DEF_PARAM_TEST(NPU, Size, int); +DEF_PARAM_TEST(CPU, Size, int); + +PERF_TEST_P(NPU, MAT_ADD_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::add(mat1, mat2, dst, noArray(), -1); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, MAT_ADD_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + TEST_CYCLE() { cv::add(mat1, mat2, dst, noArray(), -1); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, MAT_SUB_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::subtract(mat1, mat2, dst, noArray(), -1); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, MAT_SUB_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + TEST_CYCLE() { cv::subtract(mat1, mat2, dst, noArray(), -1); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, MAT_MUL_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::multiply(mat1, mat2, dst, 1, -1); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, MAT_MUL_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + TEST_CYCLE() { cv::multiply(mat1, mat2, dst, 1, -1); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, MAT_DIV_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::divide(mat1, mat2, dst, 1, -1); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, MAT_DIV_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + TEST_CYCLE() { cv::divide(mat1, mat2, dst, 1, -1); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, MAT_BITWISE_AND_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::bitwise_and(mat1, mat2, dst, noArray()); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, MAT_BITWISE_AND_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + TEST_CYCLE() { cv::bitwise_and(mat1, mat2, dst, noArray()); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, MAT_BITWISE_OR_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::bitwise_or(mat1, mat2, dst, noArray()); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, MAT_BITWISE_OR_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + TEST_CYCLE() { cv::bitwise_or(mat1, mat2, dst, noArray()); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, MAT_BITWISE_XOR_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::bitwise_xor(mat1, mat2, dst, noArray()); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, MAT_BITWISE_XOR_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat1(GET_PARAM(0), GET_PARAM(1)); + Mat mat2(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat1, WARMUP_RNG); + declare.in(mat2, WARMUP_RNG); + TEST_CYCLE() { cv::bitwise_xor(mat1, mat2, dst, noArray()); } + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(NPU, MAT_BITWISE_NOT_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat, WARMUP_RNG); + cv::cann::setDevice(DEVICE_ID); + TEST_CYCLE() { cv::cann::bitwise_not(mat, dst, noArray()); } + cv::cann::resetDevice(); + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(CPU, MAT_BITWISE_NOT_MAT, testing::Combine(TYPICAL_ASCEND_MAT_SIZES, ARITHM_MAT_DEPTH)) +{ + Mat mat(GET_PARAM(0), GET_PARAM(1)); + Mat dst; + declare.in(mat, WARMUP_RNG); + TEST_CYCLE() { cv::bitwise_not(mat, dst, noArray()); } + SANITY_CHECK_NOTHING(); +} + +} // namespace +} // namespace opencv_test diff --git a/modules/cannops/perf/perf_main.cpp b/modules/cannops/perf/perf_main.cpp new file mode 100644 index 00000000000..33503ac4158 --- /dev/null +++ b/modules/cannops/perf/perf_main.cpp @@ -0,0 +1,23 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "perf_precomp.hpp" +#include "opencv2/cann_interface.hpp" +using namespace perf; + +class CannEnvironment : public ::testing::Environment +{ +public: + virtual ~CannEnvironment() = default; + virtual void SetUp() CV_OVERRIDE { cv::cann::initAcl(); } + virtual void TearDown() CV_OVERRIDE { cv::cann::finalizeAcl(); } +}; + +static void initTests() +{ + CannEnvironment* cannEnv = new CannEnvironment(); + ::testing::AddGlobalTestEnvironment(cannEnv); +} + +CV_PERF_TEST_MAIN("cannops", initTests()) diff --git a/modules/cannops/perf/perf_precomp.hpp b/modules/cannops/perf/perf_precomp.hpp new file mode 100644 index 00000000000..59e2fa03d7b --- /dev/null +++ b/modules/cannops/perf/perf_precomp.hpp @@ -0,0 +1,19 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef __OPENCV_PERF_PRECOMP_HPP__ +#define __OPENCV_PERF_PRECOMP_HPP__ + +#include "opencv2/ts.hpp" +#include "opencv2/ts/ts_perf.hpp" +#include "opencv2/cann.hpp" + +#define DEVICE_ID 0 + +using namespace perf; +using namespace testing; +using namespace cv; +using namespace cv::cann; + +#endif diff --git a/modules/cannops/samples/image_processing.cpp b/modules/cannops/samples/image_processing.cpp new file mode 100644 index 00000000000..9dca2176dfd --- /dev/null +++ b/modules/cannops/samples/image_processing.cpp @@ -0,0 +1,60 @@ +// 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 +#include +#include +#include + +int main(int argc, char* argv[]) +{ + cv::CommandLineParser parser(argc, argv, + "{@input|puppy.png|path to input image}" + "{@output|output.png|path to output image}" + "{help||show help}"); + parser.about("This is a sample for image processing with Ascend NPU. \n"); + if (argc != 3 || parser.has("help")) + { + parser.printMessage(); + return 0; + } + + std::string imagePath = parser.get(0); + std::string outputPath = parser.get(1); + + // read input image and generate guass noise + //! [input_noise] + cv::Mat img = cv::imread(imagePath); + // Generate gauss noise that will be added into the input image + cv::Mat gaussNoise(img.rows, img.cols, img.type()); + cv::RNG rng; + rng.fill(gaussNoise, cv::RNG::NORMAL, 0, 25); + //! [input_noise] + + // setup cann + //! [setup] + cv::cann::initAcl(); + cv::cann::setDevice(0); + //! [setup] + + //! [image-process] + cv::Mat output; + // add gauss noise to the image + cv::cann::add(img, gaussNoise, output); + // rotate the image with a certain mode (0, 1 and 2, correspond to rotation of 90, 180 and 270 + // degrees clockwise respectively) + cv::cann::rotate(output, output, 0); + // flip the image with a certain mode (0, positive and negative number, correspond to flipping + // around the x-axis, y-axis and both axes respectively) + cv::cann::flip(output, output, 0); + //! [image-process] + + cv::imwrite(outputPath, output); + + //! [tear-down-cann] + cv::cann::resetDevice(); + cv::cann::finalizeAcl(); + //! [tear-down-cann] + return 0; +} diff --git a/modules/cannops/samples/image_processing.py b/modules/cannops/samples/image_processing.py new file mode 100644 index 00000000000..dc974bdd78c --- /dev/null +++ b/modules/cannops/samples/image_processing.py @@ -0,0 +1,42 @@ +# 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. + +import numpy as np +import cv2 +import argparse + +parser = argparse.ArgumentParser(description='This is a sample for image processing with Ascend NPU.') +parser.add_argument('image', help='path to input image') +parser.add_argument('output', help='path to output image') +args = parser.parse_args() + +# read input image and generate guass noise +#! [input_noise] +img = cv2.imread(args.image) +# Generate gauss noise that will be added into the input image +gaussNoise = np.random.normal(0, 25,(img.shape[0], img.shape[1], img.shape[2])).astype(img.dtype) +#! [input_noise] + +# setup cann +#! [setup] +cv2.cann.initAcl() +cv2.cann.setDevice(0) +#! [setup] + +#! [image-process] +# add gauss noise to the image +output = cv2.cann.add(img, gaussNoise) +# rotate the image with a certain mode (0, 1 and 2, correspond to rotation of 90, 180 +# and 270 degrees clockwise respectively) +output = cv2.cann.rotate(output, 0) +# flip the image with a certain mode (0, positive and negative number, correspond to flipping +# around the x-axis, y-axis and both axes respectively) +output = cv2.cann.flip(output, 0) +#! [image-process] + +cv2.imwrite(args.output, output) + +#! [tear-down-cann] +cv2.cann.finalizeAcl() +#! [tear-down-cann] diff --git a/modules/cannops/src/ascend_mat.cpp b/modules/cannops/src/ascend_mat.cpp new file mode 100644 index 00000000000..ba17a545bb7 --- /dev/null +++ b/modules/cannops/src/ascend_mat.cpp @@ -0,0 +1,232 @@ +// 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 + +namespace +{ +class DefaultAllocator : public cv::cann::AscendMat::Allocator +{ +public: + std::shared_ptr allocate(size_t size) CV_OVERRIDE; + bool allocate(cv::cann::AscendMat* mat, int rows, int cols, size_t elemSize) CV_OVERRIDE; +}; + +std::shared_ptr DefaultAllocator::allocate(size_t size) +{ + uchar* data; + cv::cann::aclrtMallocWarpper((void**)(&data), size); + return std::shared_ptr(data, [](void* ptr) { cv::cann::aclrtFreeWarpper(ptr); }); +} + +bool DefaultAllocator::allocate(cv::cann::AscendMat* mat, int rows, int cols, size_t elemSize) +{ + mat->data = allocate(elemSize * cols * rows); + mat->step = cols * elemSize; + + return true; +} + +DefaultAllocator cannDefaultAllocator; +cv::cann::AscendMat::Allocator* g_defaultAllocator = &cannDefaultAllocator; +} // namespace + +namespace cv +{ +namespace cann +{ +AscendMat::Allocator* AscendMat::defaultAllocator() { return g_defaultAllocator; } + +void AscendMat::setDefaultAllocator(AscendMat::Allocator* allocator) +{ + CV_Assert(allocator != 0); + g_defaultAllocator = allocator; +} + +// TODO: this function is copied from matrix.cpp, which is a local symbol there and can not +// be refreneced, consider optimizing. +static int updateContinuityFlag(int flags, int dims, const int* size, const size_t* step) +{ + int i, j; + for (i = 0; i < dims; i++) + { + if (size[i] > 1) + break; + } + + uint64 t = (uint64)size[std::min(i, dims - 1)] * CV_MAT_CN(flags); + for (j = dims - 1; j > i; j--) + { + t *= size[j]; + if (step[j] * size[j] < step[j - 1]) + break; + } + + if (j <= i && t == (uint64)(int)t) + return flags | Mat::CONTINUOUS_FLAG; + return flags & ~Mat::CONTINUOUS_FLAG; +} + +void AscendMat::updateContinuityFlag() +{ + int sz[] = {rows, cols}; + size_t steps[] = {step, elemSize()}; + flags = cv::cann::updateContinuityFlag(flags, 2, sz, steps); +} + +void AscendMat::create(int _rows, int _cols, int _type) +{ + CV_DbgAssert(_rows >= 0 && _cols >= 0); + + _type &= Mat::TYPE_MASK; + + if (rows == _rows && cols == _cols && type() == _type && data) + return; + + if (_rows > 0 && _cols > 0) + { + flags = Mat::MAGIC_VAL + _type; + rows = _rows; + cols = _cols; + + const size_t esz = elemSize(); + + bool allocSuccess = allocator->allocate(this, rows, cols, esz); + + if (!allocSuccess) + { + // custom allocator fails, try default allocator + allocator = defaultAllocator(); + allocSuccess = allocator->allocate(this, rows, cols, esz); + CV_Assert(allocSuccess); + } + + if (esz * cols == step) + flags |= Mat::CONTINUOUS_FLAG; + + datastart = data.get(); + dataend = data.get() + step * (rows - 1) + cols * esz; + } +} + +void AscendMat::upload(InputArray arr) { upload(arr, AscendStream::Null()); } + +void AscendMat::upload(InputArray arr, AscendStream& stream) +{ + Mat mat = arr.getMat(); + CV_DbgAssert(!mat.empty()); + create(mat.rows, mat.cols, mat.type()); + aclrtMemcpy2dWarpper(data, 0, step, mat.data, mat.step[0], cols * elemSize(), rows, stream); +} + +void AscendMat::download(OutputArray dst) const { download(dst, AscendStream::Null()); } + +void AscendMat::download(OutputArray _dst, AscendStream& stream) const +{ + CV_DbgAssert(!empty()); + + _dst.create(size(), type()); + Mat dst = _dst.getMat(); + aclrtMemcpy2dWarpper(dst.data, dst.step[0], data, 0, step, cols * elemSize(), rows, stream); +} + +AscendMat::AscendMat(int rows_, int cols_, int type_, Scalar& s_, AscendMat::Allocator* allocator_) + : flags(0), rows(rows_), cols(cols_), step(0), datastart(0), dataend(0), allocator(allocator_) +{ + create(rows_, cols_, type_); + setTo(s_); +} + +AscendMat::AscendMat(Size size_, int type_, Scalar& s_, AscendMat::Allocator* allocator_) + : flags(0), rows(size_.height), cols(size_.width), step(0), datastart(0), dataend(0), + allocator(allocator_) +{ + create(size_.height, size_.width, type_); + setTo(s_); +} + +AscendMat::AscendMat(InputArray _m, const Rect& roi) : AscendMat(_m, roi, AscendStream::Null()) {} + +AscendMat::AscendMat(InputArray _m, const Rect& roi, AscendStream& stream) + : rows(roi.height), cols(roi.width), allocator(defaultAllocator()) +{ + AscendMat m; + m.upload(_m, stream); + step = m.step; + data = m.data; + flags = m.flags; + CV_Assert(0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && + 0 <= roi.height && roi.y + roi.height <= m.rows); + size_t esz = CV_ELEM_SIZE(flags); + size_t sizeMem = esz * roi.width * roi.height * m.channels(); + size_t offset = roi.y * m.step + roi.x * esz; + + void* dst = malloc(sizeMem); + size_t dpitch = roi.width * esz; + std::shared_ptr dstDevice = allocator->allocate(sizeMem); + aclrtMemcpy2dWarpper(dst, dpitch, data, offset, step, dpitch, roi.height, stream); + aclrtMemcpy2dWarpper(dstDevice, 0, dpitch, dst, dpitch, dpitch, roi.height, stream); + data = dstDevice; + step = dpitch; + free(dst); + updateContinuityFlag(); +} + +AscendMat& AscendMat::setTo(const Scalar& sc) { return setTo(sc, AscendStream::Null()); } + +AscendMat& AscendMat::setTo(const Scalar& sc, AscendStream& stream) +{ + size_t totalBytes = (size_t)rows * cols * elemSize(); + if (totalBytes == 0) + return *this; + + aclrtMemsetWarpper(data, 0, totalBytes, stream); + AscendMat dst(rows, cols, type()); + arithm_op(*this, sc, dst, "Add", stream); + swap(dst); + + return *this; +} + +AscendMat& AscendMat::setTo(float sc) { return setTo(sc, AscendStream::Null()); } + +AscendMat& AscendMat::setTo(float sc, AscendStream& stream) +{ + size_t totalBytes = (size_t)rows * cols * elemSize(); + if (totalBytes == 0) + return *this; + + aclrtMemsetWarpper(data, 0, totalBytes, stream); + + AscendMat dst(rows, cols, type()); + arithm_op(*this, sc, dst, "Adds", stream); + swap(dst); + + return *this; +} + +void AscendMat::convertTo(AscendMat& dst, int rtype) const +{ + convertTo(dst, rtype, AscendStream::Null()); +} + +void AscendMat::convertTo(AscendMat& dst, int _rtype, AscendStream& stream) const +{ + int cn = channels(); + dst.create(rows, cols, CV_MAKE_TYPE(_rtype, cn)); + convertTo(dst, stream); +} + +void AscendMat::convertTo(AscendMat& dst, AscendStream& stream) const +{ + OperatorRunner runner; + runner.setOp("Cast") + .addInput(*this, "x") + .addOutput(dst, "y") + .addAttr((int32_t)(getACLType(dst.depth())), "dst_type") + .run(stream); +} +} // namespace cann +} // namespace cv diff --git a/modules/cannops/src/cann_call.cpp b/modules/cannops/src/cann_call.cpp new file mode 100644 index 00000000000..3b83052ccbe --- /dev/null +++ b/modules/cannops/src/cann_call.cpp @@ -0,0 +1,524 @@ +// 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 +#include +#include "precomp.hpp" +#include "opencv2/core/private.hpp" +namespace cv +{ +namespace cann +{ +/*******************************Acl Error Checker*****************************/ +static inline void checkAclError(aclError err, const char* file, const int line, const char* func) +{ + if (ACL_SUCCESS != err) + { + const char* errMsg = aclGetRecentErrMsg(); + cv::error(cv::Error::StsError, errMsg == nullptr ? "" : errMsg, func, file, line); + } +} + +static inline void checkAclPtr(void* ptr, const char* file, const int line, const char* func) +{ + if (nullptr == ptr) + { + const char* errMsg = aclGetRecentErrMsg(); + cv::error(cv::Error::StsError, errMsg == nullptr ? "" : errMsg, func, file, line); + } +} + +#define CV_ACL_SAFE_CALL(expr) checkAclError((expr), __FILE__, __LINE__, CV_Func) +#define CV_ACL_SAFE_CALL_PTR(expr) \ + ({ \ + auto ptr = (expr); \ + checkAclPtr(ptr, __FILE__, __LINE__, CV_Func); \ + ptr; \ + }) + +/******************************Acl Runtime Warpper****************************/ +void aclrtMallocWarpper(void** data, size_t size) +{ + CV_ACL_SAFE_CALL(aclrtMalloc(data, size, ACL_MEM_MALLOC_HUGE_FIRST)); +} + +void aclrtFreeWarpper(void* data) { CV_ACL_SAFE_CALL(aclrtFree(data)); } + +void aclrtMemcpyWarpper(std::shared_ptr& dst, size_t offset, const void* src, size_t size, + AscendStream& stream) +{ + aclrtStream rawStream = AscendStreamAccessor::getStream(stream); + if (rawStream == nullptr) + CV_ACL_SAFE_CALL( + aclrtMemcpy(dst.get() + offset, size, src, size, ACL_MEMCPY_HOST_TO_DEVICE)); + else + { + CV_ACL_SAFE_CALL(aclrtMemcpyAsync(dst.get() + offset, size, src, size, + ACL_MEMCPY_HOST_TO_DEVICE, rawStream)); + if (offset == 0) + stream.addTensorHolder(dst); + } +} + +void aclrtMemcpyWarpper(void* dst, const std::shared_ptr& src, size_t offset, size_t size, + AscendStream& stream) +{ + aclrtStream rawStream = AscendStreamAccessor::getStream(stream); + if (rawStream == nullptr) + CV_ACL_SAFE_CALL( + aclrtMemcpy(dst, size, src.get() + offset, size, ACL_MEMCPY_DEVICE_TO_HOST)); + else + { + CV_ACL_SAFE_CALL(aclrtMemcpyAsync(dst, size, src.get() + offset, size, + ACL_MEMCPY_DEVICE_TO_HOST, rawStream)); + if (offset == 0) + stream.addTensorHolder(src); + } +} + +void aclrtMemcpyWarpper(std::shared_ptr& dst, size_t dstOffset, + const std::shared_ptr& src, size_t srcOffset, size_t size, + AscendStream& stream) +{ + aclrtStream rawStream = AscendStreamAccessor::getStream(stream); + if (rawStream == nullptr) + CV_ACL_SAFE_CALL(aclrtMemcpy(dst.get() + dstOffset, size, src.get() + srcOffset, size, + ACL_MEMCPY_DEVICE_TO_DEVICE)); + else + { + CV_ACL_SAFE_CALL(aclrtMemcpyAsync(dst.get() + dstOffset, size, src.get() + srcOffset, size, + ACL_MEMCPY_DEVICE_TO_DEVICE, rawStream)); + if (srcOffset == 0) + stream.addTensorHolder(src); + if (dstOffset == 0) + stream.addTensorHolder(dst); + } +} + +void aclrtMemcpy2dWarpper(std::shared_ptr& dst, size_t offset, size_t dpitch, + const void* src, size_t spitch, size_t width, size_t length, + AscendStream& stream) +{ + aclrtStream rawStream = AscendStreamAccessor::getStream(stream); + if (rawStream == nullptr) + CV_ACL_SAFE_CALL(aclrtMemcpy2d(dst.get() + offset, dpitch, src, spitch, width, length, + ACL_MEMCPY_HOST_TO_DEVICE)); + else + { + CV_ACL_SAFE_CALL(aclrtMemcpy2dAsync(dst.get() + offset, dpitch, src, spitch, width, length, + ACL_MEMCPY_HOST_TO_DEVICE, rawStream)); + stream.addTensorHolder(dst); + } +} + +void aclrtMemcpy2dWarpper(void* dst, size_t dpitch, const std::shared_ptr& src, + size_t offset, size_t spitch, size_t width, size_t length, + AscendStream& stream) +{ + aclrtStream rawStream = AscendStreamAccessor::getStream(stream); + if (rawStream == nullptr) + CV_ACL_SAFE_CALL(aclrtMemcpy2d(dst, dpitch, src.get() + offset, spitch, width, length, + ACL_MEMCPY_DEVICE_TO_HOST)); + else + { + CV_ACL_SAFE_CALL(aclrtMemcpy2dAsync(dst, dpitch, src.get() + offset, spitch, width, length, + ACL_MEMCPY_DEVICE_TO_HOST, rawStream)); + stream.addTensorHolder(src); + } +} + +void aclrtMemsetWarpper(std::shared_ptr& ptr, int32_t value, size_t count, + AscendStream& stream) +{ + aclrtStream rawStream = AscendStreamAccessor::getStream(stream); + if (rawStream == nullptr) + CV_ACL_SAFE_CALL(aclrtMemset(ptr.get(), count, value, count)); + else + { + CV_ACL_SAFE_CALL(aclrtMemsetAsync(ptr.get(), count, value, count, rawStream)); + stream.addTensorHolder(ptr); + } +} + +aclDataType getACLType(int opencvdepth) +{ + switch (opencvdepth) + { + case CV_8S: + return ACL_INT8; + case CV_16S: + return ACL_INT16; + case CV_8U: + return ACL_UINT8; + case CV_16U: + return ACL_UINT16; + case CV_32S: + return ACL_INT32; + case CV_32F: + return ACL_FLOAT; + case CV_64F: + return ACL_DOUBLE; + case CV_16F: + return ACL_FLOAT16; + default: + return ACL_DT_UNDEFINED; + } +} + +std::shared_ptr mallocAndUpload(const void* data, size_t size, AscendStream& stream, + AscendMat::Allocator* allocator) +{ + std::shared_ptr ptr = allocator->allocate(size); + aclrtStream rawStream = AscendStreamAccessor::getStream(stream); + + if (rawStream == nullptr) + CV_ACL_SAFE_CALL(aclrtMemcpy(ptr.get(), size, data, size, ACL_MEMCPY_HOST_TO_DEVICE)); + else + CV_ACL_SAFE_CALL( + aclrtMemcpyAsync(ptr.get(), size, data, size, ACL_MEMCPY_HOST_TO_DEVICE, rawStream)); + return ptr; +} + +/**************************Acl attribute preparation**************************/ + +OperatorRunner& OperatorRunner::reset() +{ + holder.clear(); + op.clear(); + for (auto desc : inputDesc_) + { + aclDestroyTensorDesc(desc); + } + for (auto desc : outputDesc_) + { + aclDestroyTensorDesc(desc); + } + for (auto buf : inputBuffers_) + { + CV_ACL_SAFE_CALL(aclDestroyDataBuffer(buf)); + } + for (auto buf : outputBuffers_) + { + CV_ACL_SAFE_CALL(aclDestroyDataBuffer(buf)); + } + if (opAttrInit) + aclopDestroyAttr(opAttr_); + inputDesc_.clear(); + outputDesc_.clear(); + inputBuffers_.clear(); + outputBuffers_.clear(); + opAttrInit = false; + return *this; +} + +OperatorRunner& OperatorRunner::setOp(const char* opName) +{ + reset(); + opAttr_ = CV_ACL_SAFE_CALL_PTR(aclopCreateAttr()); + opAttrInit = true; + op = std::string(opName); + return *this; +} + +OperatorRunner& OperatorRunner::addAttr(float value, const char* name) +{ + CV_ACL_SAFE_CALL(aclopSetAttrFloat(opAttr_, name, value)); + return *this; +} + +OperatorRunner& OperatorRunner::addAttr(const char* value, const char* name) +{ + CV_ACL_SAFE_CALL(aclopSetAttrString(opAttr_, name, value)); + return *this; +} + +OperatorRunner& OperatorRunner::addAttr(int value, const char* name) +{ + CV_ACL_SAFE_CALL(aclopSetAttrInt(opAttr_, name, value)); + return *this; +} + +OperatorRunner& OperatorRunner::addAttr(bool value, const char* name) +{ + CV_ACL_SAFE_CALL(aclopSetAttrBool(opAttr_, name, value)); + return *this; +} + +OperatorRunner& OperatorRunner::addAttr(const int64_t* value, int size, const char* name) +{ + CV_ACL_SAFE_CALL(aclopSetAttrListInt(opAttr_, name, size, value)); + return *this; +} + +OperatorRunner& OperatorRunner::addInput(AscendTensor& tensor) +{ + auto descPtr = CV_ACL_SAFE_CALL_PTR( + aclCreateTensorDesc(tensor.dtype, tensor.dims.size(), &tensor.dims[0], tensor.format)); + if (descPtr != nullptr) + { + if (tensor.name != nullptr && strlen(tensor.name) != 0) + aclSetTensorDescName(descPtr, tensor.name); + inputDesc_.push_back(descPtr); + } + auto bufPtr = CV_ACL_SAFE_CALL_PTR(aclCreateDataBuffer(tensor.data.get(), tensor.dataSize)); + if (bufPtr != nullptr) + inputBuffers_.push_back(bufPtr); + holder.insert(tensor.data); + return *this; +} + +OperatorRunner& OperatorRunner::addOutput(AscendTensor& tensor) +{ + auto descPtr = CV_ACL_SAFE_CALL_PTR( + aclCreateTensorDesc(tensor.dtype, tensor.dims.size(), &tensor.dims[0], tensor.format)); + if (descPtr != nullptr) + { + if (tensor.name != nullptr && strlen(tensor.name) != 0) + aclSetTensorDescName(descPtr, tensor.name); + outputDesc_.push_back(descPtr); + } + auto bufPtr = CV_ACL_SAFE_CALL_PTR(aclCreateDataBuffer(tensor.data.get(), tensor.dataSize)); + if (bufPtr != nullptr) + outputBuffers_.push_back(bufPtr); + holder.insert(tensor.data); + return *this; +} + +OperatorRunner& OperatorRunner::addInput(const AscendMat& mat, const char* name) +{ + AscendTensor tensor(mat, name); + return addInput(tensor); +} + +OperatorRunner& OperatorRunner::addOutput(AscendMat& mat, const char* name) +{ + AscendTensor tensor(mat, name); + return addOutput(tensor); +} + +OperatorRunner& OperatorRunner::addInput(const Scalar& sc, int type, const char* name) +{ + uchar rawData[32]; + cv::scalarToRawData(sc, rawData, type, 0); + std::shared_ptr scPtr = mallocAndUpload( + rawData, (CV_ELEM_SIZE(type)), AscendStream::Null(), AscendMat::defaultAllocator()); + + int64_t dims[] = {1, 1, 1, (CV_MAT_CN(type))}; + AscendTensor tensor(scPtr, (CV_ELEM_SIZE(type)), dims, sizeof(dims) / sizeof(dims[0]), + getACLType(CV_MAT_DEPTH(type)), name); + return addInput(tensor); +} + +OperatorRunner& OperatorRunner::run(AscendStream& stream) +{ + aclrtStream rawStream = AscendStreamAccessor::getStream(stream); + CV_ACL_SAFE_CALL(aclopCompileAndExecute(op.c_str(), inputDesc_.size(), inputDesc_.data(), + inputBuffers_.data(), outputDesc_.size(), + outputDesc_.data(), outputBuffers_.data(), opAttr_, + ACL_ENGINE_SYS, ACL_COMPILE_SYS, NULL, rawStream)); + if (rawStream == nullptr) + CV_ACL_SAFE_CALL(aclrtSynchronizeStream(rawStream)); + else + { + for (const auto& ptr : holder) + stream.addTensorHolder(ptr); + } + return *this; +} + +/********************************Ascend Tensor********************************/ + +AscendTensor::AscendTensor(std::shared_ptr _data, size_t _dataSize, int64_t* _dims, + size_t _dimSize, aclDataType _dtype, const char* _name, + aclFormat _format) + : name(_name), data(_data), dataSize(_dataSize), dtype(_dtype), format(_format) +{ + dims.assign(_dims, _dims + _dimSize); +} + +AscendTensor::AscendTensor(const AscendMat& ascendMat, const char* _name, aclFormat _format) + : name(_name), format(_format) +{ + data = ascendMat.data; + // Ascend can't process with gaps in matrix. + CV_Assert(ascendMat.isContinuous()); + dataSize = ascendMat.rows * ascendMat.cols * ascendMat.elemSize(); + + switch (_format) + { + case ACL_FORMAT_NHWC: + case ACL_FORMAT_ND: + dims.resize(4); + // Batch, default = 1. + dims[0] = 1; + // Default OpenCV image format = NHWC. + dims[1] = ascendMat.rows; + dims[2] = ascendMat.cols; + dims[3] = ascendMat.channels(); + break; + case ACL_FORMAT_NCHW: + dims.resize(4); + dims[0] = 1; + dims[1] = ascendMat.channels(); + dims[2] = ascendMat.rows; + dims[3] = ascendMat.cols; + break; + default: + CV_Error(Error::StsBadArg, "Unknown/unsupported matrix format"); + } + + dtype = getACLType(ascendMat.depth()); +} + +/**********************************Device*************************************/ +void setDevice(int device_id) +{ + aclrtContext context; + CV_ACL_SAFE_CALL(aclrtSetDevice(device_id)); + CV_ACL_SAFE_CALL(aclrtCreateContext(&context, device_id)); +} + +void resetDevice() { CV_ACL_SAFE_CALL(aclrtResetDevice(getDevice())); } + +int32_t getDevice() +{ + int32_t deviceId; + CV_ACL_SAFE_CALL(aclrtGetDevice(&deviceId)); + return deviceId; +} + +void initAcl() { CV_ACL_SAFE_CALL(aclInit(nullptr)); } + +void finalizeAcl() { CV_ACL_SAFE_CALL(aclFinalize()); } + +class DefaultDeviceInitializer +{ +public: + DefaultDeviceInitializer(); + ~DefaultDeviceInitializer(); + + AscendStream& getNullAscendStream(int deviceId); + +private: + std::vector> streams_; + Mutex streams_mtx_; +}; + +DefaultDeviceInitializer::DefaultDeviceInitializer() {} + +DefaultDeviceInitializer::~DefaultDeviceInitializer() { streams_.clear(); } + +AscendStream& DefaultDeviceInitializer::getNullAscendStream(int deviceId) +{ + AutoLock lock(streams_mtx_); + + if (streams_.empty()) + { + uint32_t deviceCount; + CV_ACL_SAFE_CALL(aclrtGetDeviceCount(&deviceCount)); + + if (deviceCount > 0) + streams_.resize(deviceCount); + } + + CV_DbgAssert(deviceId >= 0 && deviceId < static_cast(streams_.size())); + + if (streams_[deviceId].empty()) + { + aclrtStream stream = nullptr; + Ptr impl = makePtr(stream); + streams_[deviceId] = Ptr(new AscendStream(impl)); + } + + return *streams_[deviceId]; +} + +DefaultDeviceInitializer initializer; + +/***********************************Event*************************************/ +AscendEvent::Impl::Impl() : event(nullptr), ownEvent(true) +{ + CV_ACL_SAFE_CALL(aclrtCreateEvent(&event)); +} + +AscendEvent::Impl::Impl(aclrtEvent e) : event(e), ownEvent(false) {} + +AscendEvent::Impl::~Impl() +{ + if (event && ownEvent) + { + CV_ACL_SAFE_CALL(aclrtDestroyEvent(event)); + } +} + +aclrtEvent AscendEventAccessor::getEvent(const AscendEvent& event) { return event.impl_->event; } + +AscendEvent AscendEventAccessor::wrapEvent(aclrtEvent event) +{ + return AscendEvent(makePtr(event)); +} + +AscendEvent::AscendEvent() { impl_ = makePtr(); } + +void AscendEvent::record(AscendStream& stream) +{ + CV_ACL_SAFE_CALL(aclrtRecordEvent(impl_->event, AscendStreamAccessor::getStream(stream))); +} + +void AscendEvent::waitForComplete() const { CV_ACL_SAFE_CALL(aclrtSynchronizeEvent(impl_->event)); } + +/************************************Stream***********************************/ +void AscendStream::Impl::AddTensorHolder(const std::shared_ptr& tensorData) +{ + tensorHolders.insert(tensorData); +} + +AscendStream::Impl::Impl() : stream(nullptr), ownStream(true) +{ + CV_ACL_SAFE_CALL(aclrtCreateStream(&stream)); +} + +AscendStream::Impl::Impl(aclrtStream s) : stream(s), ownStream(false) {} + +aclrtStream AscendStreamAccessor::getStream(const AscendStream& stream) +{ + return stream.impl_->stream; +} + +AscendStream AscendStreamAccessor::wrapStream(aclrtStream stream) +{ + return AscendStream(makePtr(stream)); +} + +AscendStream wrapStream(size_t AscendStreamAddress) +{ + return AscendStreamAccessor::wrapStream(reinterpret_cast(AscendStreamAddress)); +} + +AscendStream::AscendStream() { impl_ = makePtr(); } + +void AscendStream::waitForCompletion() +{ + CV_ACL_SAFE_CALL(aclrtSynchronizeStream(impl_->stream)); + impl_->tensorHolders.clear(); +} + +void AscendStream::waitAscendEvent(const AscendEvent& event) +{ + CV_ACL_SAFE_CALL(aclrtStreamWaitEvent(impl_->stream, AscendEventAccessor::getEvent(event))); +} + +AscendStream& AscendStream::Null() +{ + const uint32_t deviceId = getDevice(); + return initializer.getNullAscendStream(deviceId); +} + +void AscendStream::addTensorHolder(const std::shared_ptr& holder) +{ + impl_->AddTensorHolder(holder); +} + +} // namespace cann +} // namespace cv diff --git a/modules/cannops/src/color.cpp b/modules/cannops/src/color.cpp new file mode 100644 index 00000000000..f08a785e576 --- /dev/null +++ b/modules/cannops/src/color.cpp @@ -0,0 +1,777 @@ +// 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" + +namespace cv +{ +namespace cann +{ +// Integer type images will have a loss of accuracy during calculation, so they must be converted to +// float before calculation. +static AscendMat convertTo(const AscendMat& src, int dtype, AscendStream& stream) +{ + AscendMat ret; + if (src.depth() != dtype) + src.convertTo(ret, dtype, stream); + else + ret = src; + return ret; +} + +static void convertBack(const AscendMat& src, AscendMat& dst, AscendStream& stream) +{ + if (src.depth() != dst.depth()) + src.convertTo(dst, stream); +} + +//! Set alpha channel to a Mat. +static void matAlphaSet(AscendMat& mat, int dtype, AscendStream& stream) +{ + if (dtype < 0) + dtype = mat.depth(); + + if (mat.depth() == CV_8U || mat.depth() == CV_16U) + { + size_t size = mat.rows * mat.step; + aclrtMemsetWarpper(mat.data, 255, size, stream); + } + else + { + if (dtype == CV_32F) + mat.setTo(1.0f, stream); + else + mat.setTo((dtype == CV_8U ? (1 << 8) : (1 << 16)) - 1, stream); + } +} + +inline void checkImg(const AscendMat& mat) +{ + int depth = mat.depth(); + CV_Assert(!mat.empty()); + CV_Assert(depth == CV_8U || depth == CV_16U || depth == CV_32F); +} + +inline void cvtBGRtoBGR(const AscendMat& src, AscendMat& dst, int dcn, bool swapBlue, + AscendStream& stream) +{ + checkImg(src); + CV_Assert(src.channels() == 3 || src.channels() == 4); + + AscendMat matChannels[4]; + split(src, matChannels, stream); + + if (swapBlue) + std::swap(matChannels[0], matChannels[2]); + + if (dcn == 4 && src.channels() != 4) + { + AscendMat& alpha = matChannels[3]; + alpha.create(src.rows, src.cols, CV_MAKE_TYPE(src.depth(), 1)); + matAlphaSet(alpha, -1, stream); + } + + merge(matChannels, dcn, dst, stream); +} + +inline void cvtBGRtoBGR(InputArray& _src, OutputArray& _dst, int dcn, bool swapBlue, + AscendStream& stream) +{ + AscendMat src, dst; + src.upload(_src, stream); + cvtBGRtoBGR(src, dst, dcn, swapBlue, stream); + dst.download(_dst, stream); +} + +// TODO duplicated code +static const float B2YF = 0.114f; +static const float G2YF = 0.587f; +static const float R2YF = 0.299f; + +inline void cvtBGRtoGray(const AscendMat& src, AscendMat& dst, int, bool swapBlue, + AscendStream& stream) +{ + checkImg(src); + CV_Assert(src.channels() == 3 || src.channels() == 4); + + float coeffs[] = {B2YF, G2YF, R2YF}; + dst.create(src.rows, src.cols, CV_MAKE_TYPE(src.depth(), 1)); + AscendMat formatedSrc = convertTo(src, CV_32F, stream); + AscendMat formatedDst = convertTo(dst, CV_32F, stream); + + // For RGB + if (swapBlue) + std::swap(coeffs[0], coeffs[2]); + + Scalar sc = {coeffs[0], coeffs[1], coeffs[2], 0}; + AscendMat grayRet(formatedSrc.rows, formatedSrc.cols, formatedSrc.type()); + arithm_op(formatedSrc, sc, grayRet, "Mul", stream); + + AscendMat matChannels[4]; + split(grayRet, matChannels, stream); + + OperatorRunner runner; + runner.setOp("AddN") + .addInput(matChannels[0], "x0") + .addInput(matChannels[1], "x1") + .addInput(matChannels[2], "x2") + .addOutput(formatedDst, "y") + .addAttr(3, "N") + .run(stream); + + convertBack(formatedDst, dst, stream); +} + +inline void cvtBGRtoGray(const InputArray& _src, OutputArray& _dst, int, bool swapBlue, + AscendStream& stream) +{ + AscendMat src, dst; + src.upload(_src, stream); + cvtBGRtoGray(src, dst, 0, swapBlue, stream); + dst.download(_dst, stream); +} + +inline void cvtGraytoBGR(const AscendMat& src, AscendMat& dst, int dcn, bool, AscendStream& stream) +{ + checkImg(src); + CV_Assert(src.channels() == 1); + + AscendMat matChannels[4]; + for (int i = 0; i < 3; i++) + matChannels[i] = src; + + if (dcn == 4) + { + AscendMat& alpha = matChannels[3]; + alpha.create(src.rows, src.cols, CV_MAKE_TYPE(src.depth(), 1)); + matAlphaSet(alpha, -1, stream); + } + + merge(matChannels, dcn, dst, stream); +} + +inline void cvtGraytoBGR(const InputArray& _src, OutputArray& _dst, int dcn, bool, + AscendStream& stream) +{ + AscendMat src, dst; + src.upload(_src, stream); + cvtGraytoBGR(src, dst, dcn, false, stream); + dst.download(_dst, stream); +} + +static const float RGB2XYZ_D65[] = {0.412453, 0.357580, 0.180423, 0.212671, 0.715160, + 0.072169, 0.019334, 0.119193, 0.950227}; + +static const float XYZ2RGB_D65[] = {3.240479, -1.53715, -0.498535, -0.969256, 1.875991, + 0.041556, 0.055648, -0.204043, 1.057311}; + +inline void matMulRGB(const AscendMat& src, AscendMat& dst, float* matrix, AscendStream& stream) +{ + checkImg(src); + CV_Assert(src.channels() == 3); + + dst.create(src.rows, src.cols, src.type()); + AscendMat formatedSrc = convertTo(src, CV_32F, stream); + AscendMat formatedDst = convertTo(dst, CV_32F, stream); + + int64_t dims[] = {3, 3}; + OperatorRunner runner; + runner.setOp("BatchMatMulV2") + .addInput(formatedSrc, "x1") + .addInput(matrix, dims, 2, getACLType(CV_32F), "x2") + .addOutput(formatedDst, "y") + .addAttr(false, "adj_x1") + .addAttr(true, "adj_x2") + .run(stream); + + if (src.depth() != CV_32F) + { + AscendMat thresholdTempMat(formatedSrc.size(), formatedSrc.type()); + uint16_t thresh = (src.depth() == CV_8U ? (1 << 8) : (1 << 16)) - 1; + threshold(formatedDst, thresholdTempMat, thresh, 0, 2 /*THRESH_TRUNC*/, stream); + threshold(thresholdTempMat, formatedDst, 0, 0, 3 /*THRESH_TOZERO*/, stream); + } + + convertBack(formatedDst, dst, stream); +} + +// TODO: should deal with overflow. set 255 instead of cut off. +inline void cvtBGRtoXYZ(const AscendMat& src, AscendMat& dst, int, bool swapBlue, + AscendStream& stream) +{ + float coeffs[9]; + memcpy(coeffs, RGB2XYZ_D65, 9 * sizeof(float)); + if (!swapBlue) + { + std::swap(coeffs[0], coeffs[2]); + std::swap(coeffs[3], coeffs[5]); + std::swap(coeffs[6], coeffs[8]); + } + matMulRGB(src, dst, coeffs, stream); +} + +inline void cvtBGRtoXYZ(const InputArray& _src, OutputArray& _dst, int, bool swapBlue, + AscendStream& stream) +{ + AscendMat src, dst; + src.upload(_src, stream); + cvtBGRtoXYZ(src, dst, 0, swapBlue, stream); + dst.download(_dst, stream); +} + +inline void cvtXYZtoBGR(const AscendMat& src, AscendMat& dst, int dcn, bool swapBlue, + AscendStream& stream) +{ + float coeffs[9]; + memcpy(coeffs, XYZ2RGB_D65, 9 * sizeof(float)); + if (!swapBlue) + { + std::swap(coeffs[0], coeffs[6]); + std::swap(coeffs[1], coeffs[7]); + std::swap(coeffs[2], coeffs[8]); + } + + if (dcn == 4) + { + AscendMat tempMat[2]; + matMulRGB(src, tempMat[0], coeffs, stream); + tempMat[1].create(tempMat[0].rows, tempMat[0].cols, CV_MAKE_TYPE(tempMat[0].depth(), 1)); + matAlphaSet(tempMat[1], -1, stream); + merge(tempMat, 2, dst, stream); + } + else + matMulRGB(src, dst, coeffs, stream); +} + +inline void cvtXYZtoBGR(const InputArray& _src, OutputArray& _dst, int dcn, bool swapBlue, + AscendStream& stream) +{ + AscendMat src, dst; + src.upload(_src, stream); + cvtXYZtoBGR(src, dst, dcn, swapBlue, stream); + dst.download(_dst, stream); +} + +// TODO duplicated code +static const float YCRF = 0.713f; +static const float YCBF = 0.564f; +static const float R2VF = 0.877f; +static const float B2UF = 0.492f; +inline void cvtBGRtoYCrCb(const AscendMat& src, AscendMat& dst, float* coeffs, bool swapBlue, + bool yuvOrder, AscendStream& stream) +{ + checkImg(src); + CV_Assert(src.channels() == 3); + + int buleIdx = swapBlue ? 2 : 0; + int depth = src.depth(); + float delta = (depth == CV_8U) ? 128 : ((depth == CV_16U) ? 32768 : 0.5); + + dst.create(src.rows, src.cols, src.type()); + AscendMat formatedSrc = convertTo(src, CV_32F, stream); + AscendMat formatedDst = convertTo(dst, CV_32F, stream); + + AscendMat YCrCb[3], RGB[3]; + split(formatedSrc, RGB, stream); + cvtBGRtoGray(formatedSrc, YCrCb[0], 1, swapBlue, stream); + YCrCb[1].create(YCrCb[0].rows, YCrCb[0].cols, YCrCb[0].type()); + YCrCb[2].create(YCrCb[0].rows, YCrCb[0].cols, YCrCb[0].type()); + + AscendMat tempMat1(formatedSrc.size(), CV_MAKE_TYPE(formatedSrc.depth(), 1)), + tempMat2(formatedSrc.size(), CV_MAKE_TYPE(formatedSrc.depth(), 1)); + + arithm_op(RGB[buleIdx ^ 2], YCrCb[0], tempMat1, "Sub", stream); + arithm_op(tempMat1, coeffs[0], tempMat2, "Muls", stream); + arithm_op(tempMat2, delta, YCrCb[1], "Adds", stream); + + arithm_op(RGB[buleIdx], YCrCb[0], tempMat1, "Sub", stream); + arithm_op(tempMat1, coeffs[1], tempMat2, "Muls", stream); + arithm_op(tempMat2, delta, YCrCb[2], "Adds", stream); + + if (yuvOrder) + std::swap(YCrCb[1], YCrCb[2]); + + merge(YCrCb, 3, formatedDst, stream); + if (src.depth() != CV_32F) + { + AscendMat thresholdTempMat(formatedSrc.size(), formatedSrc.type()); + uint16_t thresh = (src.depth() == CV_8U ? (1 << 8) : (1 << 16)) - 1; + threshold(formatedDst, thresholdTempMat, thresh, 0, 2 /*THRESH_TRUNC*/, stream); + threshold(thresholdTempMat, formatedDst, 0, 0, 3 /*THRESH_TOZERO*/, stream); + } + + convertBack(formatedDst, dst, stream); +} + +inline void cvtBGRtoYCrCb(const InputArray& _src, OutputArray& _dst, float* coeffs, bool swapBlue, + bool yuvOrder, AscendStream& stream) +{ + AscendMat src, dst; + src.upload(_src, stream); + cvtBGRtoYCrCb(src, dst, coeffs, swapBlue, yuvOrder, stream); + dst.download(_dst, stream); +} + +static const float CR2RF = 1.403f; +static const float CR2GF = -0.714f; +static const float CB2GF = -0.344f; +static const float CB2BF = 1.773f; + +static const float V2RF = 1.140f; +static const float V2GF = -0.581f; +static const float U2GF = -0.395f; +static const float U2BF = 2.032f; + +inline void cvtYCrCbtoBGR(const AscendMat& src, AscendMat& dst, int dcn, float* coeffs, + bool swapBlue, bool yuvOrder, AscendStream& stream) +{ + checkImg(src); + CV_Assert(src.channels() == 3); + + int buleIdx = swapBlue ? 2 : 0; + int depth = src.depth(); + float delta = (depth == CV_8U) ? 128 : ((depth == CV_16U) ? 32768 : 0.5); + + dst.create(src.rows, src.cols, CV_MAKE_TYPE(src.depth(), dcn)); + AscendMat formatedSrc = convertTo(src, CV_32F, stream); + AscendMat formatedDst = convertTo(dst, CV_32F, stream); + + AscendMat YCrCb[3], RGB[4]; + split(formatedSrc, YCrCb, stream); + if (yuvOrder) + std::swap(YCrCb[1], YCrCb[2]); + + RGB[0].create(formatedSrc.rows, formatedSrc.cols, CV_MAKE_TYPE(formatedSrc.depth(), 1)); + RGB[1].create(formatedSrc.rows, formatedSrc.cols, CV_MAKE_TYPE(formatedSrc.depth(), 1)); + RGB[2].create(formatedSrc.rows, formatedSrc.cols, CV_MAKE_TYPE(formatedSrc.depth(), 1)); + AscendMat tempMat1(formatedSrc.size(), CV_MAKE_TYPE(formatedSrc.depth(), 1)), + tempMat2(formatedSrc.size(), CV_MAKE_TYPE(formatedSrc.depth(), 1)), + CbSubDelta(formatedSrc.size(), CV_MAKE_TYPE(formatedSrc.depth(), 1)), + CrSubDelta(formatedSrc.size(), CV_MAKE_TYPE(formatedSrc.depth(), 1)); + + arithm_op(YCrCb[1], (0.0f - delta), CrSubDelta, "Adds", stream); + arithm_op(YCrCb[2], (0.0f - delta), CbSubDelta, "Adds", stream); + arithm_op(CrSubDelta, coeffs[0], tempMat1, "Muls", stream); + arithm_op(YCrCb[0], tempMat1, RGB[buleIdx ^ 2], "Add", stream); + + arithm_op(CrSubDelta, coeffs[1], tempMat1, "Muls", stream); + arithm_op(YCrCb[0], tempMat1, tempMat2, "Add", stream); + arithm_op(CbSubDelta, coeffs[2], tempMat1, "Muls", stream); + arithm_op(tempMat2, tempMat1, RGB[1], "Add", stream); + + arithm_op(CbSubDelta, coeffs[3], tempMat1, "Muls", stream); + arithm_op(YCrCb[0], tempMat1, RGB[buleIdx], "Add", stream); + + if (dcn == 4) + { + RGB[3].create(RGB[0].rows, RGB[0].cols, RGB[0].type()); + matAlphaSet(RGB[3], src.depth(), stream); + } + + merge(RGB, dcn, formatedDst, stream); + if (src.depth() != CV_32F) + { + AscendMat thresholdTempMat(formatedSrc.size(), CV_MAKE_TYPE(formatedSrc.depth(), dcn)); + uint16_t thresh = (src.depth() == CV_8U ? (1 << 8) : (1 << 16)) - 1; + threshold(formatedDst, thresholdTempMat, thresh, 0, 2 /*THRESH_TRUNC*/, stream); + threshold(thresholdTempMat, formatedDst, 0, 0, 3 /*THRESH_TOZERO*/, stream); + } + + convertBack(formatedDst, dst, stream); +} + +inline void cvtYCrCbtoBGR(const InputArray& _src, OutputArray& _dst, int dcn, float* coeffs, + bool swapBlue, bool yuvOrder, AscendStream& stream) +{ + AscendMat src, dst; + src.upload(_src, stream); + cvtYCrCbtoBGR(src, dst, dcn, coeffs, swapBlue, yuvOrder, stream); + dst.download(_dst, stream); +} + +// The input may be Input/OutputArray or AscendMat. Use templates to reduce duplicate code. +template +inline void BGR2BGRA(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtBGRtoBGR(src, dst, 4, false, stream); +} + +template +inline void BGRA2BGR(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtBGRtoBGR(src, dst, 3, false, stream); +} + +template +inline void BGR2RGBA(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtBGRtoBGR(src, dst, 4, true, stream); +} + +template +inline void RGBA2BGR(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtBGRtoBGR(src, dst, 3, true, stream); +} + +template +inline void BGR2RGB(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtBGRtoBGR(src, dst, 3, true, stream); +} + +template +inline void BGRA2RGBA(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtBGRtoBGR(src, dst, 4, true, stream); +} + +template +inline void BGR2GRAY(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtBGRtoGray(src, dst, 1, false, stream); +} + +template +inline void RGB2GRAY(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtBGRtoGray(src, dst, 1, true, stream); +} + +template +inline void GRAY2BGR(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtGraytoBGR(src, dst, 3, false, stream); +} + +template +inline void GRAY2BGRA(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtGraytoBGR(src, dst, 4, false, stream); +} + +template +inline void BGRA2GRAY(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtBGRtoGray(src, dst, 1, false, stream); +} + +template +inline void RGBA2GRAY(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtBGRtoGray(src, dst, 1, true, stream); +} + +template +inline void BGR2XYZ(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtBGRtoXYZ(src, dst, 3, false, stream); +} + +template +inline void RGB2XYZ(const SRC& src, DST& dst, int, AscendStream& stream) +{ + cvtBGRtoXYZ(src, dst, 3, true, stream); +} + +template +inline void XYZ2BGR(const SRC& src, DST& dst, int dcn, AscendStream& stream) +{ + if (dcn <= 0) + dcn = 3; + cvtXYZtoBGR(src, dst, dcn, false, stream); +} + +template +inline void XYZ2RGB(const SRC& src, DST& dst, int dcn, AscendStream& stream) +{ + if (dcn <= 0) + dcn = 3; + cvtXYZtoBGR(src, dst, dcn, true, stream); +} + +template +inline void BGR2YCrCb(const SRC& src, DST& dst, int, AscendStream& stream) +{ + float coeffs[2]; + coeffs[0] = YCRF; + coeffs[1] = YCBF; + cvtBGRtoYCrCb(src, dst, coeffs, false, false, stream); +} + +template +inline void RGB2YCrCb(const SRC& src, DST& dst, int, AscendStream& stream) +{ + float coeffs[2]; + coeffs[0] = YCRF; + coeffs[1] = YCBF; + cvtBGRtoYCrCb(src, dst, coeffs, true, false, stream); +} + +template +inline void YCrCb2BGR(const SRC& src, DST& dst, int dcn, AscendStream& stream) +{ + float coeffs[4]; + coeffs[0] = CR2RF; + coeffs[1] = CR2GF; + coeffs[2] = CB2GF; + coeffs[3] = CB2BF; + if (dcn <= 0) + dcn = 3; + cvtYCrCbtoBGR(src, dst, dcn, coeffs, false, false, stream); +} + +template +inline void YCrCb2RGB(const SRC& src, DST& dst, int dcn, AscendStream& stream) +{ + float coeffs[4]; + coeffs[0] = CR2RF; + coeffs[1] = CR2GF; + coeffs[2] = CB2GF; + coeffs[3] = CB2BF; + if (dcn <= 0) + dcn = 3; + cvtYCrCbtoBGR(src, dst, dcn, coeffs, true, false, stream); +} + +template +inline void BGR2YUV(const SRC& src, DST& dst, int, AscendStream& stream) +{ + float coeffs[2]; + coeffs[0] = R2VF; + coeffs[1] = B2UF; + cvtBGRtoYCrCb(src, dst, coeffs, false, true, stream); +} + +template +inline void RGB2YUV(const SRC& src, DST& dst, int, AscendStream& stream) +{ + float coeffs[2]; + coeffs[0] = R2VF; + coeffs[1] = B2UF; + cvtBGRtoYCrCb(src, dst, coeffs, true, true, stream); +} + +template +inline void YUV2BGR(const SRC& src, DST& dst, int dcn, AscendStream& stream) +{ + float coeffs[4]; + coeffs[0] = V2RF; + coeffs[1] = V2GF; + coeffs[2] = U2GF; + coeffs[3] = U2BF; + if (dcn <= 0) + dcn = 3; + cvtYCrCbtoBGR(src, dst, dcn, coeffs, false, true, stream); +} + +template +inline void YUV2RGB(const SRC& src, DST& dst, int dcn, AscendStream& stream) +{ + float coeffs[4]; + coeffs[0] = V2RF; + coeffs[1] = V2GF; + coeffs[2] = U2GF; + coeffs[3] = U2BF; + if (dcn <= 0) + dcn = 3; + cvtYCrCbtoBGR(src, dst, dcn, coeffs, true, true, stream); +} + +template +void cvtColorDo(const SRC& src, DST& dst, int code, int dcn, AscendStream& stream) +{ + typedef void (*func_t)(const SRC& src, DST& dst, int dcn, AscendStream& stream); + static const func_t funcs[] = { + BGR2BGRA, // CV_BGR2BGRA =0 + BGRA2BGR, // CV_BGRA2BGR =1 + BGR2RGBA, // CV_BGR2RGBA =2 + RGBA2BGR, // CV_RGBA2BGR =3 + BGR2RGB, // CV_BGR2RGB =4 + BGRA2RGBA, // CV_BGRA2RGBA =5 + + BGR2GRAY, // CV_BGR2GRAY =6 + RGB2GRAY, // CV_RGB2GRAY =7 + GRAY2BGR, // CV_GRAY2BGR =8 + GRAY2BGRA, // CV_GRAY2BGRA =9 + BGRA2GRAY, // CV_BGRA2GRAY =10 + RGBA2GRAY, // CV_RGBA2GRAY =11 + + 0, // CV_BGR2BGR565 =12 + 0, // CV_RGB2BGR565 =13 + 0, // CV_BGR5652BGR =14 + 0, // CV_BGR5652RGB =15 + 0, // CV_BGRA2BGR565 =16 + 0, // CV_RGBA2BGR565 =17 + 0, // CV_BGR5652BGRA =18 + 0, // CV_BGR5652RGBA =19 + + 0, // CV_GRAY2BGR565 =20 + 0, // CV_BGR5652GRAY =21 + + 0, // CV_BGR2BGR555 =22 + 0, // CV_RGB2BGR555 =23 + 0, // CV_BGR5552BGR =24 + 0, // CV_BGR5552RGB =25 + 0, // CV_BGRA2BGR555 =26 + 0, // CV_RGBA2BGR555 =27 + 0, // CV_BGR5552BGRA =28 + 0, // CV_BGR5552RGBA =29 + + 0, // CV_GRAY2BGR555 =30 + 0, // CV_BGR5552GRAY =31 + + BGR2XYZ, // CV_BGR2XYZ =32 + RGB2XYZ, // CV_RGB2XYZ =33 + XYZ2BGR, // CV_XYZ2BGR =34 + XYZ2RGB, // CV_XYZ2RGB =35 + + BGR2YCrCb, // CV_BGR2YCrCb =36 + RGB2YCrCb, // CV_RGB2YCrCb =37 + YCrCb2BGR, // CV_YCrCb2BGR =38 + YCrCb2RGB, // CV_YCrCb2RGB =39 + + 0, // CV_BGR2HSV =40 + 0, // CV_RGB2HSV =41 + + 0, // =42 + 0, // =43 + + 0, // CV_BGR2Lab =44 + 0, // CV_RGB2Lab =45 + + 0, // CV_BayerBG2BGR =46 + 0, // CV_BayeRGB2BGR =47 + 0, // CV_BayerRG2BGR =48 + 0, // CV_BayerGR2BGR =49 + + 0, // CV_BGR2Luv =50 + 0, // CV_RGB2Luv =51 + + 0, // CV_BGR2HLS =52 + 0, // CV_RGB2HLS =53 + + 0, // CV_HSV2BGR =54 + 0, // CV_HSV2RGB =55 + + 0, // CV_Lab2BGR =56 + 0, // CV_Lab2RGB =57 + 0, // CV_Luv2BGR =58 + 0, // CV_Luv2RGB =59 + + 0, // CV_HLS2BGR =60 + 0, // CV_HLS2RGB =61 + + 0, // CV_BayerBG2BGR_VNG =62 + 0, // CV_BayeRGB2BGR_VNG =63 + 0, // CV_BayerRG2BGR_VNG =64 + 0, // CV_BayerGR2BGR_VNG =65 + + 0, // CV_BGR2HSV_FULL = 66 + 0, // CV_RGB2HSV_FULL = 67 + 0, // CV_BGR2HLS_FULL = 68 + 0, // CV_RGB2HLS_FULL = 69 + + 0, // CV_HSV2BGR_FULL = 70 + 0, // CV_HSV2RGB_FULL = 71 + 0, // CV_HLS2BGR_FULL = 72 + 0, // CV_HLS2RGB_FULL = 73 + + 0, // CV_LBGR2Lab = 74 + 0, // CV_LRGB2Lab = 75 + 0, // CV_LBGR2Luv = 76 + 0, // CV_LRGB2Luv = 77 + + 0, // CV_Lab2LBGR = 78 + 0, // CV_Lab2LRGB = 79 + 0, // CV_Luv2LBGR = 80 + 0, // CV_Luv2LRGB = 81 + + BGR2YUV, // CV_BGR2YUV = 82 + RGB2YUV, // CV_RGB2YUV = 83 + YUV2BGR, // CV_YUV2BGR = 84 + YUV2RGB, // CV_YUV2RGB = 85 + + 0, // CV_BayerBG2GRAY = 86 + 0, // CV_BayeRGB2GRAY = 87 + 0, // CV_BayerRG2GRAY = 88 + 0, // CV_BayerGR2GRAY = 89 + + // YUV 4:2:0 formats family + 0, // CV_YUV2RGB_NV12 = 90, + 0, // CV_YUV2BGR_NV12 = 91, + 0, // CV_YUV2RGB_NV21 = 92, + 0, // CV_YUV2BGR_NV21 = 93, + + 0, // CV_YUV2RGBA_NV12 = 94, + 0, // CV_YUV2BGRA_NV12 = 95, + 0, // CV_YUV2RGBA_NV21 = 96, + 0, // CV_YUV2BGRA_NV21 = 97, + + 0, // CV_YUV2RGB_YV12 = 98, + 0, // CV_YUV2BGR_YV12 = 99, + 0, // CV_YUV2RGB_IYUV = 100, + 0, // CV_YUV2BGR_IYUV = 101, + + 0, // CV_YUV2RGBA_YV12 = 102, + 0, // CV_YUV2BGRA_YV12 = 103, + 0, // CV_YUV2RGBA_IYUV = 104, + 0, // CV_YUV2BGRA_IYUV = 105, + + 0, // CV_YUV2GRAY_420 = 106, + + // YUV 4:2:2 formats family + 0, // CV_YUV2RGB_UYVY = 107, + 0, // CV_YUV2BGR_UYVY = 108, + 0, // //CV_YUV2RGB_VYUY = 109, + 0, // //CV_YUV2BGR_VYUY = 110, + + 0, // CV_YUV2RGBA_UYVY = 111, + 0, // CV_YUV2BGRA_UYVY = 112, + 0, // //CV_YUV2RGBA_VYUY = 113, + 0, // //CV_YUV2BGRA_VYUY = 114, + + 0, // CV_YUV2RGB_YUY2 = 115, + 0, // CV_YUV2BGR_YUY2 = 116, + 0, // CV_YUV2RGB_YVYU = 117, + 0, // CV_YUV2BGR_YVYU = 118, + + 0, // CV_YUV2RGBA_YUY2 = 119, + 0, // CV_YUV2BGRA_YUY2 = 120, + 0, // CV_YUV2RGBA_YVYU = 121, + 0, // CV_YUV2BGRA_YVYU = 122, + + 0, // CV_YUV2GRAY_UYVY = 123, + 0, // CV_YUV2GRAY_YUY2 = 124, + + // alpha premultiplication + 0, // CV_RGBA2mRGBA = 125, + 0, // CV_mRGBA2RGBA = 126, + + 0, // CV_COLORCVT_MAX = 127 + }; + + CV_Assert(code < 128); + + func_t func = funcs[code]; + + if (func == 0) + CV_Error(Error::StsBadFlag, "Unknown/unsupported color conversion code"); + + func(src, dst, dcn, stream); +} + +// Instantiate templates to avoid confusion in python code generation +void cvtColor(const InputArray src, OutputArray dst, int code, int dcn, AscendStream& stream) +{ + cvtColorDo(src, dst, code, dcn, stream); +} + +void cvtColor(const AscendMat& src, AscendMat& dst, int code, int dcn, AscendStream& stream) +{ + cvtColorDo(src, dst, code, dcn, stream); +} + +} // namespace cann +} // namespace cv \ No newline at end of file diff --git a/modules/cannops/src/core.cpp b/modules/cannops/src/core.cpp new file mode 100644 index 00000000000..7d328915ef9 --- /dev/null +++ b/modules/cannops/src/core.cpp @@ -0,0 +1,310 @@ +// 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" + +namespace cv +{ +namespace cann +{ +// Transform data type from one to another. eg. from NCHW to NHWC. +void transData(const AscendMat& src, AscendMat& dst, const char* from, const char* to, + AscendStream& stream) +{ + OperatorRunner runner; + runner.setOp("TransData") + .addInput(src, "src") + .addOutput(dst, "dst") + .addAttr(from, "src_format") + .addAttr(to, "dst_format") + .run(stream); +} + +void merge(const AscendMat* src, size_t n, AscendMat& dst, AscendStream& stream) +{ + if (src == nullptr || n < 2) + return; + + int depth = src->depth(); + int rows = src->rows; + int cols = src->cols; + + // All matrix must have same size and type + for (size_t i = 1; i < n; i++) + { + CV_Assert(src[i].depth() == depth && src[i].channels() == 1); + CV_Assert(src[i].rows == rows && src[i].cols == cols); + } + + int cns = 0; + for (size_t i = 0; i < n; i++) + cns += src[i].channels(); + dst.create(src->rows, src->cols, CV_MAKE_TYPE(src->depth(), cns)); + + OperatorRunner runner; + runner.setOp("ConcatD"); + + for (size_t i = 0; i < n; i++) + { + runner.addInput(src[i], ("x" + std::to_string(i)).c_str()); + } + + runner.addOutput(dst, "output_data").addAttr(3, "concat_dim").run(stream); +} + +void merge(const std::vector& src, AscendMat& dst, AscendStream& stream) +{ + merge(&src[0], src.size(), dst, stream); +} + +void merge(const AscendMat* src, size_t n, OutputArray& _dst, AscendStream& stream) +{ + AscendMat dst; + merge(src, n, dst, stream); + dst.download(_dst, stream); +} +void merge(const std::vector& src, OutputArray& dst, AscendStream& stream) +{ + merge(&src[0], src.size(), dst, stream); +} + +void split(const AscendMat& src, AscendMat* dst, AscendStream& stream) +{ + if (src.empty() || dst == nullptr) + return; + + int cn = src.channels(); + + OperatorRunner runner; + runner.setOp("SplitD").addInput(src, "x"); + for (int i = 0; i < cn; i++) + { + dst[i].create(src.rows, src.cols, CV_MAKE_TYPE(src.depth(), 1)); + runner.addOutput(dst[i], ("y" + std::to_string(i)).c_str()); + } + runner.addAttr(3, "split_dim").addAttr(cn, "num_split").run(stream); +} + +void split(const AscendMat& src, std::vector& dst, AscendStream& stream) +{ + dst.resize(src.channels()); + split(src, &dst[0], stream); +} + +void split(const InputArray _src, AscendMat* dst, AscendStream& stream) +{ + AscendMat src; + src.upload(_src, stream); + split(src, dst, stream); +} +void split(const InputArray _src, std::vector& dst, AscendStream& stream) +{ + AscendMat src; + src.upload(_src, stream); + dst.resize(src.channels()); + split(_src, &dst[0], stream); +} + +void transpose(const AscendMat& src, int64_t* perm, AscendMat& dst, AscendStream& stream) +{ + OperatorRunner runner; + runner.setOp("TransposeD") + .addInput(src, "x") + .addOutput(dst, "y") + .addAttr(perm, 4, "perm") + .run(stream); +} + +void transpose(const AscendMat& src, AscendMat& dst, AscendStream& stream) +{ + int64_t perm[] = {0, 2, 1, 3}; + dst.create(src.cols, src.rows, src.type()); + transpose(src, perm, dst, stream); +} + +void transpose(InputArray _src, OutputArray _dst, AscendStream& stream) +{ + AscendMat src, dst; + src.upload(_src, stream); + transpose(src, dst, stream); + dst.download(_dst, stream); +} + +void flip(const AscendMat& src, std::vector& asixs, AscendMat& dst, AscendStream& stream) +{ + int64_t dim = asixs.size(); + OperatorRunner runner; + runner.setOp("ReverseV2") + .addInput(src, "x") + .addInput(&asixs.at(0), &dim, 1, ACL_INT32, "axis") + .addOutput(dst, "y") + .run(stream); +} + +void flip(const AscendMat& src, AscendMat& dst, int flipCode, AscendStream& stream) +{ + std::vector asix; + if (flipCode == 0) + asix.push_back(1); + else if (flipCode > 0) + asix.push_back(2); + else + { + asix.push_back(1); + asix.push_back(2); + } + dst.create(src.rows, src.cols, src.type()); + flip(src, asix, dst, stream); +} + +void flip(const InputArray _src, OutputArray _dst, int flipCode, AscendStream& stream) +{ + AscendMat src, dst; + src.upload(_src, stream); + flip(src, dst, flipCode, stream); + dst.download(_dst, stream); +} + +void rotate(const AscendMat& src, AscendMat& dst, int rotateMode, AscendStream& stream) +{ + AscendMat tempMat; + switch (rotateMode) + { + case ROTATE_90_CLOCKWISE: + { + dst.create(src.cols, src.rows, src.type()); + transpose(src, tempMat, stream); + flip(tempMat, dst, 1, stream); + break; + } + case ROTATE_180: + { + dst.create(src.rows, src.cols, src.type()); + flip(src, dst, -1, stream); + break; + } + case ROTATE_90_COUNTERCLOCKWISE: + { + dst.create(src.cols, src.rows, src.type()); + transpose(src, tempMat, stream); + flip(tempMat, dst, 0, stream); + break; + } + default: + break; + } +} + +void rotate(InputArray _src, OutputArray _dst, int rotateMode, AscendStream& stream) +{ + AscendMat src, dst; + src.upload(_src, stream); + rotate(src, dst, rotateMode, stream); + dst.download(_dst, stream); +} + +void crop(const AscendMat& src, AscendMat& dst, const AscendMat& sizeSrcNpu, int64_t* offset, + AscendStream& stream) +{ + OperatorRunner runner; + runner.setOp("Crop") + .addInput(src, "x") + .addInput(sizeSrcNpu, "size") + .addAttr(1, "axis") + .addAttr(offset, 3, "offsets") + .addOutput(dst, "y") + .run(stream); +} + +AscendMat crop(const AscendMat& src, const Rect& rect, AscendStream& stream) +{ + AscendMat dst, sizeSrcNpu; + // left-up conner + int x = rect.x, y = rect.y, width = rect.width, height = rect.height; + int64_t offset[] = {y, x, 0}; + + CV_Assert(x + width <= src.cols && y + height <= src.rows); + int size1[] = {1, src.channels(), height, width}; + dst.create(height, width, src.type()); + + Mat sizeSrc(height, width, src.type(), size1); + sizeSrcNpu.upload(sizeSrc); + crop(src, dst, sizeSrcNpu, offset, stream); + + return dst; +} +AscendMat crop(InputArray _src, const Rect& rect, AscendStream& stream) +{ + AscendMat src; + src.upload(_src, stream); + return crop(src, rect, stream); +} + +void resize(const AscendMat& src, AscendMat& dst, int32_t* dstSize, int interpolation, + AscendStream& stream) +{ + OperatorRunner runner; + int64_t dims[] = {2}; + char const* mode = ""; + switch (interpolation) + { + case INTER_CUBIC: + mode = "ResizeBicubic"; + break; + case INTER_AREA: + mode = "ResizeArea"; + break; + default: + break; + } + + runner.setOp(mode) + .addInput(src, "images") + .addInput(dstSize, dims, 1, ACL_INT32, "size") + .addAttr(true, "half_pixel_centers") + .addOutput(dst, "y") + .run(stream); +} + +void resize(const AscendMat& src, AscendMat& dst, Size dsize, double inv_scale_x, + double inv_scale_y, int interpolation, AscendStream& stream) +{ + Size ssize = src.size(); + CV_Assert(!ssize.empty()); + float_t scaleX = (float_t)inv_scale_x; + float_t scaleY = (float_t)inv_scale_y; + CV_Assert(interpolation == INTER_CUBIC || interpolation == INTER_AREA); + + if (dsize.empty()) + { + CV_Assert(scaleX > 0); + CV_Assert(scaleY > 0); + dsize = Size(saturate_cast(ssize.width * inv_scale_x), + saturate_cast(ssize.height * inv_scale_y)); + CV_Assert(!dsize.empty()); + } + else + { + scaleX = (float_t)dsize.width / ssize.width; + scaleY = (float_t)dsize.height / ssize.height; + CV_Assert(scaleX > 0); + CV_Assert(scaleY > 0); + } + + int32_t dstSize[] = {dsize.width, dsize.height}; + dst.create(dstSize[0], dstSize[1], src.type()); + resize(src, dst, dstSize, interpolation, stream); +} + +void resize(InputArray _src, OutputArray _dst, Size dsize, double inv_scale_x, double inv_scale_y, + int interpolation, AscendStream& stream) +{ + AscendMat src, dst; + src.upload(_src, stream); + resize(src, dst, dsize, inv_scale_x, inv_scale_y, interpolation, stream); + dst.download(_dst, stream); +} + +} // namespace cann +} // namespace cv diff --git a/modules/cannops/src/element_operations.cpp b/modules/cannops/src/element_operations.cpp new file mode 100644 index 00000000000..402658369b5 --- /dev/null +++ b/modules/cannops/src/element_operations.cpp @@ -0,0 +1,499 @@ +// 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" +namespace cv +{ +namespace cann +{ + +static inline void applyMask(const AscendMat& src, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) +{ + int mtype = mask.type(); + CV_Assert((mtype == CV_8UC1 || mtype == CV_8SC1) && mask.size() == src.size()); + AscendMat onesMask, castedMask; + onesMask.create(mask.rows, mask.cols, mask.type()); + + OperatorRunner runner; + runner.setOp("Div") + .addInput(mask, "x1") + .addInput(mask, "x2") + .addOutput(onesMask, "y") + .run(stream); + + onesMask.convertTo(castedMask, dst.depth(), stream); + arithm_op(src, castedMask, dst, "Mul", stream); +} + +static inline void applyScale(const AscendMat& src, AscendMat& dst, float scale, + AscendStream& stream) +{ + OperatorRunner runner; + arithm_op(src, scale, dst, "Muls", stream); +} + +void arithm_op(const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const char* op, + AscendStream& stream) +{ + if (src2.empty()) + arithm_op(src1, dst, op, stream); + else + { + OperatorRunner runner; + runner.setOp(op).addInput(src1, "x1").addInput(src2, "x2").addOutput(dst, "y").run(stream); + } +} + +void arithm_op(const AscendMat& src, const Scalar& sc, AscendMat& dst, const char* op, + AscendStream& stream) +{ + OperatorRunner runner; + runner.setOp(op) + .addInput(src, "x1") + .addInput(sc, src.type(), "x2") + .addOutput(dst, "y") + .run(stream); +} + +void arithm_op(const Scalar& sc, const AscendMat& src, AscendMat& dst, const char* op, + AscendStream& stream) +{ + OperatorRunner runner; + runner.setOp(op) + .addInput(sc, src.type(), "x1") + .addInput(src, "x2") + .addOutput(dst, "y") + .run(stream); +} + +void arithm_op(const AscendMat& src, AscendMat& dst, const char* op, AscendStream& stream) +{ + OperatorRunner runner; + runner.setOp(op).addInput(src, "x").addOutput(dst, "y").run(stream); +} + +void arithm_op(const AscendMat& src, float scalar, AscendMat& dst, const char* op, + AscendStream& stream) +{ + OperatorRunner runner; + runner.setOp(op).addInput(src, "x").addAttr(scalar, "value").addOutput(dst, "y").run(stream); +} + +// Helper function for template arithm_op. all function called in template arithm_op should be +// done in both AscendMat and Scalar. +static void getInputInfo(const AscendMat& src, int& depth, int& cn, Size& size) +{ + depth = src.depth(); + cn = src.channels(); + size = src.size(); +} + +static void getInputInfo(const Scalar& src, int& depth, int& cn, Size& size) +{ + CV_UNUSED(src); + depth = -1; + cn = -1; + size = {-1, -1}; +} + +static void convert(const AscendMat& src, AscendMat& dst, AscendStream& stream) +{ + src.convertTo(dst, CV_32F, stream); +} + +static void convert(const Scalar& src, Scalar& dst, AscendStream& stream) +{ + CV_UNUSED(stream); + dst = src; +} + +template +static void arithm_op(const T1& src1, const T2& src2, AscendMat& dst, const AscendMat& mask, float scale, + int dtype, const char* op, AscendStream& stream) +{ + T1 castedSrc1; + T2 castedSrc2; + AscendMat castedRet; + + int sdepth1, sdepth2, scn1, scn2; + Size ssize1, ssize2; + getInputInfo(src1, sdepth1, scn1, ssize1); + getInputInfo(src2, sdepth2, scn2, ssize2); + + int sdepth = sdepth1 == -1 ? sdepth2 : sdepth1; + int cn = scn1 == -1 ? scn2 : scn1; + Size size = sdepth1 == -1 ? ssize2 : ssize1; + + if (sdepth1 != -1 && sdepth2 != -1 && !ssize1.empty() && !ssize2.empty()) + CV_Assert(sdepth1 == sdepth2 && scn1 == scn2 && ssize1 == ssize2); + + if (dtype < 0) + dtype = sdepth; + const int ddepth = CV_MAT_DEPTH(dtype); + CV_Assert(sdepth <= CV_16F && ddepth <= CV_16F); + + dst.create(size.height, size.width, CV_MAKE_TYPE(ddepth, cn)); + + // In order to achieve high accuracy, convert integers to float for calculation. + if (scale != 1 && dtype < CV_32F) + { + convert(src1, castedSrc1, stream); + convert(src2, castedSrc2, stream); + castedRet.create(size.height, size.width, CV_MAKE_TYPE(CV_32F, cn)); + } + else + { + castedSrc1 = src1; + castedSrc2 = src2; + castedRet = dst; + } + + // step1, calculate operator. + OperatorRunner runner; + arithm_op(castedSrc1, castedSrc2, castedRet, op, stream); + + // step2, apply mask if need. + if (!mask.empty()) + applyMask(castedRet, castedRet, mask, stream); + + // step3, apply scale if need. + if (scale != 1) + applyScale(castedRet, castedRet, scale, stream); + + // After rounding the result, convert the type to the original type. + if (castedRet.depth() != dst.depth()) + { + runner.setOp("Round").addInput(castedRet, "x").addOutput(castedRet, "y").run(stream); + castedRet.convertTo(dst, stream); + } +} + +static void arithm_op(const InputArray _src1, const InputArray _src2, OutputArray _dst, const InputArray _mask, + float scale, int dtype, const char* op, AscendStream& stream) +{ + const bool isScalar1 = (_src1.kind() == _InputArray::MATX); + const bool isScalar2 = (_src2.kind() == _InputArray::MATX); + + if (isScalar1 && isScalar2) + CV_Error(Error::StsBadArg, "At list one matrix parameter shoule be passwd."); + + AscendMat src1, src2, dst, mask; + Mat scalar; + + if (!isScalar1 && !_src1.empty()) + src1.upload(_src1, stream); + if (!isScalar2 && !_src2.empty()) + src2.upload(_src2, stream); + + if (!_mask.empty()) + mask.upload(_mask, stream); + + Scalar val; + if (isScalar1) + scalar = _src1.getMat(); + else if (isScalar2) + scalar = _src2.getMat(); + + if (!scalar.empty()) + { + CV_Assert(scalar.total() <= 4); + scalar.convertTo(Mat_(scalar.rows, scalar.cols, &val[0]), CV_64F); + } + + if (isScalar1) + arithm_op(val, src2, dst, mask, scale, dtype, op, stream); + else if (isScalar2) + arithm_op(src1, val, dst, mask, scale, dtype, op, stream); + else + arithm_op(src1, src2, dst, mask, scale, dtype, op, stream); + + dst.download(_dst, stream); +} + +// In order to supply more interfaces, differnet function declaration shoule be done. +void add(const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, dtype, "Add", stream); +} + +void add(const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, dtype, "Add", stream); +} + +void add(const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, dtype, "Add", stream); +} + +void add(const Scalar& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, dtype, "Add", stream); +} + + +void subtract(const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, dtype, "Sub", stream); +} + +void subtract(const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, dtype, "Sub", stream); +} + +void subtract(const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, dtype, "Sub", stream); +} + +void subtract(const Scalar& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, dtype, "Sub", stream); +} + + +void multiply(const InputArray src1, const InputArray src2, OutputArray dst, float scale, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, noArray(), scale, dtype, "Mul", stream); +} + +void multiply(const AscendMat& src1, const AscendMat& src2, AscendMat& dst, float scale, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, AscendMat(), scale, dtype, "Mul", stream); +} + +void multiply(const AscendMat& src1, const Scalar& src2, AscendMat& dst, float scale, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, AscendMat(), scale, dtype, "Mul", stream); +} + +void multiply(const Scalar& src1, const AscendMat& src2, AscendMat& dst, float scale, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, AscendMat(), scale, dtype, "Mul", stream); +} + + +void divide(const InputArray src1, const InputArray src2, OutputArray dst, float scale, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, noArray(), scale, dtype, "RealDiv", stream); +} + +void divide(const AscendMat& src1, const AscendMat& src2, AscendMat& dst, float scale, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, AscendMat(), scale, dtype, "RealDiv", stream); +} + +void divide(const AscendMat& src1, const Scalar& src2, AscendMat& dst, float scale, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, AscendMat(), scale, dtype, "RealDiv", stream); +} + +void divide(const Scalar& src1, const AscendMat& src2, AscendMat& dst, float scale, int dtype, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, AscendMat(), scale, dtype, "RealDiv", stream); +} + + +void bitwise_and(const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, -1, "BitwiseAnd", stream); +} + +void bitwise_and(const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, -1, "BitwiseAnd", stream); +} + +void bitwise_and(const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, -1, "BitwiseAnd", stream); +} + +void bitwise_and(const Scalar& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, -1, "BitwiseAnd", stream); +} + + +void bitwise_or(const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, -1, "BitwiseOr", stream); +} + +void bitwise_or(const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, -1, "BitwiseOr", stream); +} + +void bitwise_or(const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, -1, "BitwiseOr", stream); +} + +void bitwise_or(const Scalar& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, -1, "BitwiseOr", stream); +} + + +void bitwise_xor(const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, -1, "BitwiseXor", stream); +} + +void bitwise_xor(const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, -1, "BitwiseXor", stream); +} + +void bitwise_xor(const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, -1, "BitwiseXor", stream); +} + +void bitwise_xor(const Scalar& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) +{ + arithm_op(src1, src2, dst, mask, 1, -1, "BitwiseXor", stream); +} + + +void bitwise_not(const InputArray src, OutputArray dst, const InputArray mask, AscendStream& stream) +{ + arithm_op(src, noArray(), dst, mask, 1, -1, "Invert", stream); +} + +void bitwise_not(const AscendMat& src, AscendMat& dst, const AscendMat& mask, AscendStream& stream) +{ + arithm_op(src, AscendMat(), dst, mask, 1, -1, "Invert", stream); +} + + +void addWeighted(const AscendMat& src1, double alpha, const AscendMat& src2, double beta, double gamma, + AscendMat& dst, int dtype, AscendStream& stream) +{ + if (dtype < 0) + dtype = src1.depth(); + + CV_Assert(src2.depth() == src1.depth() && src2.size() == src1.size() && + src1.channels() == src2.channels()); + + int type = CV_MAKE_TYPE(dtype, src1.channels()); + dst.create(src1.rows, src1.cols, type); + + // TODO: Consider overflow, should extend type or not? + AscendMat src1Weighted(src1.size(), type), src2Weighted(src1.size(), type), + srcWeightedSumRet(src1.size(), type); + + arithm_op(src1, (float)alpha, src1Weighted, "Muls", stream); + arithm_op(src2, (float)beta, src2Weighted, "Muls", stream); + arithm_op(src1Weighted, src2Weighted, srcWeightedSumRet, "Add", stream); + arithm_op(srcWeightedSumRet, (float)gamma, dst, "Adds", stream); +} + +void addWeighted(const InputArray _src1, double alpha, const InputArray _src2, double beta, double gamma, + OutputArray _dst, int dtype, AscendStream& stream) +{ + AscendMat src1, src2, dst; + src1.upload(_src1, stream); + src2.upload(_src2, stream); + addWeighted(src1, alpha, src2, beta, gamma, dst, dtype, stream); + dst.download(_dst, stream); +} + +double threshold(const AscendMat& src, AscendMat& dst, double thresh, double maxval, int type, + AscendStream& stream) +{ + // ThresholdTypes is defined in opencv2/imgproc, This type is the only Symbol we need. + // Add imgproc to dependence is too heavy, use magic number instead. + CV_Assert(type <= 4 /*THRESH_TOZERO_INV*/); + + AscendMat threshMat(src.size(), src.type()); + + dst.create(src.rows, src.cols, src.type()); + + OperatorRunner runner; + runner.setOp("Threshold") + .addInput(src, "x") + .addOutput(threshMat, "y") + .addAttr((float)thresh, "threshold") + .run(stream); + + // THRESH_*_INV, THRESH_TRUNC need a inverse threshMat. + // THRESH_BINARY_INV = 1, THRESH_TRUNC = 2, THRESH_TOZERO_INV = 4, + if (type == 1 || type == 2 || type == 4) + { + AscendMat threshInvMat(src.size(), src.type()); + AscendMat ones(src.size(), src.type()); + Scalar s(1, 1, 1, 1); + ones.setTo(s, stream); + arithm_op(ones, threshMat, threshInvMat, "Sub", stream); + + if (type == 1) + arithm_op(threshInvMat, (float)maxval, dst, "Muls", stream); + else if (type == 2) + { + AscendMat ToZeroInvMat(src.size(), src.type()); + AscendMat TruncMat(src.size(), src.type()); + arithm_op(threshInvMat, src, ToZeroInvMat, "Mul", stream); + arithm_op(threshMat, (float)thresh, TruncMat, "Muls", stream); + arithm_op(ToZeroInvMat, TruncMat, dst, "Add", stream); + } + else + arithm_op(threshInvMat, src, dst, "Mul", stream); + } + else + { + if (type == 0) /* THRESH_BINARY = 0 */ + arithm_op(threshMat, (float)maxval, dst, "Muls", stream); + else if (type == 3) /* THRESH_TOZERO = 3 */ + arithm_op(threshMat, src, dst, "Mul", stream); + else + CV_Error(Error::StsError, "Unknown/unsupported threshold type"); + } + return thresh; +} + +double threshold(const InputArray _src, OutputArray _dst, double thresh, double maxval, int type, + AscendStream& stream) +{ + AscendMat src, dst; + src.upload(_src, stream); + dst.create(src.rows, src.cols, src.type()); + double ret = threshold(src, dst, thresh, maxval, type, stream); + dst.download(_dst, stream); + return ret; +} + +} // namespace cann +} // namespace cv diff --git a/modules/cannops/src/precomp.hpp b/modules/cannops/src/precomp.hpp new file mode 100644 index 00000000000..8411cc40407 --- /dev/null +++ b/modules/cannops/src/precomp.hpp @@ -0,0 +1,14 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef __OPENCV_PRECOMP_H__ +#define __OPENCV_PRECOMP_H__ + +#include "opencv2/cann.hpp" +#include "opencv2/stream_accessor.hpp" +#include "opencv2/cann_call.hpp" +#include "opencv2/cann_interface.hpp" +#include "opencv2/cann_private.hpp" + +#endif /* __OPENCV_PRECOMP_H__ */ diff --git a/modules/cannops/test/test_core.cpp b/modules/cannops/test/test_core.cpp new file mode 100644 index 00000000000..6b63a8cf061 --- /dev/null +++ b/modules/cannops/test/test_core.cpp @@ -0,0 +1,217 @@ +// 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" +#include + +namespace opencv_test +{ +namespace +{ +TEST(CORE, MERGE) +{ + Mat m1 = (Mat_(2, 2) << 1, 4, 7, 10); + Mat m2 = (Mat_(2, 2) << 2, 5, 8, 11); + Mat m3 = (Mat_(2, 2) << 3, 6, 9, 12); + Mat channels[3] = {m1, m2, m3}; + Mat m; + cv::merge(channels, 3, m); + + cv::cann::setDevice(0); + + AscendMat a1, a2, a3; + a1.upload(m1); + a2.upload(m2); + a3.upload(m3); + AscendMat aclChannels[3] = {a1, a2, a3}; + std::vector aclChannelsVector; + aclChannelsVector.push_back(a1); + aclChannelsVector.push_back(a2); + aclChannelsVector.push_back(a3); + + Mat checker1, checker2; + cv::cann::merge(aclChannels, 3, checker1); + cv::cann::merge(aclChannelsVector, checker2); + + EXPECT_MAT_NEAR(m, checker1, 0.0); + EXPECT_MAT_NEAR(m, checker2, 0.0); + + cv::cann::resetDevice(); +} + +TEST(CORE, SPLIT) +{ + char d[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + Mat m(2, 2, CV_8UC3, d); + Mat channels[3]; + cv::split(m, channels); + + cv::cann::setDevice(0); + + AscendMat aclChannels[3]; + std::vector aclChannelsVector; + + cv::cann::split(m, aclChannels); + cv::cann::split(m, aclChannelsVector); + + Mat checker1[3], checker2[3]; + aclChannels[0].download(checker1[0]); + aclChannels[1].download(checker1[1]); + aclChannels[2].download(checker1[2]); + + aclChannelsVector[0].download(checker2[0]); + aclChannelsVector[1].download(checker2[1]); + aclChannelsVector[2].download(checker2[2]); + + EXPECT_MAT_NEAR(channels[0], checker1[0], 0.0); + EXPECT_MAT_NEAR(channels[1], checker1[1], 0.0); + EXPECT_MAT_NEAR(channels[2], checker1[2], 0.0); + + EXPECT_MAT_NEAR(channels[0], checker2[0], 0.0); + EXPECT_MAT_NEAR(channels[1], checker2[1], 0.0); + EXPECT_MAT_NEAR(channels[2], checker2[2], 0.0); + + AscendMat npuM; + npuM.upload(m); + cv::cann::split(npuM, aclChannels); + cv::cann::split(npuM, aclChannelsVector); + + aclChannels[0].download(checker1[0]); + aclChannels[1].download(checker1[1]); + aclChannels[2].download(checker1[2]); + + aclChannelsVector[0].download(checker2[0]); + aclChannelsVector[1].download(checker2[1]); + aclChannelsVector[2].download(checker2[2]); + + EXPECT_MAT_NEAR(channels[0], checker1[0], 0.0); + EXPECT_MAT_NEAR(channels[1], checker1[1], 0.0); + EXPECT_MAT_NEAR(channels[2], checker1[2], 0.0); + + EXPECT_MAT_NEAR(channels[0], checker2[0], 0.0); + EXPECT_MAT_NEAR(channels[1], checker2[1], 0.0); + EXPECT_MAT_NEAR(channels[2], checker2[2], 0.0); + cv::cann::resetDevice(); +} + +TEST(CORE, TRANSPOSE) +{ + Mat cpuMat = randomMat(10, 10, CV_32SC3), cpuRetMat, checker; + cv::transpose(cpuMat, cpuRetMat); + cv::cann::transpose(cpuMat, checker); + EXPECT_MAT_NEAR(cpuRetMat, checker, 0.0); + + AscendMat npuMat, npuChecker; + npuMat.upload(cpuMat); + cv::cann::transpose(npuMat, npuChecker); + npuChecker.download(checker); + EXPECT_MAT_NEAR(cpuRetMat, checker, 0.0); +} + +TEST(CORE, FLIP) +{ + Mat cpuMat = randomMat(10, 10, CV_32SC3), cpuRetMat, checker; + + int flipMode; + + for (flipMode = -1; flipMode < 2; flipMode++) + { + cv::flip(cpuMat, cpuRetMat, flipMode); + cv::cann::flip(cpuMat, checker, flipMode); + EXPECT_MAT_NEAR(cpuRetMat, checker, 0.0); + } + + AscendMat npuMat, npuChecker; + npuMat.upload(cpuMat); + for (flipMode = -1; flipMode < 2; flipMode++) + { + cv::flip(cpuMat, cpuRetMat, flipMode); + cv::cann::flip(npuMat, npuChecker, flipMode); + npuChecker.download(checker); + EXPECT_MAT_NEAR(cpuRetMat, checker, 0.0); + } +} + +TEST(CORE, ROTATE) +{ + Mat cpuRetMat, checker, cpuMat = randomMat(3, 5, CV_16S, 0.0, 255.0); + + int rotateMode; + for (rotateMode = 0; rotateMode < 3; rotateMode++) + { + cv::rotate(cpuMat, cpuRetMat, rotateMode); + cv::cann::rotate(cpuMat, checker, rotateMode); + EXPECT_MAT_NEAR(cpuRetMat, checker, 0.0); + } + + AscendMat npuMat, npuChecker; + npuMat.upload(cpuMat); + for (rotateMode = 0; rotateMode < 3; rotateMode++) + { + cv::rotate(cpuMat, cpuRetMat, rotateMode); + cv::cann::rotate(npuMat, npuChecker, rotateMode); + npuChecker.download(checker); + EXPECT_MAT_NEAR(cpuRetMat, checker, 0.0); + } +} + +TEST(CORE, CROP) +{ + Mat cpuOpRet, checker, cpuMat = randomMat(6, 6, CV_32SC3, 0.0, 255.0); + Rect b(1, 2, 4, 4); + Mat cropped_cv(cpuMat, b); + AscendMat cropped_cann(cpuMat, b); + cropped_cann.download(checker); + EXPECT_MAT_NEAR(cropped_cv, checker, 1e-10); +} + +TEST(CORE, CROP_OVERLOAD) +{ + Mat cpuOpRet, checker, cpuMat = randomMat(6, 6, CV_16SC3, 0.0, 255.0); + const Rect b(1, 2, 4, 4); + Mat cropped_cv = cpuMat(b); + AscendMat cropped_cann = cv::cann::crop(cpuMat, b); + cropped_cann.download(checker); + EXPECT_MAT_NEAR(cropped_cv, checker, 1e-10); + + AscendMat npuMat; + npuMat.upload(cpuMat); + cropped_cann = cv::cann::crop(npuMat, b); + cropped_cann.download(checker); + EXPECT_MAT_NEAR(cropped_cv, checker, 1e-10); +} + +TEST(CORE, RESIZE) +{ + Mat resized_cv, checker, cpuMat = randomMat(10, 10, CV_32F, 100.0, 255.0); + Size dsize = Size(6, 6); + // only support {2 INTER_CUBIC} and {3 INTER_AREA} + // only the resize result of INTER_AREA is close to CV's. + int flags = 3; + cv::cann::setDevice(0); + cv::resize(cpuMat, resized_cv, dsize, 0, 0, flags); + cv::cann::resize(cpuMat, checker, dsize, 0, 0, flags); + EXPECT_MAT_NEAR(resized_cv, checker, 1e-4); + + cv::resize(cpuMat, resized_cv, Size(), 0.5, 0.5, flags); + cv::cann::resize(cpuMat, checker, Size(), 0.5, 0.5, flags); + EXPECT_MAT_NEAR(resized_cv, checker, 1e-4); + + AscendMat npuMat, npuChecker; + npuMat.upload(cpuMat); + cv::resize(cpuMat, resized_cv, dsize, 0, 0, flags); + cv::cann::resize(npuMat, npuChecker, dsize, 0, 0, flags); + npuChecker.download(checker); + EXPECT_MAT_NEAR(resized_cv, checker, 1e-4); + + cv::resize(cpuMat, resized_cv, Size(), 0.5, 0.5, flags); + cv::cann::resize(npuMat, npuChecker, Size(), 0.5, 0.5, flags); + npuChecker.download(checker); + EXPECT_MAT_NEAR(resized_cv, checker, 1e-4); + cv::cann::resetDevice(); +} + + +} // namespace +} // namespace opencv_test diff --git a/modules/cannops/test/test_cvtcolor.cpp b/modules/cannops/test/test_cvtcolor.cpp new file mode 100644 index 00000000000..27a92298961 --- /dev/null +++ b/modules/cannops/test/test_cvtcolor.cpp @@ -0,0 +1,89 @@ +// 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 +{ + +void cvtColorTest(int code, int cn, int dcn = 3, float diff = 0.0f) +{ + cv::cann::setDevice(DEVICE_ID); + Mat cpuRet, npuRet; + + Mat img8U = randomMat(512, 512, CV_MAKETYPE(CV_8U, cn), 0.0f, 255.0f); + Mat img16U = randomMat(512, 512, CV_MAKETYPE(CV_16U, cn), 0.0f, 65535.0f); + Mat img32F = randomMat(512, 512, CV_MAKETYPE(CV_32F, cn), 0.0f, 65535.0f); + + cv::cvtColor(img8U, cpuRet, code, dcn); + cv::cann::cvtColor(img8U, npuRet, code, dcn); + EXPECT_MAT_NEAR(cpuRet, npuRet, diff); + + cv::cvtColor(img16U, cpuRet, code, dcn); + cv::cann::cvtColor(img16U, npuRet, code, dcn); + EXPECT_MAT_NEAR(cpuRet, npuRet, diff); + + cv::cvtColor(img32F, cpuRet, code, dcn); + cv::cann::cvtColor(img32F, npuRet, code, dcn); + EXPECT_MAT_NEAR(cpuRet, npuRet, diff); + cv::cann::resetDevice(); +} + +TEST(CVT_COLOR, BGR2BGRA) { cvtColorTest(COLOR_BGR2BGRA, 3, 4); } +TEST(CVT_COLOR, BGRA2BGR) { cvtColorTest(COLOR_BGRA2BGR, 4); } +TEST(CVT_COLOR, BGR2RGBA) { cvtColorTest(COLOR_BGR2RGBA, 3, 4); } +TEST(CVT_COLOR, RGBA2BGR) { cvtColorTest(COLOR_RGBA2BGR, 4); } +TEST(CVT_COLOR, BGR2RGB) { cvtColorTest(COLOR_BGR2RGB, 3); } +TEST(CVT_COLOR, BGRA2RGBA) { cvtColorTest(COLOR_BGRA2RGBA, 4, 4); } + +// Due to parameter accuracy issues, the calculation results have certain accuracy differences. +TEST(CVT_COLOR, BGR2GRAY) { cvtColorTest(COLOR_BGR2GRAY, 3, 1, 10.0f); } +TEST(CVT_COLOR, RGB2GRAY) { cvtColorTest(COLOR_BGR2GRAY, 3, 1, 10.0f); } +TEST(CVT_COLOR, GRAY2BGR) { cvtColorTest(COLOR_GRAY2BGR, 1); } +TEST(CVT_COLOR, GRAY2BGRA) { cvtColorTest(COLOR_GRAY2BGRA, 1, 4); } +TEST(CVT_COLOR, BGRA2GRAY) { cvtColorTest(COLOR_BGRA2GRAY, 4, 1, 10.0f); } +TEST(CVT_COLOR, RGBA2GRAY) { cvtColorTest(COLOR_RGBA2GRAY, 4, 1, 10.0f); } + +TEST(CVT_COLOR, RGB2XYZ) { cvtColorTest(COLOR_RGB2XYZ, 3, 3, 50.0f); } +TEST(CVT_COLOR, BGR2XYZ) { cvtColorTest(COLOR_BGR2XYZ, 3, 3, 50.0f); } +TEST(CVT_COLOR, XYZ2BGR) { cvtColorTest(COLOR_XYZ2BGR, 3, 3, 150.0f); } +TEST(CVT_COLOR, XYZ2RGB) { cvtColorTest(COLOR_XYZ2RGB, 3, 3, 150.0f); } +TEST(CVT_COLOR, XYZ2BGR_DC4) { cvtColorTest(COLOR_XYZ2BGR, 3, 4, 150.0f); } +TEST(CVT_COLOR, XYZ2RGB_DC4) { cvtColorTest(COLOR_XYZ2RGB, 3, 4, 150.0f); } + +TEST(CVT_COLOR, BGR2YCrCb) { cvtColorTest(COLOR_BGR2YCrCb, 3, 3, 10.0f); } +TEST(CVT_COLOR, RGB2YCrCb) { cvtColorTest(COLOR_RGB2YCrCb, 3, 3, 10.0f); } +TEST(CVT_COLOR, YCrCb2BGR) { cvtColorTest(COLOR_YCrCb2BGR, 3, 3, 10.0f); } +TEST(CVT_COLOR, YCrCb2RGB) { cvtColorTest(COLOR_YCrCb2RGB, 3, 3, 10.0f); } +TEST(CVT_COLOR, YCrCb2BGR_DC4) { cvtColorTest(COLOR_YCrCb2BGR, 3, 4, 10.0f); } +TEST(CVT_COLOR, YCrCb2RGB_DC4) { cvtColorTest(COLOR_YCrCb2RGB, 3, 4, 10.0f); } + +TEST(CVT_COLOR, BGR2YUV) { cvtColorTest(COLOR_BGR2YUV, 3, 3, 10.0f); } +TEST(CVT_COLOR, RGB2YUV) { cvtColorTest(COLOR_RGB2YUV, 3, 3, 10.0f); } +TEST(CVT_COLOR, YUV2BGR) { cvtColorTest(COLOR_YUV2BGR, 3, 3, 10.0f); } +TEST(CVT_COLOR, YUV2RGB) { cvtColorTest(COLOR_YUV2RGB, 3, 3, 10.0f); } +TEST(CVT_COLOR, YUV2BGR_DC4) { cvtColorTest(COLOR_YUV2BGR, 3, 4, 10.0f); } +TEST(CVT_COLOR, YUV2RGB_DC4) { cvtColorTest(COLOR_YUV2RGB, 3, 4, 10.0f); } + +// Test of AscendMat. Since the logic is the same, only interface test is needed. +TEST(CVT_COLOR, COLOR_BGR2BGRA_ASCENDMAT) +{ + cv::cann::setDevice(DEVICE_ID); + Mat cpuRet, npuRet; + + Mat img8U = randomMat(512, 512, CV_8UC3, 0.0f, 255.0f); + cv::cvtColor(img8U, cpuRet, COLOR_BGR2BGRA, 4); + + AscendMat npuImg8U, npuChecker; + npuImg8U.upload(img8U); + cv::cann::cvtColor(npuImg8U, npuChecker, COLOR_BGR2BGRA, 4); + npuChecker.download(npuRet); + EXPECT_MAT_NEAR(cpuRet, npuRet, 10.0f); + cv::cann::resetDevice(); +} + +} // namespace +} // namespace opencv_test diff --git a/modules/cannops/test/test_element_operations.cpp b/modules/cannops/test/test_element_operations.cpp new file mode 100644 index 00000000000..76c103a65f4 --- /dev/null +++ b/modules/cannops/test/test_element_operations.cpp @@ -0,0 +1,697 @@ +// 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" +#include + +namespace opencv_test +{ +namespace +{ +template +void testMatOpMat(FCV cvFunc, FCANN cannFunc, PARAMS... param) +{ + cv::cann::setDevice(DEVICE_ID); + Mat mat1 = randomMat(10, 10, CV_32SC3); + Mat mat2 = randomMat(10, 10, CV_32SC3); + Mat cpuDst, check; + + cvFunc(mat1, mat2, cpuDst, param...); + cannFunc(mat1, mat2, check, param..., AscendStream::Null()); + EXPECT_MAT_NEAR(cpuDst, check, 1.0); + + AscendStream stream; + cannFunc(mat1, mat2, check, param..., stream); + stream.waitForCompletion(); + EXPECT_MAT_NEAR(cpuDst, check, 1.0); + + cv::cann::resetDevice(); +} + +template +void testAscendMatOpAscendMatMask(FCV cvFunc, FCANN cannFunc, DTMASK mask = AscendMat(), + PARAMS... param) +{ + cv::cann::setDevice(DEVICE_ID); + Mat mat1 = randomMat(10, 10, CV_32SC3); + Mat mat2 = randomMat(10, 10, CV_32SC3); + Mat cpuDst, check, cpuMask; + AscendMat npuMat1, npuMat2, npuCheck; + npuMat1.upload(mat1); + npuMat2.upload(mat2); + if (mask.empty()) + { + cvFunc(mat1, mat2, cpuDst, noArray(), param...); + } + else + { + mask.download(cpuMask); + cvFunc(mat1, mat2, cpuDst, cpuMask, param...); + } + + cannFunc(npuMat1, npuMat2, npuCheck, mask, param..., AscendStream::Null()); + npuCheck.download(check); + EXPECT_MAT_NEAR(cpuDst, check, 1.0); + + AscendStream stream; + cannFunc(npuMat1, npuMat2, npuCheck, mask, param..., stream); + npuCheck.download(check); + stream.waitForCompletion(); + EXPECT_MAT_NEAR(cpuDst, check, 1.0); + + cv::cann::resetDevice(); +} + +template +void testAscendMatOpAscendMat(FCV cvFunc, FCANN cannFunc, PARAMS... param) +{ + cv::cann::setDevice(DEVICE_ID); + Mat mat1 = randomMat(10, 10, CV_32SC3); + Mat mat2 = randomMat(10, 10, CV_32SC3); + Mat cpuDst, check; + AscendMat npuMat1, npuMat2, npuCheck; + npuMat1.upload(mat1); + npuMat2.upload(mat2); + cvFunc(mat1, mat2, cpuDst, param...); + cannFunc(npuMat1, npuMat2, npuCheck, param..., AscendStream::Null()); + npuCheck.download(check); + EXPECT_MAT_NEAR(cpuDst, check, 1.0); + + AscendStream stream; + cannFunc(npuMat1, npuMat2, npuCheck, param..., stream); + npuCheck.download(check); + stream.waitForCompletion(); + EXPECT_MAT_NEAR(cpuDst, check, 1.0); + + cv::cann::resetDevice(); +} + +TEST(ELEMENTWISE_OP, MAT_ADD_MAT) +{ + testMatOpMat( + cv::add, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + int dtype, AscendStream& stream) + { cv::cann::add(src1, src2, dst, mask, dtype, stream); }, + noArray(), -1); + testAscendMatOpAscendMatMask( + cv::add, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + int dtype, AscendStream& stream) + { cv::cann::add(src1, src2, dst, mask, dtype, stream); }, + AscendMat(), -1); +} + +TEST(ELEMENTWISE_OP, MAT_SUB_MAT) +{ + testMatOpMat( + cv::subtract, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + int dtype, AscendStream& stream) + { cv::cann::subtract(src1, src2, dst, mask, dtype, stream); }, + noArray(), -1); + testAscendMatOpAscendMatMask( + cv::subtract, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + int dtype, AscendStream& stream) + { cv::cann::subtract(src1, src2, dst, mask, dtype, stream); }, + AscendMat(), -1); +} + +TEST(ELEMENTWISE_OP, MAT_MUL_MAT) +{ + testMatOpMat( + cv::multiply, + [](const InputArray src1, const InputArray src2, OutputArray dst, float scale, int dtype, + AscendStream& stream) { cv::cann::multiply(src1, src2, dst, scale, dtype, stream); }, + 1, -1); + testAscendMatOpAscendMat( + cv::multiply, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, float scale, int dtype, + AscendStream& stream) { cv::cann::multiply(src1, src2, dst, scale, dtype, stream); }, + 1, -1); +} + +TEST(ELEMENTWISE_OP, MAT_DIV_MAT) +{ + testMatOpMat([](const cv::Mat& src1, const cv::Mat& src2, cv::Mat& dst, double scale, int dtype) + { cv::divide(src1, src2, dst, scale, dtype); }, + [](const InputArray src1, const InputArray src2, OutputArray dst, float scale, + int dtype, AscendStream& stream) + { cv::cann::divide(src1, src2, dst, scale, dtype, stream); }, + 1, -1); + testAscendMatOpAscendMat( + [](const cv::Mat& src1, const cv::Mat& src2, cv::Mat& dst, double scale, int dtype) + { cv::divide(src1, src2, dst, scale, dtype); }, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, float scale, int dtype, + AscendStream& stream) { cv::cann::divide(src1, src2, dst, scale, dtype, stream); }, + 1, -1); +} + +TEST(ELEMENTWISE_OP, MAT_BITWISE_AND_MAT) +{ + testMatOpMat( + cv::bitwise_and, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) { cv::cann::bitwise_and(src1, src2, dst, mask, stream); }, + noArray()); + testAscendMatOpAscendMatMask( + cv::bitwise_and, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) { cv::cann::bitwise_and(src1, src2, dst, mask, stream); }, + AscendMat()); +} + +TEST(ELEMENTWISE_OP, MAT_BITWISE_OR_MAT) +{ + testMatOpMat( + cv::bitwise_or, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) { cv::cann::bitwise_or(src1, src2, dst, mask, stream); }, + noArray()); + testAscendMatOpAscendMatMask( + cv::bitwise_or, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) { cv::cann::bitwise_or(src1, src2, dst, mask, stream); }, + AscendMat()); +} + +TEST(ELEMENTWISE_OP, MAT_BITWISE_XOR_MAT) +{ + testMatOpMat( + cv::bitwise_xor, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) { cv::cann::bitwise_xor(src1, src2, dst, mask, stream); }, + noArray()); + testAscendMatOpAscendMatMask( + cv::bitwise_xor, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) { cv::cann::bitwise_xor(src1, src2, dst, mask, stream); }, + AscendMat()); +} + +TEST(ELEMENTWISE_OP, MAT_ADD_MAT_WITH_MASK_AND_DTYPE) +{ + testMatOpMat( + cv::add, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + int dtype, AscendStream& stream) + { cv::cann::add(src1, src2, dst, mask, dtype, stream); }, + genMask(), CV_32SC3); + testAscendMatOpAscendMatMask( + cv::add, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + int dtype, AscendStream& stream) + { cv::cann::add(src1, src2, dst, mask, dtype, stream); }, + AscendMat(), CV_32SC3); +} + +TEST(ELEMENTWISE_OP, MAT_SUB_MAT_WITH_MASK_AND_DTYPE) +{ + testMatOpMat( + cv::subtract, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + int dtype, AscendStream& stream) + { cv::cann::subtract(src1, src2, dst, mask, dtype, stream); }, + genMask(), CV_32SC3); + testAscendMatOpAscendMatMask( + cv::subtract, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + int dtype, AscendStream& stream) + { cv::cann::subtract(src1, src2, dst, mask, dtype, stream); }, + AscendMat(), CV_32SC3); +} + +TEST(ELEMENTWISE_OP, MAT_BITWISE_AND_MAT_WITH_MASK) +{ + testMatOpMat( + cv::bitwise_and, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) { cv::cann::bitwise_and(src1, src2, dst, mask, stream); }, + genMask()); + testAscendMatOpAscendMatMask( + cv::bitwise_and, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) { cv::cann::bitwise_and(src1, src2, dst, mask, stream); }, + genNpuMask()); +} + +TEST(ELEMENTWISE_OP, MAT_BITWISE_OR_MAT_WITH_MASK) +{ + testMatOpMat( + cv::bitwise_or, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) { cv::cann::bitwise_or(src1, src2, dst, mask, stream); }, + genMask()); + testAscendMatOpAscendMatMask( + cv::bitwise_or, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) { cv::cann::bitwise_or(src1, src2, dst, mask, stream); }, + genNpuMask()); +} + +TEST(ELEMENTWISE_OP, MAT_BITWISE_XOR_MAT_WITH_MASK) +{ + testMatOpMat( + cv::bitwise_xor, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) { cv::cann::bitwise_xor(src1, src2, dst, mask, stream); }, + genMask()); + testAscendMatOpAscendMatMask( + cv::bitwise_xor, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) { cv::cann::bitwise_xor(src1, src2, dst, mask, stream); }, + genNpuMask()); +} + +float randomScale = randomNum(); +TEST(ELEMENTWISE_OP, MAT_MUL_MAT_WITH_SCALE) +{ + testMatOpMat( + cv::multiply, + [](const InputArray src1, const InputArray src2, OutputArray dst, float scale, int dtype, + AscendStream& stream) { cv::cann::multiply(src1, src2, dst, scale, dtype, stream); }, + randomScale, -1); + testAscendMatOpAscendMat( + cv::multiply, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, float scale, int dtype, + AscendStream& stream) { cv::cann::multiply(src1, src2, dst, scale, dtype, stream); }, + randomScale, -1); +} + +TEST(ELEMENTWISE_OP, MAT_DIV_MAT_WITH_SCALE) +{ + testMatOpMat([](const cv::Mat& src1, const cv::Mat& src2, cv::Mat& dst, double scale, int dtype) + { cv::divide(src1, src2, dst, scale, dtype); }, + [](const InputArray src1, const InputArray src2, OutputArray dst, float scale, + int dtype, AscendStream& stream) + { cv::cann::divide(src1, src2, dst, scale, dtype, stream); }, + randomScale, -1); + testAscendMatOpAscendMat( + [](const cv::Mat& src1, const cv::Mat& src2, cv::Mat& dst, double scale, int dtype) + { cv::divide(src1, src2, dst, scale, dtype); }, + [](const AscendMat& src1, const AscendMat& src2, AscendMat& dst, float scale, int dtype, + AscendStream& stream) { cv::cann::divide(src1, src2, dst, scale, dtype, stream); }, + randomScale, -1); +} + +template +void testMatOpScalar(FCV cvFunc, FCANN cannFunc, PARAMS... param) +{ + Scalar scalar = randomScalar(); + Mat mat(10, 10, CV_32SC3, randomScalar()); + Mat cpuDst1, cpuDst2, checker1, checker2; + + cvFunc(Mat(10, 10, CV_32SC3, scalar), mat, cpuDst1, param...); + cvFunc(mat, Mat(10, 10, CV_32SC3, scalar), cpuDst2, param...); + cv::cann::setDevice(DEVICE_ID); + + cannFunc(scalar, mat, checker1, param..., AscendStream::Null()); + cannFunc(mat, scalar, checker2, param..., AscendStream::Null()); + + EXPECT_MAT_NEAR(cpuDst1, checker1, 1.0); + EXPECT_MAT_NEAR(cpuDst2, checker2, 1.0); + + AscendStream stream; + cannFunc(scalar, mat, checker1, param..., stream); + cannFunc(mat, scalar, checker2, param..., stream); + stream.waitForCompletion(); + EXPECT_MAT_NEAR(cpuDst1, checker1, 1.0); + EXPECT_MAT_NEAR(cpuDst2, checker2, 1.0); + + cv::cann::resetDevice(); +} + +template +void testAscendMatOpScalarMask(FCV cvFunc, FCANN cannFunc, DTMASK mask, PARAMS... param) +{ + Scalar scalar = randomScalar(); + Mat mat(10, 10, CV_32SC3, randomScalar()); + Mat cpuDst, checker, cpuMask; + AscendMat npuMat, npuChecker; + npuMat.upload(mat); + if (mask.empty()) + { + cvFunc(mat, Mat(10, 10, CV_32SC3, scalar), cpuDst, noArray(), param...); + } + else + { + mask.download(cpuMask); + cvFunc(mat, Mat(10, 10, CV_32SC3, scalar), cpuDst, cpuMask, param...); + } + cv::cann::setDevice(DEVICE_ID); + + cannFunc(npuMat, scalar, npuChecker, mask, param..., AscendStream::Null()); + npuChecker.download(checker); + EXPECT_MAT_NEAR(cpuDst, checker, 1.0); + + AscendStream stream; + cannFunc(npuMat, scalar, npuChecker, mask, param..., stream); + stream.waitForCompletion(); + npuChecker.download(checker); + EXPECT_MAT_NEAR(cpuDst, checker, 1.0); + + cv::cann::resetDevice(); +} +template +void testScalarOpAscendMatMask(FCV cvFunc, FCANN cannFunc, DTMASK mask, PARAMS... param) +{ + Scalar scalar = randomScalar(); + Mat mat(10, 10, CV_32SC3, randomScalar()); + Mat cpuDst, checker, cpuMask; + AscendMat npuMat, npuChecker; + npuMat.upload(mat); + if (mask.empty()) + { + cvFunc(Mat(10, 10, CV_32SC3, scalar), mat, cpuDst, noArray(), param...); + } + else + { + mask.download(cpuMask); + cvFunc(Mat(10, 10, CV_32SC3, scalar), mat, cpuDst, cpuMask, param...); + } + cv::cann::setDevice(DEVICE_ID); + + cannFunc(scalar, npuMat, npuChecker, mask, param..., AscendStream::Null()); + npuChecker.download(checker); + EXPECT_MAT_NEAR(cpuDst, checker, 1.0); + + AscendStream stream; + cannFunc(scalar, npuMat, npuChecker, mask, param..., stream); + stream.waitForCompletion(); + npuChecker.download(checker); + EXPECT_MAT_NEAR(cpuDst, checker, 1.0); + + cv::cann::resetDevice(); +} +template +void testAscendMatOpScalar(FCV cvFunc, FCANN cannFunc, PARAMS... param) +{ + Scalar scalar = randomScalar(); + Mat mat(10, 10, CV_32SC3, randomScalar()); + Mat cpuDst, checker; + AscendMat npuMat, npuChecker; + npuMat.upload(mat); + + cvFunc(mat, Mat(10, 10, CV_32SC3, scalar), cpuDst, param...); + cv::cann::setDevice(DEVICE_ID); + + cannFunc(npuMat, scalar, npuChecker, param..., AscendStream::Null()); + npuChecker.download(checker); + EXPECT_MAT_NEAR(cpuDst, checker, 1.0); + + AscendStream stream; + cannFunc(npuMat, scalar, npuChecker, param..., stream); + stream.waitForCompletion(); + npuChecker.download(checker); + + cv::cann::resetDevice(); +} + +TEST(ELEMENTWISE_OP, MAT_ADD_SCALAR) +{ + testMatOpScalar( + cv::add, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + int dtype, AscendStream& stream) + { cv::cann::add(src1, src2, dst, mask, dtype, stream); }, + noArray(), -1); + testAscendMatOpScalarMask( + cv::add, + [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, + int dtype, AscendStream& stream) + { cv::cann::add(src1, src2, dst, mask, dtype, stream); }, + AscendMat(), -1); + testScalarOpAscendMatMask( + cv::add, + [](const Scalar& src1, const AscendMat& src2, AscendMat& dst, const AscendMat& mask, + int dtype, AscendStream& stream) + { cv::cann::add(src1, src2, dst, mask, dtype, stream); }, + AscendMat(), -1); +} + +TEST(ELEMENTWISE_OP, MAT_SUB_SCALAR) +{ + testMatOpScalar( + cv::subtract, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + int dtype, AscendStream& stream) + { cv::cann::subtract(src1, src2, dst, mask, dtype, stream); }, + noArray(), -1); + testAscendMatOpScalarMask( + cv::subtract, + [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, + int dtype, AscendStream& stream) + { cv::cann::subtract(src1, src2, dst, mask, dtype, stream); }, + AscendMat(), -1); +} + +TEST(ELEMENTWISE_OP, MAT_MUL_SCALAR) +{ + testMatOpScalar( + cv::multiply, + [](const InputArray src1, const InputArray src2, OutputArray dst, float scale, int dtype, + AscendStream& stream) { cv::cann::multiply(src1, src2, dst, scale, dtype, stream); }, + 1, -1); + testAscendMatOpScalar( + cv::multiply, + [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, float scale, int dtype, + AscendStream& stream) { cv::cann::multiply(src1, src2, dst, scale, dtype, stream); }, + 1, -1); +} + +TEST(ELEMENTWISE_OP, MAT_DIV_SCALAR) +{ + testMatOpScalar( + [](const cv::Mat& src1, const cv::Mat& src2, cv::Mat& dst, double scale, int dtype) + { cv::divide(src1, src2, dst, scale, dtype); }, + [](const InputArray src1, const InputArray src2, OutputArray dst, float scale, int dtype, + AscendStream& stream) { cv::cann::divide(src1, src2, dst, scale, dtype, stream); }, + 1, -1); + testAscendMatOpScalar( + [](const cv::Mat& src1, const cv::Mat& src2, cv::Mat& dst, double scale, int dtype) + { cv::divide(src1, src2, dst, scale, dtype); }, + [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, float scale, int dtype, + AscendStream& stream) { cv::cann::divide(src1, src2, dst, scale, dtype, stream); }, + 1, -1); +} + +TEST(ELEMENTWISE_OP, MAT_BITWISE_AND_SCALAR) +{ + testMatOpScalar( + cv::bitwise_and, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) { cv::cann::bitwise_and(src1, src2, dst, mask, stream); }, + noArray()); + testAscendMatOpScalarMask( + cv::bitwise_and, + [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) { cv::cann::bitwise_and(src1, src2, dst, mask, stream); }, + AscendMat()); +} + +TEST(ELEMENTWISE_OP, MAT_BITWISE_OR_SCALAR) +{ + testMatOpScalar( + cv::bitwise_or, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) { cv::cann::bitwise_or(src1, src2, dst, mask, stream); }, + noArray()); + testAscendMatOpScalarMask( + cv::bitwise_or, + [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) { cv::cann::bitwise_or(src1, src2, dst, mask, stream); }, + AscendMat()); +} + +TEST(ELEMENTWISE_OP, MAT_BITWISE_XOR_SCALAR) +{ + testMatOpScalar( + cv::bitwise_xor, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) { cv::cann::bitwise_xor(src1, src2, dst, mask, stream); }, + noArray()); + testAscendMatOpScalarMask( + cv::bitwise_xor, + [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) { cv::cann::bitwise_xor(src1, src2, dst, mask, stream); }, + AscendMat()); +} + +TEST(ELEMENTWISE_OP, MAT_ADD_SCALAR_WITH_MASK_AND_DETYPE) +{ + testMatOpScalar( + cv::add, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + int dtype, AscendStream& stream) + { cv::cann::add(src1, src2, dst, mask, dtype, stream); }, + genMask(), CV_32SC3); + testAscendMatOpScalarMask( + cv::add, + [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, + int dtype, AscendStream& stream) + { cv::cann::add(src1, src2, dst, mask, dtype, stream); }, + genNpuMask(), CV_32SC3); +} + +TEST(ELEMENTWISE_OP, MAT_SUB_SCALAR_WITH_MASK_AND_DETYPE) +{ + testMatOpScalar( + cv::subtract, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + int dtype, AscendStream& stream) + { cv::cann::subtract(src1, src2, dst, mask, dtype, stream); }, + genMask(), CV_32SC3); + testAscendMatOpScalarMask( + cv::subtract, + [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, + int dtype, AscendStream& stream) + { cv::cann::subtract(src1, src2, dst, mask, dtype, stream); }, + genNpuMask(), CV_32SC3); +} + +TEST(ELEMENTWISE_OP, MAT_BITWISE_AND_SCALAR_WITH_MASK) +{ + testMatOpScalar( + cv::bitwise_and, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) { cv::cann::bitwise_and(src1, src2, dst, mask, stream); }, + genMask()); + testAscendMatOpScalarMask( + cv::bitwise_and, + [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) { cv::cann::bitwise_and(src1, src2, dst, mask, stream); }, + genNpuMask()); +} + +TEST(ELEMENTWISE_OP, MAT_BITWISE_OR_SCALAR_WITH_MASK) +{ + testMatOpScalar( + cv::bitwise_or, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) { cv::cann::bitwise_or(src1, src2, dst, mask, stream); }, + genMask()); + testAscendMatOpScalarMask( + cv::bitwise_or, + [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) { cv::cann::bitwise_or(src1, src2, dst, mask, stream); }, + genNpuMask()); +} + +TEST(ELEMENTWISE_OP, MAT_BITWISE_XOR_SCALAR_WITH_MASK) +{ + testMatOpScalar( + cv::bitwise_xor, + [](const InputArray src1, const InputArray src2, OutputArray dst, const InputArray mask, + AscendStream& stream) { cv::cann::bitwise_xor(src1, src2, dst, mask, stream); }, + genMask()); + testAscendMatOpScalarMask( + cv::bitwise_xor, + [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, const AscendMat& mask, + AscendStream& stream) { cv::cann::bitwise_xor(src1, src2, dst, mask, stream); }, + genNpuMask()); +} + +// TODO: I think the cv result is wrong, which has truncated middle result. +// Disable these two test case bacause it't not stable. +// TEST(ELEMENTWISE_OP, MAT_MUL_SCALAR_WITH_SCALE) +// { +// testMatOpScalar( +// cv::multiply, +// [](const InputArray src1, const InputArray src2, OutputArray dst, float scale, int dtype, +// AscendStream& stream) { cv::cann::multiply(src1, src2, dst, scale, dtype, stream); }, +// randomScale, CV_32SC3); +// testAscendMatOpScalar( +// [](const cv::Mat& src1, const cv::Mat& src2, cv::Mat& dst, double scale, int dtype) +// { cv::divide(src1, src2, dst, scale, dtype); }, +// [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, float scale, int dtype, +// AscendStream& stream) { cv::cann::divide(src1, src2, dst, scale, dtype, stream); }, +// randomScale, -1); +// } + +// TEST(ELEMENTWISE_OP, MAT_DIV_SCALAR_WITH_SCALE) +// { +// testMatOpScalar( +// [](const cv::Mat& src1, const cv::Mat& src2, cv::Mat& dst, double scale, int dtype) +// { cv::divide(src1, src2, dst, scale, dtype); }, +// [](const InputArray src1, const InputArray src2, OutputArray dst, float scale, int dtype, +// AscendStream& stream) { cv::cann::divide(src1, src2, dst, scale, dtype, stream); }, +// randomScale, -1); +// testAscendMatOpScalar( +// [](const cv::Mat& src1, const cv::Mat& src2, cv::Mat& dst, double scale, int dtype) +// { cv::divide(src1, src2, dst, scale, dtype); }, +// [](const AscendMat& src1, const Scalar& src2, AscendMat& dst, float scale, int dtype, +// AscendStream& stream) { cv::cann::divide(src1, src2, dst, scale, dtype, stream); }, +// randomScale, -1); +// } + +TEST(ELEMENTWISE_OP, MAT_BITWISE_NOT) +{ + Mat cpuOpRet, checker, cpuMat = randomMat(10, 10, CV_32SC3); + cv::cann::setDevice(DEVICE_ID); + cv::bitwise_not(cpuMat, cpuOpRet); + cv::cann::bitwise_not(cpuMat, checker); + EXPECT_MAT_NEAR(cpuOpRet, checker, 0.0); + + AscendMat npuMat, npuOpRet; + npuMat.upload(cpuMat); + cv::cann::bitwise_not(npuMat, npuOpRet); + npuOpRet.download(checker); + EXPECT_MAT_NEAR(cpuOpRet, checker, 0.0); + + cv::cann::resetDevice(); +} + +// TODO random test matrix +TEST(ELEMENTWISE_OP, MAT_ADD_WEIGHTED) +{ + Mat cpuOpRet, checker, cpuMat1 = Mat::ones(5, 5, CV_32S), cpuMat2 = Mat::ones(5, 5, CV_32S); + + cv::cann::setDevice(DEVICE_ID); + cv::addWeighted(cpuMat1, 2, cpuMat2, 3, 5, cpuOpRet); + cv::cann::addWeighted(cpuMat1, 2, cpuMat2, 3, 5, checker); + EXPECT_MAT_NEAR(cpuOpRet, checker, 0.0); + + AscendMat npuOpRet, npuMat1, npuMat2; + npuMat1.upload(cpuMat1); + npuMat2.upload(cpuMat2); + cv::cann::addWeighted(npuMat1, 2, npuMat2, 3, 5, npuOpRet); + npuOpRet.download(checker); + EXPECT_MAT_NEAR(cpuOpRet, checker, 0.0); + + cv::cann::resetDevice(); +} + +TEST(ELEMENTWISE_OP, MAT_THRESHOLD) +{ + Mat cpuOpRet, checker, cpuMat = randomMat(10, 10, CV_16SC3, 0.0, 255.0); + + AscendMat ascendMat, ascendMat16F, aclOpRet, aclOpRet16S; + cv::cann::setDevice(DEVICE_ID); + ascendMat.upload(cpuMat); + ascendMat.convertTo(ascendMat16F, CV_16F); + + Mat cpuMat16F, checker16F; + cpuMat.convertTo(cpuMat16F, CV_16F); + + for (int i = 0; i <= 4; i++) + { + cv::threshold(cpuMat, cpuOpRet, 128, 250, i); + // TODO find the reason empty AscendMat is not continuous. + cv::cann::threshold(ascendMat16F, aclOpRet, 128, 250, i); + aclOpRet.convertTo(aclOpRet16S, CV_16S); + aclOpRet16S.download(checker); + + EXPECT_MAT_NEAR(cpuOpRet, checker, 1e-10); + + cv::cann::threshold(cpuMat16F, checker16F, 128, 250, i); + checker16F.convertTo(checker, CV_16S); + EXPECT_MAT_NEAR(cpuOpRet, checker, 1e-10); + } + + cv::cann::resetDevice(); +} + +} // namespace +} // namespace opencv_test diff --git a/modules/cannops/test/test_main.cpp b/modules/cannops/test/test_main.cpp new file mode 100644 index 00000000000..202c6af27ee --- /dev/null +++ b/modules/cannops/test/test_main.cpp @@ -0,0 +1,21 @@ +// 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" + +class CannEnvironment : public ::testing::Environment +{ +public: + virtual ~CannEnvironment() = default; + virtual void SetUp() CV_OVERRIDE { initAcl(); } + virtual void TearDown() CV_OVERRIDE { finalizeAcl(); } +}; + +static void initTests() +{ + CannEnvironment* cannEnv = new CannEnvironment(); + ::testing::AddGlobalTestEnvironment(cannEnv); +} + +CV_TEST_MAIN("cannops", initTests()); diff --git a/modules/cannops/test/test_npumat.cpp b/modules/cannops/test/test_npumat.cpp new file mode 100644 index 00000000000..1ff445399f8 --- /dev/null +++ b/modules/cannops/test/test_npumat.cpp @@ -0,0 +1,146 @@ +// 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 +{ + +class DummyAllocator : public AscendMat::Allocator +{ +public: + std::shared_ptr allocate(size_t size) CV_OVERRIDE + { + CV_UNUSED(size); + return std::shared_ptr(); + } + bool allocate(cv::cann::AscendMat* mat, int rows, int cols, size_t elemSize) CV_OVERRIDE + { + CV_UNUSED(rows); + CV_UNUSED(cols); + CV_UNUSED(elemSize); + mat->data = std::shared_ptr((uchar*)0x12345, [](void* ptr) { CV_UNUSED(ptr); }); + return true; + } +}; + +TEST(AscendMat, Construct) +{ + cv::cann::setDevice(0); + // 1 Default constructor. + AscendMat defaultAscendMat; + AscendMat::Allocator* defaultAllocator = AscendMat::defaultAllocator(); + ASSERT_EQ(defaultAscendMat.allocator, defaultAllocator); + + // 2 get & set allocator. + DummyAllocator dummyAllocator; + AscendMat::setDefaultAllocator(&dummyAllocator); + ASSERT_EQ(defaultAscendMat.defaultAllocator(), &dummyAllocator); + AscendMat::setDefaultAllocator(defaultAllocator); + + // 3 constructs AscendMat of the specified size and type + AscendMat specifiedSizeAscendMat1(5, 6, CV_8UC3); + AscendMat specifiedSizeAscendMat2(Size(300, 200), CV_64F); + + ASSERT_EQ(specifiedSizeAscendMat1.rows, 5); + ASSERT_EQ(specifiedSizeAscendMat1.cols, 6); + ASSERT_EQ(specifiedSizeAscendMat1.depth(), CV_8U); + ASSERT_EQ(specifiedSizeAscendMat1.channels(), 3); + + ASSERT_EQ(specifiedSizeAscendMat2.cols, 300); + ASSERT_EQ(specifiedSizeAscendMat2.rows, 200); + ASSERT_EQ(specifiedSizeAscendMat2.depth(), CV_64F); + ASSERT_EQ(specifiedSizeAscendMat2.channels(), 1); + + // 4 constructs AscendMat and fills it with the specified value s + srand((unsigned int)(time(NULL))); + Scalar sc(rand() % 256, rand() % 256, rand() % 256, rand() % 256); + + Mat scalarToMat(7, 8, CV_8UC3, sc); + AscendMat scalarToAscendMat1(7, 8, CV_8UC3, sc); + Mat scalarToMatChecker; + scalarToAscendMat1.download(scalarToMatChecker); + + EXPECT_MAT_NEAR(scalarToMat, scalarToMatChecker, 0.0); + + AscendMat scalarToAscendMat2(Size(123, 345), CV_32S); + + ASSERT_EQ(scalarToAscendMat1.rows, 7); + ASSERT_EQ(scalarToAscendMat1.cols, 8); + ASSERT_EQ(scalarToAscendMat1.depth(), CV_8U); + ASSERT_EQ(scalarToAscendMat1.channels(), 3); + + ASSERT_EQ(scalarToAscendMat2.cols, 123); + ASSERT_EQ(scalarToAscendMat2.rows, 345); + ASSERT_EQ(scalarToAscendMat2.depth(), CV_32S); + ASSERT_EQ(scalarToAscendMat2.channels(), 1); + + // 6 builds AscendMat from host memory + Scalar sc2(rand() % 256, rand() % 256, rand() % 256, rand() % 256); + Mat randomMat(7, 8, CV_8UC3, sc2); + InputArray arr = randomMat; + + AscendMat fromInputArray(arr, AscendStream::Null()); + Mat randomMatChecker; + fromInputArray.download(randomMatChecker); + EXPECT_MAT_NEAR(randomMat, randomMatChecker, 0.0); + + cv::cann::resetDevice(); +} + +TEST(AscendMat, Assignment) +{ + DummyAllocator dummyAllocator; + AscendMat mat1; + AscendMat mat2(3, 4, CV_8SC1, &dummyAllocator); + mat1 = mat2; + + ASSERT_EQ(mat1.rows, 3); + ASSERT_EQ(mat1.cols, 4); + ASSERT_EQ(mat1.depth(), CV_8S); + ASSERT_EQ(mat1.channels(), 1); + ASSERT_EQ(mat1.data.get(), (uchar*)0x12345); +} + +TEST(AscendMat, SetTo) +{ + cv::cann::setDevice(0); + + srand((unsigned int)(time(NULL))); + Scalar sc(rand() % 256, rand() % 256, rand() % 256, rand() % 256); + + AscendMat ascendMat(2, 2, CV_8UC4); + ascendMat.setTo(sc); + Mat mat(2, 2, CV_8UC4, sc); + Mat checker; + ascendMat.download(checker); + + EXPECT_MAT_NEAR(mat, checker, 0.0); + + cv::cann::resetDevice(); +} + +TEST(AscendMat, ConvertTo) +{ + cv::cann::setDevice(0); + + srand((unsigned int)(time(NULL))); + Scalar sc(rand() % 256, rand() % 256, rand() % 256, rand() % 256); + + AscendMat ascendMat(2, 2, CV_8UC4, sc); + AscendMat convertedAscendMat; + ascendMat.convertTo(convertedAscendMat, CV_16S); + Mat mat(2, 2, CV_16SC4, sc); + Mat checker; + convertedAscendMat.download(checker); + + EXPECT_MAT_NEAR(mat, checker, 0.0); + + cv::cann::resetDevice(); +} + +} // namespace +} // namespace opencv_test diff --git a/modules/cannops/test/test_precomp.hpp b/modules/cannops/test/test_precomp.hpp new file mode 100644 index 00000000000..f7bdbea0b08 --- /dev/null +++ b/modules/cannops/test/test_precomp.hpp @@ -0,0 +1,28 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef __OPENCV_TEST_PRECOMP_HPP__ +#define __OPENCV_TEST_PRECOMP_HPP__ + +#include "opencv2/ts.hpp" +#include "opencv2/cann.hpp" +#include "opencv2/ts/cuda_test.hpp" +#include "opencv2/cann_interface.hpp" + +using namespace cv; +using namespace cv::cann; +#undef EXPECT_MAT_NEAR +#define EXPECT_MAT_NEAR(m1, m2, eps) EXPECT_PRED_FORMAT3(cvtest::assertMatNear, m1, m2, eps) +#define ASSERT_MAT_NEAR(m1, m2, eps) ASSERT_PRED_FORMAT3(cvtest::assertMatNear, m1, m2, eps) + +#define DEVICE_ID 0 + +Mat randomMat(int w, int h, int dtype, float min = 1.0f, float max = 10.0f); +Scalar randomScalar(); +float randomNum(); +int randomInterger(); +Mat genMask(); +AscendMat genNpuMask(); + +#endif //__OPENCV_TEST_PRECOMP_HPP__ diff --git a/modules/cannops/test/test_utils.cpp b/modules/cannops/test/test_utils.cpp new file mode 100644 index 00000000000..d2bd31647b7 --- /dev/null +++ b/modules/cannops/test/test_utils.cpp @@ -0,0 +1,49 @@ +// 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" + +// Random Generator +Mat randomMat(int w, int h, int dtype, float min, float max) +{ + Mat rnMat(w, h, dtype); + RNG rng(getTickCount()); + rng.fill(rnMat, RNG::UNIFORM, min, max); + return rnMat; +} +Scalar randomScalar() +{ + RNG rng(getTickCount()); + Scalar sc; + rng.fill(sc, RNG::UNIFORM, 1.0, 5.0); + return sc; +} +float randomNum() +{ + RNG rng(getTickCount()); + float rdnNum = float(rng.uniform(1.0, 5.0)); + return rdnNum; +} + +int randomInterger() +{ + RNG rng(getTickCount()); + float rdnNum = float(rng.uniform(1, 5)); + return rdnNum; +} + +Mat genMask() +{ + Mat mask = Mat::zeros(Size(10, 10), CV_8UC1); + rectangle(mask, cv::Rect(5, 5, 3, 3), Scalar(255), -1); + return mask; +} + +AscendMat genNpuMask() +{ + cv::Mat mask = genMask(); + cv::cann::AscendMat npuMask; + npuMask.upload(mask); + return npuMask; +} diff --git a/modules/cannops/tutorials/ascend_npu_image_processing.markdown b/modules/cannops/tutorials/ascend_npu_image_processing.markdown new file mode 100644 index 00000000000..ed905831d31 --- /dev/null +++ b/modules/cannops/tutorials/ascend_npu_image_processing.markdown @@ -0,0 +1,130 @@ +Ascend NPU Image Processing {#tutorial_ascend_npu_image_processing} +========================================================== + +## Goal + +In this guide, you will gain insights into the thread safety of Ascend operators already in use, as well as discover how to effectively employ Ascend operators for image preprocessing and understand their usage limitations. + +## Preface + +We provide a suite of common matrix operation operators that support the [Ascend NPU](https://www.hiascend.com/en/) within OpenCV. For user convenience, the new 'AscendMat' structure and its associated operators maintain compatibility with the 'Mat' interface in OpenCV. These operators encompass a wide range of frequently used functions, including arithmetic operations, image processing operations, and image color space conversion. All of these operators are implemented utilizing [CANN](https://www.hiascend.com/en/software/cann)(Compute Architecture of Neural Networks). The Ascend operator facilitates accelerated operations on the NPU by making use of CANN. This acceleration effect is particularly noticeable when working with larger images, such as those with dimensions like 2048x2048, 3840x2160, 7680x4320, etc. + + +## Instructions on Thread Safety + +Our stream function is implemented by invoking the CANN operators. In the same stream, tasks are executed sequentially, while across different streams, tasks are executed in parallel. The use of event mechanisms ensures synchronization of tasks between streams, please refer to the [**Stream Management**](https://www.hiascend.com/document/detail/en/CANNCommunityEdition/600alphaX/infacldevg/aclcppdevg/aclcppdevg_000147.html) documentation for details. + + +## Example for Image Preprocessing + +In this section, you will discover how to use Ascend operators for image preprocessing, including functions below: + +- Add +- Rotate +- Flip + + +### code + +@add_toggle_cpp +@include opencv_contrib/modules/cannops/samples/image_processing.cpp +@end_toggle + +@add_toggle_python +@include opencv_contrib/modules/cannops/samples/image_processing.py +@end_toggle + +### Explanation + +**Input Image** + +@add_toggle_cpp +@snippet opencv_contrib/modules/cannops/samples/image_processing.cpp input_noise +@end_toggle + +@add_toggle_python + +```python +# Read the input image +img = cv2.imread("/path/to/img") +# Generate gauss noise that will be added into the input image +gaussNoise = np.random.normal(mean=0,sigma=25,(img.shape[0],img.shape[1],img.shape[2])).astype(img.dtype) +``` + +@end_toggle + +**Setup CANN** + +@add_toggle_cpp + +@snippet opencv_contrib/modules/cannops/samples/image_processing.cpp setup + +@end_toggle + +@add_toggle_python + +@snippet opencv_contrib/modules/cannops/samples/image_processing.py setup + +@end_toggle +**Image Preprocessing Example** + +@add_toggle_cpp + +@snippet opencv_contrib/modules/cannops/samples/image_processing.cpp image-process + +@end_toggle + +@add_toggle_python + +@snippet opencv_contrib/modules/cannops/samples/image_processing.py image-process + +@end_toggle + +**Tear down CANN** + +@add_toggle_cpp +@snippet opencv_contrib/modules/cannops/samples/image_processing.cpp tear-down-cann + +@end_toggle + +@add_toggle_python + +@snippet opencv_contrib/modules/cannops/samples/image_processing.py tear-down-cann + +@end_toggle +Results + +1. The original RGB input image with dimensions of (480, 640, 3): + + ![puppy](./puppy.jpg) + +2. After introducing Gaussian noise, we obtain the following result: + + ![puppy_noisy](./puppy_noisy.jpg) + +3. When applying the rotate operation with a rotation code of 0 (90 degrees clockwise), we obtain this result: + + ![puppy_noisy_rotate](./puppy_noisy_rotate.jpg) + +4. Upon applying the flip operation with a flip code of 0 (flipping around the x-axis), we achieve the final result: + + ![puppy_processed_normalized](./puppy_processed.jpg) + + + +## Usage Limitations + +While Ascend supports most commonly used operators, there are still some limitations that need to be addressed. + +- There is no strict limit on the size of the input image used for encoding; however, it depends on the available RAM size of your device. +- Please note that not all data types (dtypes) are supported by every operator. The current dtype limitations are outlined in the following table. We are actively working on addressing these limitations through automatic dtype conversion in an upcoming commit. + + +| Operator | Supported Dtype | +| ---------------------- | ------------------------------------------------------------ | +| multiply (with scale) | float16,float32,int32 | +| divide (with scale) | float16,float,int32,int8,uint8 | +| bitwise add/or/xor/not | int32,int16,uint16 | +| flip | float16,float,int64,int32,int16,uint16 | +| transpose | float16,float,int64,int32,int16,int8,uint64,uint32,uint16,uint8,bool | +| rotate | float16,float,int64,int32,int16,uint16 | diff --git a/modules/cannops/tutorials/puppy.jpg b/modules/cannops/tutorials/puppy.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b0f0595e5ce5c24832d0a02d5653ce61d429e984 GIT binary patch literal 49852 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 literal 0 HcmV?d00001 diff --git a/modules/cannops/tutorials/puppy_noisy.jpg b/modules/cannops/tutorials/puppy_noisy.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e90cadb1720fad3833dd4737cc8ec8ea36558730 GIT binary patch literal 168316 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͚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 literal 0 HcmV?d00001 diff --git a/modules/cannops/tutorials/puppy_processed.jpg b/modules/cannops/tutorials/puppy_processed.jpg new file mode 100644 index 0000000000000000000000000000000000000000..296b47aefeaaa1191dd80d8c8ee2a4f70834d13b GIT binary patch literal 168163 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

ngbsZS=inbbim1{-1{O%sD^E^-lIUP8w% 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 literal 0 HcmV?d00001