diff --git a/modules/imgproc/src/geometry.cpp b/modules/imgproc/src/geometry.cpp index 8cf2474787..ae582fcafc 100644 --- a/modules/imgproc/src/geometry.cpp +++ b/modules/imgproc/src/geometry.cpp @@ -698,15 +698,16 @@ static Rect pointSetBoundingRect( const Mat& points ) return Rect(); #if CV_SIMD // TODO: enable for CV_SIMD_SCALABLE, loop tail related. - const int64_t* pts = points.ptr(); - if( !is_float ) { + const int32_t* pts = points.ptr(); + int64_t firstval = 0; + std::memcpy(&firstval, pts, sizeof(pts[0]) * 2); v_int32 minval, maxval; - minval = maxval = v_reinterpret_as_s32(vx_setall_s64(*pts)); //min[0]=pt.x, min[1]=pt.y, min[2]=pt.x, min[3]=pt.y + minval = maxval = v_reinterpret_as_s32(vx_setall_s64(firstval)); //min[0]=pt.x, min[1]=pt.y, min[2]=pt.x, min[3]=pt.y for( i = 1; i <= npoints - VTraits::vlanes()/2; i+= VTraits::vlanes()/2 ) { - v_int32 ptXY2 = v_reinterpret_as_s32(vx_load(pts + i)); + v_int32 ptXY2 = vx_load(pts + 2 * i); minval = v_min(ptXY2, minval); maxval = v_max(ptXY2, maxval); } @@ -714,7 +715,7 @@ static Rect pointSetBoundingRect( const Mat& points ) maxval = v_max(v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(maxval))), v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(maxval)))); if( i <= npoints - VTraits::vlanes()/4 ) { - v_int32 ptXY = v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(vx_load_low(pts + i)))); + v_int32 ptXY = v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(vx_load_low(pts + 2 * i)))); minval = v_min(ptXY, minval); maxval = v_max(ptXY, maxval); i += VTraits::vlanes()/2; @@ -732,10 +733,10 @@ static Rect pointSetBoundingRect( const Mat& points ) if( i < npoints ) { v_int32x4 minval2, maxval2; - minval2 = maxval2 = v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + i)))); + minval2 = maxval2 = v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + 2 * i)))); for( i++; i < npoints; i++ ) { - v_int32x4 ptXY = v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + i)))); + v_int32x4 ptXY = v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + 2 * i)))); minval2 = v_min(ptXY, minval2); maxval2 = v_max(ptXY, maxval2); } @@ -748,11 +749,14 @@ static Rect pointSetBoundingRect( const Mat& points ) } else { + const float* pts = points.ptr(); + int64_t firstval = 0; + std::memcpy(&firstval, pts, sizeof(pts[0]) * 2); v_float32 minval, maxval; - minval = maxval = v_reinterpret_as_f32(vx_setall_s64(*pts)); //min[0]=pt.x, min[1]=pt.y, min[2]=pt.x, min[3]=pt.y + minval = maxval = v_reinterpret_as_f32(vx_setall_s64(firstval)); //min[0]=pt.x, min[1]=pt.y, min[2]=pt.x, min[3]=pt.y for( i = 1; i <= npoints - VTraits::vlanes()/2; i+= VTraits::vlanes()/2 ) { - v_float32 ptXY2 = v_reinterpret_as_f32(vx_load(pts + i)); + v_float32 ptXY2 = vx_load(pts + 2 * i); minval = v_min(ptXY2, minval); maxval = v_max(ptXY2, maxval); } @@ -760,7 +764,7 @@ static Rect pointSetBoundingRect( const Mat& points ) maxval = v_max(v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(maxval))), v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(maxval)))); if( i <= npoints - VTraits::vlanes()/4 ) { - v_float32 ptXY = v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(vx_load_low(pts + i)))); + v_float32 ptXY = v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(vx_load_low(pts + 2 * i)))); minval = v_min(ptXY, minval); maxval = v_max(ptXY, maxval); i += VTraits::vlanes()/4; @@ -778,10 +782,10 @@ static Rect pointSetBoundingRect( const Mat& points ) if( i < npoints ) { v_float32x4 minval2, maxval2; - minval2 = maxval2 = v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + i)))); + minval2 = maxval2 = v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + 2 * i)))); for( i++; i < npoints; i++ ) { - v_float32x4 ptXY = v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + i)))); + v_float32x4 ptXY = v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + 2 * i)))); minval2 = v_min(ptXY, minval2); maxval2 = v_max(ptXY, maxval2); } diff --git a/modules/imgproc/test/test_boundingrect.cpp b/modules/imgproc/test/test_boundingrect.cpp index d3e5495b4f..cf70b66e04 100644 --- a/modules/imgproc/test/test_boundingrect.cpp +++ b/modules/imgproc/test/test_boundingrect.cpp @@ -1,146 +1,86 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2009, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ +// 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 "opencv2/core/types.hpp" #include "test_precomp.hpp" -namespace opencv_test { namespace { - -#define IMGPROC_BOUNDINGRECT_ERROR_DIFF 1 +using namespace cv; +using namespace std; -#define MESSAGE_ERROR_DIFF "Bounding rectangle found by boundingRect function is incorrect." - -class CV_BoundingRectTest: public cvtest::ArrayTest -{ -public: - CV_BoundingRectTest(); - ~CV_BoundingRectTest(); - -protected: - void run (int); - -private: - template void generate_src_points(vector >& src, int n); - template cv::Rect get_bounding_rect(const vector > src); - template bool checking_function_work(vector >& src, int type); -}; +namespace opencv_test { namespace { -CV_BoundingRectTest::CV_BoundingRectTest() {} -CV_BoundingRectTest::~CV_BoundingRectTest() {} -template void CV_BoundingRectTest::generate_src_points(vector >& src, int n) +template +cv::Rect calcBoundingRect(Mat pts) { - src.clear(); - for (int i = 0; i < n; ++i) - src.push_back(Point_(cv::randu(), cv::randu())); + CV_Assert(pts.type() == CV_32FC2 || pts.type() == CV_32SC2); + CV_Assert(pts.size().width == 1 && pts.size().height > 0); + const int N = pts.size().height; + // NOTE: using ::lowest(), not ::min() + T min_w = std::numeric_limits::max(), max_w = std::numeric_limits::lowest(); + T min_h = min_w, max_h = max_w; + for (int i = 0; i < N; ++i) + { + const Point_ & pt = pts.at>(i, 0); + min_w = std::min(pt.x, min_w); + max_w = std::max(pt.x, max_w); + min_h = std::min(pt.y, min_h); + max_h = std::max(pt.y, max_h); + } + return Rect(cvFloor(min_w), cvFloor(min_h), cvFloor(max_w) - cvFloor(min_w) + 1, cvFloor(max_h) - cvFloor(min_h) + 1); } -template cv::Rect CV_BoundingRectTest::get_bounding_rect(const vector > src) -{ - int n = (int)src.size(); - T min_w = std::numeric_limits::max(), max_w = std::numeric_limits::min(); - T min_h = min_w, max_h = max_w; +typedef ::testing::TestWithParam Imgproc_BoundingRect_Types; - for (int i = 0; i < n; ++i) +TEST_P(Imgproc_BoundingRect_Types, accuracy) +{ + const int depth = GetParam(); + RNG& rng = ::cvtest::TS::ptr()->get_rng(); + for (int k = 0; k < 1000; ++k) { - min_w = std::min(src.at(i).x, min_w); - max_w = std::max(src.at(i).x, max_w); - min_h = std::min(src.at(i).y, min_h); - max_h = std::max(src.at(i).y, max_h); + SCOPED_TRACE(cv::format("k=%d", k)); + const int sz = rng.uniform(1, 10000); + Mat src(sz, 1, CV_MAKETYPE(depth, 2)); + rng.fill(src, RNG::UNIFORM, Scalar(-100000, -100000), Scalar(100000, 100000)); + Rect reference; + if (depth == CV_32F) + reference = calcBoundingRect(src); + else if (depth == CV_32S) + reference = calcBoundingRect(src); + else + CV_Error(Error::StsError, "Test error"); + Rect result = cv::boundingRect(src); + EXPECT_EQ(reference, result); } - - return Rect((int)min_w, (int)min_h, (int)max_w-(int)min_w + 1, (int)max_h-(int)min_h + 1); } -template bool CV_BoundingRectTest::checking_function_work(vector >& src, int type) +TEST_P(Imgproc_BoundingRect_Types, alignment) { - const int MAX_COUNT_OF_POINTS = 1000; - const int N = 10000; - - for (int k = 0; k < N; ++k) + const int depth = GetParam(); + const int SZ = 100; + int idata[SZ]; + float fdata[SZ]; + for (int i = 0; i < SZ; ++i) { - - RNG& rng = ts->get_rng(); - - int n = rng.next()%MAX_COUNT_OF_POINTS + 1; - - generate_src_points (src, n); - - cv::Rect right = get_bounding_rect (src); - - cv::Rect rect[2] = { boundingRect(src), boundingRect(Mat(src)) }; - - for (int i = 0; i < 2; ++i) if (rect[i] != right) + idata[i] = i; + fdata[i] = (float)i; + } + for (int i = 0; i < 10; ++i) + { + for (int len = 1; len < 40; ++len) { - cout << endl; cout << "Checking for the work of boundingRect function..." << endl; - cout << "Type of src points: "; - switch (type) - { - case 0: {cout << "INT"; break;} - case 1: {cout << "FLOAT"; break;} - default: break; - } - cout << endl; - cout << "Src points are stored as "; if (i == 0) cout << "VECTOR" << endl; else cout << "MAT" << endl; - cout << "Number of points: " << n << endl; - cout << "Right rect (x, y, w, h): [" << right.x << ", " << right.y << ", " << right.width << ", " << right.height << "]" << endl; - cout << "Result rect (x, y, w, h): [" << rect[i].x << ", " << rect[i].y << ", " << rect[i].width << ", " << rect[i].height << "]" << endl; - cout << endl; - CV_Error(IMGPROC_BOUNDINGRECT_ERROR_DIFF, MESSAGE_ERROR_DIFF); + SCOPED_TRACE(cv::format("i=%d, len=%d", i, len)); + Mat sub(len, 1, CV_MAKETYPE(depth, 2), (depth == CV_32S) ? (void*)(idata + i) : (void*)(fdata + i)); + EXPECT_NO_THROW(boundingRect(sub)); } - } - - return true; } -void CV_BoundingRectTest::run(int) -{ - vector src_veci; if (!checking_function_work(src_veci, 0)) return; - vector src_vecf; checking_function_work(src_vecf, 1); -} +INSTANTIATE_TEST_CASE_P(, Imgproc_BoundingRect_Types, ::testing::Values(CV_32S, CV_32F)); -TEST (Imgproc_BoundingRect, accuracy) { CV_BoundingRectTest test; test.safe_run(); } -TEST (Imgproc_BoundingRect, bug_24217) +TEST(Imgproc_BoundingRect, bug_24217) { for (int image_width = 3; image_width < 20; image_width++) {