1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 15:53:03 +04:00

Merge pull request #29225 from asmorkalov:as/more_contours_geometry

Move more 2d funcs to geometry module.
This commit is contained in:
Alexander Smorkalov
2026-06-04 12:20:06 +03:00
committed by GitHub
14 changed files with 398 additions and 394 deletions
@@ -806,6 +806,56 @@ CV_EXPORTS_W double pointPolygonTest( InputArray contour, Point2f pt, bool measu
*/
CV_EXPORTS_W int rotatedRectangleIntersection( const RotatedRect& rect1, const RotatedRect& rect2, OutputArray intersectingRegion );
/** @brief Calculates a contour perimeter or a curve length.
*
* The function computes a curve length or a closed contour perimeter.
*
* @param curve Input vector of 2D points, stored in std::vector or Mat.
* @param closed Flag indicating whether the curve is closed or not.
*/
CV_EXPORTS_W double arcLength( InputArray curve, bool closed );
/** @brief Calculates a contour area.
*
* The function computes a contour area. Similarly to moments , the area is computed using the Green
* formula. Thus, the returned area and the number of non-zero pixels, if you draw the contour using
* #drawContours or #fillPoly , can be different. Also, the function will most certainly give a wrong
* results for contours with self-intersections.
*
* Example:
* @code
* vector<Point> contour;
* contour.push_back(Point2f(0, 0));
* contour.push_back(Point2f(10, 0));
* contour.push_back(Point2f(10, 10));
* contour.push_back(Point2f(5, 4));
*
* double area0 = contourArea(contour);
* vector<Point> approx;
* approxPolyDP(contour, approx, 5, true);
* double area1 = contourArea(approx);
*
* cout << "area0 =" << area0 << endl <<
* "area1 =" << area1 << endl <<
* "approx poly vertices" << approx.size() << endl;
* @endcode
* @param contour Input vector of 2D points (contour vertices), stored in std::vector or Mat.
* @param oriented Oriented area flag. If it is true, the function returns a signed area value,
* depending on the contour orientation (clockwise or counter-clockwise). Using this feature you can
* determine orientation of a contour by taking the sign of an area. By default, the parameter is
* false, which means that the absolute value is returned.
*/
CV_EXPORTS_W double contourArea( InputArray contour, bool oriented = false );
/** @brief Calculates the up-right bounding rectangle of a point set or non-zero pixels of gray-scale image.
*
* The function calculates and returns the minimal up-right bounding rectangle for the specified point set or
* non-zero pixels of gray-scale image.
*
* @param array Input gray-scale image or 2D point set, stored in std::vector or Mat.
*/
CV_EXPORTS_W Rect boundingRect( InputArray array );
} // namespace cv
#endif // OPENCV_2D_HPP
@@ -10,6 +10,7 @@ import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfDouble;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Rect;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.MatOfPoint3f;
import org.opencv.core.MatOfInt;
@@ -733,7 +734,7 @@ public class GeometryTest extends OpenCVTestCase {
assertEquals(100.0f, radius[0], 1.0);
}
public void testPointPolygonTest() {
public void testPointPolygonTest() {
MatOfPoint2f contour = new MatOfPoint2f(new Point(0, 0), new Point(1, 3), new Point(3, 4), new Point(4, 3), new Point(2, 1));
double sign1 = Geometry.pointPolygonTest(contour, new Point(2, 2), false);
assertEquals(1.0, sign1);
@@ -741,4 +742,42 @@ public class GeometryTest extends OpenCVTestCase {
double sign2 = Geometry.pointPolygonTest(contour, new Point(4, 4), true);
assertEquals(-Math.sqrt(0.5), sign2);
}
public void testContourAreaMat() {
Mat contour = new Mat(1, 4, CvType.CV_32FC2);
contour.put(0, 0, 0, 0, 10, 0, 10, 10, 5, 4);
double area = Geometry.contourArea(contour);
assertEquals(45., area, EPS);
}
public void testContourAreaMatBoolean() {
Mat contour = new Mat(1, 4, CvType.CV_32FC2);
contour.put(0, 0, 0, 0, 10, 0, 10, 10, 5, 4);
double area = Geometry.contourArea(contour, true);
assertEquals(45., area, EPS);
// TODO_: write better test
}
public void testArcLength() {
MatOfPoint2f curve = new MatOfPoint2f(new Point(1, 3), new Point(2, 4), new Point(3, 5), new Point(4, 4), new Point(5, 3));
double arcLength = Geometry.arcLength(curve, false);
assertEquals(5.656854249, arcLength, 0.000001);
}
public void testBoundingRect() {
MatOfPoint points = new MatOfPoint(new Point(0, 0), new Point(0, 4), new Point(4, 0), new Point(4, 4));
Point p1 = new Point(1, 1);
Point p2 = new Point(-5, -2);
Rect bbox = Geometry.boundingRect(points);
assertTrue(bbox.contains(p1));
assertFalse(bbox.contains(p2));
}
}
+22
View File
@@ -9,6 +9,28 @@ namespace opencv_test { namespace {
using namespace perf;
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();
}
typedef TestBaseWithParam< tuple<MatDepth, int> > TestMinEnclosingCircle;
PERF_TEST_P(TestMinEnclosingCircle, minEnclosingCircle,
Combine(
+278
View File
@@ -433,6 +433,284 @@ static int intersectConvexConvex_( const Point2f* P, int n, const Point2f* Q, in
return nr-1;
}
// area of a whole sequence
double contourArea( InputArray _contour, bool oriented )
{
CV_INSTRUMENT_REGION();
Mat contour = _contour.getMat();
int npoints = contour.checkVector(2);
int depth = contour.depth();
CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_32S));
if( npoints == 0 )
return 0.;
double a00 = 0;
bool is_float = depth == CV_32F;
const Point* ptsi = contour.ptr<Point>();
const Point2f* ptsf = contour.ptr<Point2f>();
Point2f prev = is_float ? ptsf[npoints-1] : Point2f((float)ptsi[npoints-1].x, (float)ptsi[npoints-1].y);
for( int i = 0; i < npoints; i++ )
{
Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
a00 += (double)prev.x * p.y - (double)prev.y * p.x;
prev = p;
}
a00 *= 0.5;
if( !oriented )
a00 = fabs(a00);
return a00;
}
// calculates length of a curve (e.g. contour perimeter)
double arcLength( InputArray _curve, bool is_closed )
{
CV_INSTRUMENT_REGION();
Mat curve = _curve.getMat();
int count = curve.checkVector(2);
int depth = curve.depth();
CV_Assert( count >= 0 && (depth == CV_32F || depth == CV_32S));
double perimeter = 0;
int i;
if( count <= 1 )
return 0.;
bool is_float = depth == CV_32F;
int last = is_closed ? count-1 : 0;
const Point* pti = curve.ptr<Point>();
const Point2f* ptf = curve.ptr<Point2f>();
Point2f prev = is_float ? ptf[last] : Point2f((float)pti[last].x,(float)pti[last].y);
for( i = 0; i < count; i++ )
{
Point2f p = is_float ? ptf[i] : Point2f((float)pti[i].x,(float)pti[i].y);
float dx = p.x - prev.x, dy = p.y - prev.y;
perimeter += std::sqrt(dx*dx + dy*dy);
prev = p;
}
return perimeter;
}
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 = 0;
bool is_float = depth == CV_32F;
if( npoints == 0 )
return Rect();
if( !is_float )
{
const int32_t* pts = points.ptr<int32_t>();
int64_t firstval = 0;
std::memcpy(&firstval, pts, sizeof(pts[0]) * 2);
xmin = xmax = pts[0];
ymin = ymax = pts[1];
#if CV_SIMD || CV_SIMD_SCALABLE
v_int32 minval, maxval;
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
const int nlanes = VTraits<v_int32>::vlanes()/2;
for (; i < npoints; i += nlanes)
{
if (i > npoints - nlanes)
{
if (i == 0)
break;
i = npoints - nlanes;
}
v_int32 ptXY2 = vx_load(pts + 2 * i);
minval = v_min(ptXY2, minval);
maxval = v_max(ptXY2, maxval);
}
constexpr int max_nlanes = VTraits<v_int32>::max_nlanes;
int arr_minval[max_nlanes], arr_maxval[max_nlanes];
vx_store(arr_minval, minval);
vx_store(arr_maxval, maxval);
for (int j = 0; j < nlanes; j++)
{
xmin = std::min(xmin, arr_minval[2*j]);
ymin = std::min(ymin, arr_minval[2*j+1]);
xmax = std::max(xmax, arr_maxval[2*j]);
ymax = std::max(ymax, arr_maxval[2*j+1]);
}
#endif
for( ; i < npoints; i++ )
{
int pt_x = pts[2*i];
int pt_y = pts[2*i+1];
xmin = std::min(xmin, pt_x);
xmax = std::max(xmax, pt_x);
ymin = std::min(ymin, pt_y);
ymax = std::max(ymax, pt_y);
}
}
else
{
const float* pts = points.ptr<float>();
int64_t firstval = 0;
std::memcpy(&firstval, pts, sizeof(pts[0]) * 2);
xmin = xmax = cvFloor(pts[0]);
ymin = ymax = cvFloor(pts[1]);
#if CV_SIMD || CV_SIMD_SCALABLE
v_float32 minval, maxval;
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
const int nlanes = VTraits<v_float32>::vlanes()/2;
for (; i < npoints; i += nlanes)
{
if (i > npoints - nlanes)
{
if (i == 0)
break;
i = npoints - nlanes;
}
v_float32 ptXY2 = vx_load(pts + 2 * i);
minval = v_min(ptXY2, minval);
maxval = v_max(ptXY2, maxval);
}
constexpr int max_nlanes = VTraits<v_int32>::max_nlanes;
float arr_minval[max_nlanes], arr_maxval[max_nlanes];
vx_store(arr_minval, minval);
vx_store(arr_maxval, maxval);
for (int j = 0; j < nlanes; j++)
{
int _xmin = cvFloor(arr_minval[2*j]), _ymin = cvFloor(arr_minval[2*j+1]);
int _xmax = cvFloor(arr_maxval[2*j]), _ymax = cvFloor(arr_maxval[2*j+1]);
xmin = std::min(xmin, _xmin);
ymin = std::min(ymin, _ymin);
xmax = std::max(xmax, _xmax);
ymax = std::max(ymax, _ymax);
}
#endif
for( ; i < npoints; i++ )
{
// 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
int pt_x = cvFloor(pts[2*i]);
int pt_y = cvFloor(pts[2*i+1]);
xmin = std::min(xmin, pt_x);
xmax = std::max(xmax, pt_x);
ymin = std::min(ymin, pt_y);
ymax = std::max(ymax, pt_y);
}
}
return Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
}
cv::Rect boundingRect(InputArray array)
{
CV_INSTRUMENT_REGION();
Mat m = array.getMat();
return m.depth() <= CV_8U ? maskBoundingRect(m) : pointSetBoundingRect(m);
}
}
float cv::intersectConvexConvex( InputArray _p1, InputArray _p2, OutputArray _p12, bool handleNested )
@@ -3616,57 +3616,6 @@ CV_EXPORTS_W void findContoursLinkRuns(InputArray image, OutputArrayOfArrays con
//! @overload
CV_EXPORTS_W void findContoursLinkRuns(InputArray image, OutputArrayOfArrays contours);
/** @brief Calculates the up-right bounding rectangle of a point set or non-zero pixels of gray-scale image.
*
* The function calculates and returns the minimal up-right bounding rectangle for the specified point set or
* non-zero pixels of gray-scale image.
*
* @param array Input gray-scale image or 2D point set, stored in std::vector or Mat.
*/
CV_EXPORTS_W Rect boundingRect( InputArray array );
/** @brief Calculates a contour perimeter or a curve length.
The function computes a curve length or a closed contour perimeter.
@param curve Input vector of 2D points, stored in std::vector or Mat.
@param closed Flag indicating whether the curve is closed or not.
*/
CV_EXPORTS_W double arcLength( InputArray curve, bool closed );
/** @brief Calculates a contour area.
The function computes a contour area. Similarly to moments , the area is computed using the Green
formula. Thus, the returned area and the number of non-zero pixels, if you draw the contour using
#drawContours or #fillPoly , can be different. Also, the function will most certainly give a wrong
results for contours with self-intersections.
Example:
@code
vector<Point> contour;
contour.push_back(Point2f(0, 0));
contour.push_back(Point2f(10, 0));
contour.push_back(Point2f(10, 10));
contour.push_back(Point2f(5, 4));
double area0 = contourArea(contour);
vector<Point> approx;
approxPolyDP(contour, approx, 5, true);
double area1 = contourArea(approx);
cout << "area0 =" << area0 << endl <<
"area1 =" << area1 << endl <<
"approx poly vertices" << approx.size() << endl;
@endcode
@param contour Input vector of 2D points (contour vertices), stored in std::vector or Mat.
@param oriented Oriented area flag. If it is true, the function returns a signed area value,
depending on the contour orientation (clockwise or counter-clockwise). Using this feature you can
determine orientation of a contour by taking the sign of an area. By default, the parameter is
false, which means that the absolute value is returned.
*/
CV_EXPORTS_W double contourArea( InputArray contour, bool oriented = false );
/** @brief Creates a smart pointer to a cv::GeneralizedHoughBallard class and initializes it.
*/
CV_EXPORTS_W Ptr<GeneralizedHoughBallard> createGeneralizedHoughBallard();
@@ -145,14 +145,6 @@ public class ImgprocTest extends OpenCVTestCase {
assertEquals(src.rows(), Core.countNonZero(dst));
}
public void testArcLength() {
MatOfPoint2f curve = new MatOfPoint2f(new Point(1, 3), new Point(2, 4), new Point(3, 5), new Point(4, 4), new Point(5, 3));
double arcLength = Imgproc.arcLength(curve, false);
assertEquals(5.656854249, arcLength, 0.000001);
}
public void testBilateralFilterMatMatIntDoubleDouble() {
Imgproc.bilateralFilter(gray255, dst, 5, 10, 5);
@@ -188,17 +180,6 @@ public class ImgprocTest extends OpenCVTestCase {
// TODO_: write better test
}
public void testBoundingRect() {
MatOfPoint points = new MatOfPoint(new Point(0, 0), new Point(0, 4), new Point(4, 0), new Point(4, 4));
Point p1 = new Point(1, 1);
Point p2 = new Point(-5, -2);
Rect bbox = Imgproc.boundingRect(points);
assertTrue(bbox.contains(p1));
assertFalse(bbox.contains(p2));
}
public void testBoxFilterMatMatIntSize() {
Size size = new Size(3, 3);
Imgproc.boxFilter(gray0, dst, 0, size);
@@ -347,25 +328,6 @@ public class ImgprocTest extends OpenCVTestCase {
assertEquals(1., distance, EPS);
}
public void testContourAreaMat() {
Mat contour = new Mat(1, 4, CvType.CV_32FC2);
contour.put(0, 0, 0, 0, 10, 0, 10, 10, 5, 4);
double area = Imgproc.contourArea(contour);
assertEquals(45., area, EPS);
}
public void testContourAreaMatBoolean() {
Mat contour = new Mat(1, 4, CvType.CV_32FC2);
contour.put(0, 0, 0, 0, 10, 0, 10, 10, 5, 4);
double area = Imgproc.contourArea(contour, true);
assertEquals(45., area, EPS);
// TODO_: write better test
}
public void testConvertMapsMatMatMatMatInt() {
Mat map1 = new Mat(1, 4, CvType.CV_32FC1, new Scalar(1));
Mat map2 = new Mat(1, 4, CvType.CV_32FC1, new Scalar(2));
-22
View File
@@ -84,28 +84,6 @@ PERF_TEST_P(TestFindContoursFF, findContours,
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();
}
// ============================================================
// findTRUContours performance tests
// ============================================================
-278
View File
@@ -12,284 +12,6 @@
using namespace std;
using namespace cv;
// calculates length of a curve (e.g. contour perimeter)
double cv::arcLength( InputArray _curve, bool is_closed )
{
CV_INSTRUMENT_REGION();
Mat curve = _curve.getMat();
int count = curve.checkVector(2);
int depth = curve.depth();
CV_Assert( count >= 0 && (depth == CV_32F || depth == CV_32S));
double perimeter = 0;
int i;
if( count <= 1 )
return 0.;
bool is_float = depth == CV_32F;
int last = is_closed ? count-1 : 0;
const Point* pti = curve.ptr<Point>();
const Point2f* ptf = curve.ptr<Point2f>();
Point2f prev = is_float ? ptf[last] : Point2f((float)pti[last].x,(float)pti[last].y);
for( i = 0; i < count; i++ )
{
Point2f p = is_float ? ptf[i] : Point2f((float)pti[i].x,(float)pti[i].y);
float dx = p.x - prev.x, dy = p.y - prev.y;
perimeter += std::sqrt(dx*dx + dy*dy);
prev = p;
}
return perimeter;
}
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 = 0;
bool is_float = depth == CV_32F;
if( npoints == 0 )
return Rect();
if( !is_float )
{
const int32_t* pts = points.ptr<int32_t>();
int64_t firstval = 0;
std::memcpy(&firstval, pts, sizeof(pts[0]) * 2);
xmin = xmax = pts[0];
ymin = ymax = pts[1];
#if CV_SIMD || CV_SIMD_SCALABLE
v_int32 minval, maxval;
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
const int nlanes = VTraits<v_int32>::vlanes()/2;
for (; i < npoints; i += nlanes)
{
if (i > npoints - nlanes)
{
if (i == 0)
break;
i = npoints - nlanes;
}
v_int32 ptXY2 = vx_load(pts + 2 * i);
minval = v_min(ptXY2, minval);
maxval = v_max(ptXY2, maxval);
}
constexpr int max_nlanes = VTraits<v_int32>::max_nlanes;
int arr_minval[max_nlanes], arr_maxval[max_nlanes];
vx_store(arr_minval, minval);
vx_store(arr_maxval, maxval);
for (int j = 0; j < nlanes; j++)
{
xmin = std::min(xmin, arr_minval[2*j]);
ymin = std::min(ymin, arr_minval[2*j+1]);
xmax = std::max(xmax, arr_maxval[2*j]);
ymax = std::max(ymax, arr_maxval[2*j+1]);
}
#endif
for( ; i < npoints; i++ )
{
int pt_x = pts[2*i];
int pt_y = pts[2*i+1];
xmin = std::min(xmin, pt_x);
xmax = std::max(xmax, pt_x);
ymin = std::min(ymin, pt_y);
ymax = std::max(ymax, pt_y);
}
}
else
{
const float* pts = points.ptr<float>();
int64_t firstval = 0;
std::memcpy(&firstval, pts, sizeof(pts[0]) * 2);
xmin = xmax = cvFloor(pts[0]);
ymin = ymax = cvFloor(pts[1]);
#if CV_SIMD || CV_SIMD_SCALABLE
v_float32 minval, maxval;
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
const int nlanes = VTraits<v_float32>::vlanes()/2;
for (; i < npoints; i += nlanes)
{
if (i > npoints - nlanes)
{
if (i == 0)
break;
i = npoints - nlanes;
}
v_float32 ptXY2 = vx_load(pts + 2 * i);
minval = v_min(ptXY2, minval);
maxval = v_max(ptXY2, maxval);
}
constexpr int max_nlanes = VTraits<v_int32>::max_nlanes;
float arr_minval[max_nlanes], arr_maxval[max_nlanes];
vx_store(arr_minval, minval);
vx_store(arr_maxval, maxval);
for (int j = 0; j < nlanes; j++)
{
int _xmin = cvFloor(arr_minval[2*j]), _ymin = cvFloor(arr_minval[2*j+1]);
int _xmax = cvFloor(arr_maxval[2*j]), _ymax = cvFloor(arr_maxval[2*j+1]);
xmin = std::min(xmin, _xmin);
ymin = std::min(ymin, _ymin);
xmax = std::max(xmax, _xmax);
ymax = std::max(ymax, _ymax);
}
#endif
for( ; i < npoints; i++ )
{
// 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
int pt_x = cvFloor(pts[2*i]);
int pt_y = cvFloor(pts[2*i+1]);
xmin = std::min(xmin, pt_x);
xmax = std::max(xmax, pt_x);
ymin = std::min(ymin, pt_y);
ymax = std::max(ymax, pt_y);
}
}
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);
}
// area of a whole sequence
double cv::contourArea( InputArray _contour, bool oriented )
{
CV_INSTRUMENT_REGION();
Mat contour = _contour.getMat();
int npoints = contour.checkVector(2);
int depth = contour.depth();
CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_32S));
if( npoints == 0 )
return 0.;
double a00 = 0;
bool is_float = depth == CV_32F;
const Point* ptsi = contour.ptr<Point>();
const Point2f* ptsf = contour.ptr<Point2f>();
Point2f prev = is_float ? ptsf[npoints-1] : Point2f((float)ptsi[npoints-1].x, (float)ptsi[npoints-1].y);
for( int i = 0; i < npoints; i++ )
{
Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
a00 += (double)prev.x * p.y - (double)prev.y * p.x;
prev = p;
}
a00 *= 0.5;
if( !oriented )
a00 = fabs(a00);
return a00;
}
void cv::contourTreeToResults(CTree& tree,
int res_type,
OutputArrayOfArrays& _contours,
+2 -2
View File
@@ -60,9 +60,9 @@ protected:
points.push_back(Point(49, 51));
Moments m = moments(points, false);
double area = contourArea(points);
// double area = contourArea(points);
CV_Assert( m.m00 == 0 && m.m01 == 0 && m.m10 == 0 && area == 0 );
CV_Assert( m.m00 == 0 && m.m01 == 0 && m.m10 == 0 /*&& area == 0*/ );
}
catch(...)
{
@@ -10,6 +10,7 @@ import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;
import org.opencv.geometry.Geometry;
public class ColorBlobDetector {
// Lower and Upper bounds for range checking in HSV color space
@@ -85,7 +86,7 @@ public class ColorBlobDetector {
Iterator<MatOfPoint> each = contours.iterator();
while (each.hasNext()) {
MatOfPoint wrapper = each.next();
double area = Imgproc.contourArea(wrapper);
double area = Geometry.contourArea(wrapper);
if (area > maxArea)
maxArea = area;
}
@@ -95,7 +96,7 @@ public class ColorBlobDetector {
each = contours.iterator();
while (each.hasNext()) {
MatOfPoint contour = each.next();
if (Imgproc.contourArea(contour) > mMinContourArea*maxArea) {
if (Geometry.contourArea(contour) > mMinContourArea*maxArea) {
Core.multiply(contour, new Scalar(4,4), contour);
mContours.add(contour);
}
+1
View File
@@ -1,4 +1,5 @@
#include "opencv2/imgproc.hpp"
#include "opencv2/geometry.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/video/background_segm.hpp"
@@ -7,6 +7,7 @@
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/geometry.hpp"
#include <iostream>
#include <iomanip>
@@ -6,6 +6,7 @@
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/geometry.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>