mirror of
https://github.com/opencv/opencv.git
synced 2024-11-27 20:50:25 +08:00
Merge pull request #25439 from mshabunin:cpp-contours-5-back
imgproc: sync boundingRect function with 5.x
This commit is contained in:
commit
a1e4444fb5
@ -39,7 +39,9 @@
|
||||
//
|
||||
//M*/
|
||||
#include "precomp.hpp"
|
||||
#include "opencv2/core/hal/intrin.hpp"
|
||||
|
||||
using namespace cv;
|
||||
|
||||
CV_IMPL CvRect
|
||||
cvMaxRect( const CvRect* rect1, const CvRect* rect2 )
|
||||
@ -592,3 +594,332 @@ float cv::intersectConvexConvex( InputArray _p1, InputArray _p2, OutputArray _p1
|
||||
}
|
||||
return (float)fabs(area);
|
||||
}
|
||||
|
||||
static Rect maskBoundingRect( const Mat& img )
|
||||
{
|
||||
CV_Assert( img.depth() <= CV_8S && img.channels() == 1 );
|
||||
|
||||
Size size = img.size();
|
||||
int xmin = size.width, ymin = -1, xmax = -1, ymax = -1, i, j, k;
|
||||
|
||||
for( i = 0; i < size.height; i++ )
|
||||
{
|
||||
const uchar* _ptr = img.ptr(i);
|
||||
const uchar* ptr = (const uchar*)alignPtr(_ptr, 4);
|
||||
int have_nz = 0, k_min, offset = (int)(ptr - _ptr);
|
||||
j = 0;
|
||||
offset = MIN(offset, size.width);
|
||||
for( ; j < offset; j++ )
|
||||
if( _ptr[j] )
|
||||
{
|
||||
if( j < xmin )
|
||||
xmin = j;
|
||||
if( j > xmax )
|
||||
xmax = j;
|
||||
have_nz = 1;
|
||||
}
|
||||
if( offset < size.width )
|
||||
{
|
||||
xmin -= offset;
|
||||
xmax -= offset;
|
||||
size.width -= offset;
|
||||
j = 0;
|
||||
for( ; j <= xmin - 4; j += 4 )
|
||||
if( *((int*)(ptr+j)) )
|
||||
break;
|
||||
for( ; j < xmin; j++ )
|
||||
if( ptr[j] )
|
||||
{
|
||||
xmin = j;
|
||||
if( j > xmax )
|
||||
xmax = j;
|
||||
have_nz = 1;
|
||||
break;
|
||||
}
|
||||
k_min = MAX(j-1, xmax);
|
||||
k = size.width - 1;
|
||||
for( ; k > k_min && (k&3) != 3; k-- )
|
||||
if( ptr[k] )
|
||||
break;
|
||||
if( k > k_min && (k&3) == 3 )
|
||||
{
|
||||
for( ; k > k_min+3; k -= 4 )
|
||||
if( *((int*)(ptr+k-3)) )
|
||||
break;
|
||||
}
|
||||
for( ; k > k_min; k-- )
|
||||
if( ptr[k] )
|
||||
{
|
||||
xmax = k;
|
||||
have_nz = 1;
|
||||
break;
|
||||
}
|
||||
if( !have_nz )
|
||||
{
|
||||
j &= ~3;
|
||||
for( ; j <= k - 3; j += 4 )
|
||||
if( *((int*)(ptr+j)) )
|
||||
break;
|
||||
for( ; j <= k; j++ )
|
||||
if( ptr[j] )
|
||||
{
|
||||
have_nz = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
xmin += offset;
|
||||
xmax += offset;
|
||||
size.width += offset;
|
||||
}
|
||||
if( have_nz )
|
||||
{
|
||||
if( ymin < 0 )
|
||||
ymin = i;
|
||||
ymax = i;
|
||||
}
|
||||
}
|
||||
|
||||
if( xmin >= size.width )
|
||||
xmin = ymin = 0;
|
||||
return Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
|
||||
}
|
||||
|
||||
// Calculates bounding rectangle of a point set or retrieves already calculated
|
||||
static Rect pointSetBoundingRect( const Mat& points )
|
||||
{
|
||||
int npoints = points.checkVector(2);
|
||||
int depth = points.depth();
|
||||
CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_32S));
|
||||
|
||||
int xmin = 0, ymin = 0, xmax = -1, ymax = -1, i;
|
||||
bool is_float = depth == CV_32F;
|
||||
|
||||
if( npoints == 0 )
|
||||
return Rect();
|
||||
|
||||
#if CV_SIMD // TODO: enable for CV_SIMD_SCALABLE, loop tail related.
|
||||
const int64_t* pts = points.ptr<int64_t>();
|
||||
|
||||
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 - VTraits<v_int32>::vlanes()/2; i+= VTraits<v_int32>::vlanes()/2 )
|
||||
{
|
||||
v_int32 ptXY2 = v_reinterpret_as_s32(vx_load(pts + i));
|
||||
minval = v_min(ptXY2, minval);
|
||||
maxval = v_max(ptXY2, maxval);
|
||||
}
|
||||
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 - VTraits<v_int32>::vlanes()/4 )
|
||||
{
|
||||
v_int32 ptXY = v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(vx_load_low(pts + i))));
|
||||
minval = v_min(ptXY, minval);
|
||||
maxval = v_max(ptXY, maxval);
|
||||
i += VTraits<v_int64>::vlanes()/2;
|
||||
}
|
||||
for(int j = 16; j < VTraits<v_uint8>::vlanes(); 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 = v_get0(minval);
|
||||
xmax = v_get0(maxval);
|
||||
ymin = v_get0(v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(minval))));
|
||||
ymax = v_get0(v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(maxval))));
|
||||
#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++ )
|
||||
{
|
||||
v_int32x4 ptXY = v_reinterpret_as_s32(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, v_get0(minval2));
|
||||
xmax = max(xmax, v_get0(maxval2));
|
||||
ymin = min(ymin, v_get0(v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(minval2)))));
|
||||
ymax = max(ymax, v_get0(v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(maxval2)))));
|
||||
}
|
||||
#endif // CV_SIMD
|
||||
}
|
||||
else
|
||||
{
|
||||
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 - VTraits<v_float32>::vlanes()/2; i+= VTraits<v_float32>::vlanes()/2 )
|
||||
{
|
||||
v_float32 ptXY2 = v_reinterpret_as_f32(vx_load(pts + i));
|
||||
minval = v_min(ptXY2, minval);
|
||||
maxval = v_max(ptXY2, maxval);
|
||||
}
|
||||
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 - VTraits<v_float32>::vlanes()/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 += VTraits<v_float32>::vlanes()/4;
|
||||
}
|
||||
for(int j = 16; j < VTraits<v_uint8>::vlanes(); 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(v_get0(minval));
|
||||
xmax = cvFloor(v_get0(maxval));
|
||||
ymin = cvFloor(v_get0(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(minval)))));
|
||||
ymax = cvFloor(v_get0(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(maxval)))));
|
||||
#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++ )
|
||||
{
|
||||
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(v_get0(minval2)));
|
||||
xmax = max(xmax, cvFloor(v_get0(maxval2)));
|
||||
ymin = min(ymin, cvFloor(v_get0(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(minval2))))));
|
||||
ymax = max(ymax, cvFloor(v_get0(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(maxval2))))));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
const Point* pts = points.ptr<Point>();
|
||||
Point pt = pts[0];
|
||||
|
||||
if( !is_float )
|
||||
{
|
||||
xmin = xmax = pt.x;
|
||||
ymin = ymax = pt.y;
|
||||
|
||||
for( i = 1; i < npoints; i++ )
|
||||
{
|
||||
pt = pts[i];
|
||||
|
||||
if( xmin > pt.x )
|
||||
xmin = pt.x;
|
||||
|
||||
if( xmax < pt.x )
|
||||
xmax = pt.x;
|
||||
|
||||
if( ymin > pt.y )
|
||||
ymin = pt.y;
|
||||
|
||||
if( ymax < pt.y )
|
||||
ymax = pt.y;
|
||||
}
|
||||
}
|
||||
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++ )
|
||||
{
|
||||
pt = pts[i];
|
||||
pt.x = CV_TOGGLE_FLT(pt.x);
|
||||
pt.y = CV_TOGGLE_FLT(pt.y);
|
||||
|
||||
if( xmin > pt.x )
|
||||
xmin = pt.x;
|
||||
|
||||
if( xmax < pt.x )
|
||||
xmax = pt.x;
|
||||
|
||||
if( ymin > pt.y )
|
||||
ymin = pt.y;
|
||||
|
||||
if( ymax < pt.y )
|
||||
ymax = pt.y;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
cv::Rect cv::boundingRect(InputArray array)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
Mat m = array.getMat();
|
||||
return m.depth() <= CV_8U ? maskBoundingRect(m) : pointSetBoundingRect(m);
|
||||
}
|
||||
|
||||
|
||||
/* Calculates bounding rectangle of a point set or retrieves already calculated */
|
||||
CV_IMPL CvRect
|
||||
cvBoundingRect( CvArr* array, int update )
|
||||
{
|
||||
cv::Rect rect;
|
||||
CvContour contour_header;
|
||||
CvSeq* ptseq = 0;
|
||||
CvSeqBlock block;
|
||||
|
||||
CvMat stub, *mat = 0;
|
||||
int calculate = update;
|
||||
|
||||
if( CV_IS_SEQ( array ))
|
||||
{
|
||||
ptseq = (CvSeq*)array;
|
||||
if( !CV_IS_SEQ_POINT_SET( ptseq ))
|
||||
CV_Error( cv::Error::StsBadArg, "Unsupported sequence type" );
|
||||
|
||||
if( ptseq->header_size < (int)sizeof(CvContour))
|
||||
{
|
||||
update = 0;
|
||||
calculate = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mat = cvGetMat( array, &stub );
|
||||
if( CV_MAT_TYPE(mat->type) == CV_32SC2 ||
|
||||
CV_MAT_TYPE(mat->type) == CV_32FC2 )
|
||||
{
|
||||
ptseq = cvPointSeqFromMat(CV_SEQ_KIND_GENERIC, mat, &contour_header, &block);
|
||||
mat = 0;
|
||||
}
|
||||
else if( CV_MAT_TYPE(mat->type) != CV_8UC1 &&
|
||||
CV_MAT_TYPE(mat->type) != CV_8SC1 )
|
||||
CV_Error( cv::Error::StsUnsupportedFormat,
|
||||
"The image/matrix format is not supported by the function" );
|
||||
update = 0;
|
||||
calculate = 1;
|
||||
}
|
||||
|
||||
if( !calculate )
|
||||
return ((CvContour*)ptseq)->rect;
|
||||
|
||||
if( mat )
|
||||
{
|
||||
rect = cvRect(maskBoundingRect(cv::cvarrToMat(mat)));
|
||||
}
|
||||
else if( ptseq->total )
|
||||
{
|
||||
cv::AutoBuffer<double> abuf;
|
||||
rect = cvRect(pointSetBoundingRect(cv::cvarrToMat(ptseq, false, false, 0, &abuf)));
|
||||
}
|
||||
if( update )
|
||||
((CvContour*)ptseq)->rect = cvRect(rect);
|
||||
return cvRect(rect);
|
||||
}
|
||||
|
@ -862,282 +862,6 @@ cv::RotatedRect cv::fitEllipseDirect( InputArray _points )
|
||||
return box;
|
||||
}
|
||||
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
// Calculates bounding rectangle of a point set or retrieves already calculated
|
||||
static Rect pointSetBoundingRect( const Mat& points )
|
||||
{
|
||||
int npoints = points.checkVector(2);
|
||||
int depth = points.depth();
|
||||
CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_32S));
|
||||
|
||||
int xmin = 0, ymin = 0, xmax = -1, ymax = -1, i;
|
||||
bool is_float = depth == CV_32F;
|
||||
|
||||
if( npoints == 0 )
|
||||
return Rect();
|
||||
|
||||
#if CV_SIMD // TODO: enable for CV_SIMD_SCALABLE, loop tail related.
|
||||
const int64_t* pts = points.ptr<int64_t>();
|
||||
|
||||
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 - VTraits<v_int32>::vlanes()/2; i+= VTraits<v_int32>::vlanes()/2 )
|
||||
{
|
||||
v_int32 ptXY2 = v_reinterpret_as_s32(vx_load(pts + i));
|
||||
minval = v_min(ptXY2, minval);
|
||||
maxval = v_max(ptXY2, maxval);
|
||||
}
|
||||
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 - VTraits<v_int32>::vlanes()/4 )
|
||||
{
|
||||
v_int32 ptXY = v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(vx_load_low(pts + i))));
|
||||
minval = v_min(ptXY, minval);
|
||||
maxval = v_max(ptXY, maxval);
|
||||
i += VTraits<v_int64>::vlanes()/2;
|
||||
}
|
||||
for(int j = 16; j < VTraits<v_uint8>::vlanes(); 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 = v_get0(minval);
|
||||
xmax = v_get0(maxval);
|
||||
ymin = v_get0(v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(minval))));
|
||||
ymax = v_get0(v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(maxval))));
|
||||
#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++ )
|
||||
{
|
||||
v_int32x4 ptXY = v_reinterpret_as_s32(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, v_get0(minval2));
|
||||
xmax = max(xmax, v_get0(maxval2));
|
||||
ymin = min(ymin, v_get0(v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(minval2)))));
|
||||
ymax = max(ymax, v_get0(v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(maxval2)))));
|
||||
}
|
||||
#endif // CV_SIMD
|
||||
}
|
||||
else
|
||||
{
|
||||
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 - VTraits<v_float32>::vlanes()/2; i+= VTraits<v_float32>::vlanes()/2 )
|
||||
{
|
||||
v_float32 ptXY2 = v_reinterpret_as_f32(vx_load(pts + i));
|
||||
minval = v_min(ptXY2, minval);
|
||||
maxval = v_max(ptXY2, maxval);
|
||||
}
|
||||
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 - VTraits<v_float32>::vlanes()/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 += VTraits<v_float32>::vlanes()/4;
|
||||
}
|
||||
for(int j = 16; j < VTraits<v_uint8>::vlanes(); 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(v_get0(minval));
|
||||
xmax = cvFloor(v_get0(maxval));
|
||||
ymin = cvFloor(v_get0(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(minval)))));
|
||||
ymax = cvFloor(v_get0(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(maxval)))));
|
||||
#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++ )
|
||||
{
|
||||
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(v_get0(minval2)));
|
||||
xmax = max(xmax, cvFloor(v_get0(maxval2)));
|
||||
ymin = min(ymin, cvFloor(v_get0(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(minval2))))));
|
||||
ymax = max(ymax, cvFloor(v_get0(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(maxval2))))));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
const Point* pts = points.ptr<Point>();
|
||||
Point pt = pts[0];
|
||||
|
||||
if( !is_float )
|
||||
{
|
||||
xmin = xmax = pt.x;
|
||||
ymin = ymax = pt.y;
|
||||
|
||||
for( i = 1; i < npoints; i++ )
|
||||
{
|
||||
pt = pts[i];
|
||||
|
||||
if( xmin > pt.x )
|
||||
xmin = pt.x;
|
||||
|
||||
if( xmax < pt.x )
|
||||
xmax = pt.x;
|
||||
|
||||
if( ymin > pt.y )
|
||||
ymin = pt.y;
|
||||
|
||||
if( ymax < pt.y )
|
||||
ymax = pt.y;
|
||||
}
|
||||
}
|
||||
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++ )
|
||||
{
|
||||
pt = pts[i];
|
||||
pt.x = CV_TOGGLE_FLT(pt.x);
|
||||
pt.y = CV_TOGGLE_FLT(pt.y);
|
||||
|
||||
if( xmin > pt.x )
|
||||
xmin = pt.x;
|
||||
|
||||
if( xmax < pt.x )
|
||||
xmax = pt.x;
|
||||
|
||||
if( ymin > pt.y )
|
||||
ymin = pt.y;
|
||||
|
||||
if( ymax < pt.y )
|
||||
ymax = pt.y;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static Rect maskBoundingRect( const Mat& img )
|
||||
{
|
||||
CV_Assert( img.depth() <= CV_8S && img.channels() == 1 );
|
||||
|
||||
Size size = img.size();
|
||||
int xmin = size.width, ymin = -1, xmax = -1, ymax = -1, i, j, k;
|
||||
|
||||
for( i = 0; i < size.height; i++ )
|
||||
{
|
||||
const uchar* _ptr = img.ptr(i);
|
||||
const uchar* ptr = (const uchar*)alignPtr(_ptr, 4);
|
||||
int have_nz = 0, k_min, offset = (int)(ptr - _ptr);
|
||||
j = 0;
|
||||
offset = MIN(offset, size.width);
|
||||
for( ; j < offset; j++ )
|
||||
if( _ptr[j] )
|
||||
{
|
||||
if( j < xmin )
|
||||
xmin = j;
|
||||
if( j > xmax )
|
||||
xmax = j;
|
||||
have_nz = 1;
|
||||
}
|
||||
if( offset < size.width )
|
||||
{
|
||||
xmin -= offset;
|
||||
xmax -= offset;
|
||||
size.width -= offset;
|
||||
j = 0;
|
||||
for( ; j <= xmin - 4; j += 4 )
|
||||
if( *((int*)(ptr+j)) )
|
||||
break;
|
||||
for( ; j < xmin; j++ )
|
||||
if( ptr[j] )
|
||||
{
|
||||
xmin = j;
|
||||
if( j > xmax )
|
||||
xmax = j;
|
||||
have_nz = 1;
|
||||
break;
|
||||
}
|
||||
k_min = MAX(j-1, xmax);
|
||||
k = size.width - 1;
|
||||
for( ; k > k_min && (k&3) != 3; k-- )
|
||||
if( ptr[k] )
|
||||
break;
|
||||
if( k > k_min && (k&3) == 3 )
|
||||
{
|
||||
for( ; k > k_min+3; k -= 4 )
|
||||
if( *((int*)(ptr+k-3)) )
|
||||
break;
|
||||
}
|
||||
for( ; k > k_min; k-- )
|
||||
if( ptr[k] )
|
||||
{
|
||||
xmax = k;
|
||||
have_nz = 1;
|
||||
break;
|
||||
}
|
||||
if( !have_nz )
|
||||
{
|
||||
j &= ~3;
|
||||
for( ; j <= k - 3; j += 4 )
|
||||
if( *((int*)(ptr+j)) )
|
||||
break;
|
||||
for( ; j <= k; j++ )
|
||||
if( ptr[j] )
|
||||
{
|
||||
have_nz = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
xmin += offset;
|
||||
xmax += offset;
|
||||
size.width += offset;
|
||||
}
|
||||
if( have_nz )
|
||||
{
|
||||
if( ymin < 0 )
|
||||
ymin = i;
|
||||
ymax = i;
|
||||
}
|
||||
}
|
||||
|
||||
if( xmin >= size.width )
|
||||
xmin = ymin = 0;
|
||||
return Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cv::Rect cv::boundingRect(InputArray array)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
Mat m = array.getMat();
|
||||
return m.depth() <= CV_8U ? maskBoundingRect(m) : pointSetBoundingRect(m);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////// C API ///////////////////////////////////////////
|
||||
|
||||
CV_IMPL int
|
||||
@ -1478,62 +1202,4 @@ cvFitEllipse2( const CvArr* array )
|
||||
return cvBox2D(cv::fitEllipse(points));
|
||||
}
|
||||
|
||||
/* Calculates bounding rectangle of a point set or retrieves already calculated */
|
||||
CV_IMPL CvRect
|
||||
cvBoundingRect( CvArr* array, int update )
|
||||
{
|
||||
cv::Rect rect;
|
||||
CvContour contour_header;
|
||||
CvSeq* ptseq = 0;
|
||||
CvSeqBlock block;
|
||||
|
||||
CvMat stub, *mat = 0;
|
||||
int calculate = update;
|
||||
|
||||
if( CV_IS_SEQ( array ))
|
||||
{
|
||||
ptseq = (CvSeq*)array;
|
||||
if( !CV_IS_SEQ_POINT_SET( ptseq ))
|
||||
CV_Error( cv::Error::StsBadArg, "Unsupported sequence type" );
|
||||
|
||||
if( ptseq->header_size < (int)sizeof(CvContour))
|
||||
{
|
||||
update = 0;
|
||||
calculate = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mat = cvGetMat( array, &stub );
|
||||
if( CV_MAT_TYPE(mat->type) == CV_32SC2 ||
|
||||
CV_MAT_TYPE(mat->type) == CV_32FC2 )
|
||||
{
|
||||
ptseq = cvPointSeqFromMat(CV_SEQ_KIND_GENERIC, mat, &contour_header, &block);
|
||||
mat = 0;
|
||||
}
|
||||
else if( CV_MAT_TYPE(mat->type) != CV_8UC1 &&
|
||||
CV_MAT_TYPE(mat->type) != CV_8SC1 )
|
||||
CV_Error( cv::Error::StsUnsupportedFormat,
|
||||
"The image/matrix format is not supported by the function" );
|
||||
update = 0;
|
||||
calculate = 1;
|
||||
}
|
||||
|
||||
if( !calculate )
|
||||
return ((CvContour*)ptseq)->rect;
|
||||
|
||||
if( mat )
|
||||
{
|
||||
rect = cvRect(cv::maskBoundingRect(cv::cvarrToMat(mat)));
|
||||
}
|
||||
else if( ptseq->total )
|
||||
{
|
||||
cv::AutoBuffer<double> abuf;
|
||||
rect = cvRect(cv::pointSetBoundingRect(cv::cvarrToMat(ptseq, false, false, 0, &abuf)));
|
||||
}
|
||||
if( update )
|
||||
((CvContour*)ptseq)->rect = cvRect(rect);
|
||||
return cvRect(rect);
|
||||
}
|
||||
|
||||
/* End of file. */
|
||||
|
Loading…
Reference in New Issue
Block a user