Commit 0395b2ea authored by Alexander Alekhin's avatar Alexander Alekhin

Merge pull request #13650 from terfendail:shapedescr_wintr

parents 3812ae79 a84bbc62
...@@ -84,4 +84,26 @@ PERF_TEST_P(TestFindContoursFF, findContours, ...@@ -84,4 +84,26 @@ PERF_TEST_P(TestFindContoursFF, findContours,
SANITY_CHECK_NOTHING(); SANITY_CHECK_NOTHING();
} }
typedef TestBaseWithParam< tuple<MatDepth, int> > TestBoundingRect;
PERF_TEST_P(TestBoundingRect, BoundingRect,
Combine(
testing::Values(CV_32S, CV_32F), // points type
Values(400, 511, 1000, 10000, 100000) // points count
)
)
{
int ptType = get<0>(GetParam());
int n = get<1>(GetParam());
Mat pts(n, 2, ptType);
declare.in(pts, WARMUP_RNG);
cv::Rect rect;
TEST_CYCLE() rect = boundingRect(pts);
SANITY_CHECK_NOTHING();
}
} } // namespace } } // namespace
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
// //
//M*/ //M*/
#include "precomp.hpp" #include "precomp.hpp"
#include "opencv2/core/hal/intrin.hpp"
namespace cv namespace cv
{ {
...@@ -746,109 +748,161 @@ static Rect pointSetBoundingRect( const Mat& points ) ...@@ -746,109 +748,161 @@ static Rect pointSetBoundingRect( const Mat& points )
if( npoints == 0 ) if( npoints == 0 )
return Rect(); return Rect();
const Point* pts = points.ptr<Point>(); #if CV_SIMD
Point pt = pts[0]; const int64_t* pts = points.ptr<int64_t>();
#if CV_SSE4_2 if( !is_float )
if(cv::checkHardwareSupport(CV_CPU_SSE4_2))
{ {
if( !is_float ) 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
for( i = 1; i <= npoints - v_int32::nlanes/2; i+= v_int32::nlanes/2 )
{ {
__m128i minval, maxval; v_int32 ptXY2 = v_reinterpret_as_s32(vx_load(pts + i));
minval = maxval = _mm_loadl_epi64((const __m128i*)(&pt)); //min[0]=pt.x, min[1]=pt.y minval = v_min(ptXY2, minval);
maxval = v_max(ptXY2, maxval);
for( i = 1; i < npoints; i++ )
{
__m128i ptXY = _mm_loadl_epi64((const __m128i*)&pts[i]);
minval = _mm_min_epi32(ptXY, minval);
maxval = _mm_max_epi32(ptXY, maxval);
}
xmin = _mm_cvtsi128_si32(minval);
ymin = _mm_cvtsi128_si32(_mm_srli_si128(minval, 4));
xmax = _mm_cvtsi128_si32(maxval);
ymax = _mm_cvtsi128_si32(_mm_srli_si128(maxval, 4));
} }
else minval = v_min(v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(minval))), v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(minval))));
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 - v_int32::nlanes/4 )
{ {
__m128 minvalf, maxvalf, z = _mm_setzero_ps(), ptXY = _mm_setzero_ps(); v_int32 ptXY = v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(vx_load_low(pts + i))));
minvalf = maxvalf = _mm_loadl_pi(z, (const __m64*)(&pt)); minval = v_min(ptXY, minval);
maxval = v_max(ptXY, maxval);
for( i = 1; i < npoints; i++ ) i += v_int64::nlanes/2;
}
for(int j = 16; j < CV_SIMD_WIDTH; j*=2)
{
minval = v_min(v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(minval))), v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(minval))));
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))));
}
xmin = minval.get0();
xmax = maxval.get0();
ymin = v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(minval))).get0();
ymax = v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(maxval))).get0();
#if CV_SIMD_WIDTH > 16
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))));
for( i++; i < npoints; i++ )
{ {
ptXY = _mm_loadl_pi(ptXY, (const __m64*)&pts[i]); v_int32x4 ptXY = v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + i))));
minval2 = v_min(ptXY, minval2);
minvalf = _mm_min_ps(minvalf, ptXY); maxval2 = v_max(ptXY, maxval2);
maxvalf = _mm_max_ps(maxvalf, ptXY);
} }
xmin = min(xmin, minval2.get0());
float xyminf[2], xymaxf[2]; xmax = max(xmax, maxval2.get0());
_mm_storel_pi((__m64*)xyminf, minvalf); ymin = min(ymin, v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(minval2))).get0());
_mm_storel_pi((__m64*)xymaxf, maxvalf); ymax = max(ymax, v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(maxval2))).get0());
xmin = cvFloor(xyminf[0]);
ymin = cvFloor(xyminf[1]);
xmax = cvFloor(xymaxf[0]);
ymax = cvFloor(xymaxf[1]);
} }
#endif
} }
else else
#endif
{ {
if( !is_float ) 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
for( i = 1; i <= npoints - v_float32::nlanes/2; i+= v_float32::nlanes/2 )
{ {
xmin = xmax = pt.x; v_float32 ptXY2 = v_reinterpret_as_f32(vx_load(pts + i));
ymin = ymax = pt.y; minval = v_min(ptXY2, minval);
maxval = v_max(ptXY2, maxval);
for( i = 1; i < npoints; i++ ) }
minval = v_min(v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(minval))), v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(minval))));
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 - v_float32::nlanes/4 )
{
v_float32 ptXY = v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(vx_load_low(pts + i))));
minval = v_min(ptXY, minval);
maxval = v_max(ptXY, maxval);
i += v_float32::nlanes/4;
}
for(int j = 16; j < CV_SIMD_WIDTH; j*=2)
{
minval = v_min(v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(minval))), v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(minval))));
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))));
}
xmin = cvFloor(minval.get0());
xmax = cvFloor(maxval.get0());
ymin = cvFloor(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(minval))).get0());
ymax = cvFloor(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(maxval))).get0());
#if CV_SIMD_WIDTH > 16
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))));
for( i++; i < npoints; i++ )
{ {
pt = pts[i]; v_float32x4 ptXY = v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + i))));
minval2 = v_min(ptXY, minval2);
maxval2 = v_max(ptXY, maxval2);
}
xmin = min(xmin, cvFloor(minval2.get0()));
xmax = max(xmax, cvFloor(maxval2.get0()));
ymin = min(ymin, cvFloor(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(minval2))).get0()));
ymax = max(ymax, cvFloor(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(maxval2))).get0()));
}
#endif
}
#else
const Point* pts = points.ptr<Point>();
Point pt = pts[0];
if( xmin > pt.x ) if( !is_float )
xmin = pt.x; {
xmin = xmax = pt.x;
ymin = ymax = pt.y;
if( xmax < pt.x ) for( i = 1; i < npoints; i++ )
xmax = pt.x; {
pt = pts[i];
if( ymin > pt.y ) if( xmin > pt.x )
ymin = pt.y; xmin = pt.x;
if( ymax < pt.y ) if( xmax < pt.x )
ymax = pt.y; xmax = pt.x;
}
}
else
{
Cv32suf v;
// init values
xmin = xmax = CV_TOGGLE_FLT(pt.x);
ymin = ymax = CV_TOGGLE_FLT(pt.y);
for( i = 1; i < npoints; i++ ) if( ymin > pt.y )
{ ymin = pt.y;
pt = pts[i];
pt.x = CV_TOGGLE_FLT(pt.x);
pt.y = CV_TOGGLE_FLT(pt.y);
if( xmin > pt.x ) if( ymax < pt.y )
xmin = pt.x; ymax = pt.y;
}
}
else
{
Cv32suf v;
// init values
xmin = xmax = CV_TOGGLE_FLT(pt.x);
ymin = ymax = CV_TOGGLE_FLT(pt.y);
if( xmax < pt.x ) for( i = 1; i < npoints; i++ )
xmax = pt.x; {
pt = pts[i];
pt.x = CV_TOGGLE_FLT(pt.x);
pt.y = CV_TOGGLE_FLT(pt.y);
if( ymin > pt.y ) if( xmin > pt.x )
ymin = pt.y; xmin = pt.x;
if( ymax < pt.y ) if( xmax < pt.x )
ymax = pt.y; xmax = pt.x;
}
if( ymin > pt.y )
ymin = pt.y;
v.i = CV_TOGGLE_FLT(xmin); xmin = cvFloor(v.f); if( ymax < pt.y )
v.i = CV_TOGGLE_FLT(ymin); ymin = cvFloor(v.f); ymax = pt.y;
// because right and bottom sides of the bounding rectangle are not inclusive
// (note +1 in width and height calculation below), cvFloor is used here instead of cvCeil
v.i = CV_TOGGLE_FLT(xmax); xmax = cvFloor(v.f);
v.i = CV_TOGGLE_FLT(ymax); ymax = cvFloor(v.f);
} }
v.i = CV_TOGGLE_FLT(xmin); xmin = cvFloor(v.f);
v.i = CV_TOGGLE_FLT(ymin); ymin = cvFloor(v.f);
// because right and bottom sides of the bounding rectangle are not inclusive
// (note +1 in width and height calculation below), cvFloor is used here instead of cvCeil
v.i = CV_TOGGLE_FLT(xmax); xmax = cvFloor(v.f);
v.i = CV_TOGGLE_FLT(ymax); ymax = cvFloor(v.f);
} }
#endif
return Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); return Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment