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:
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
// ============================================================
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(...)
|
||||
{
|
||||
|
||||
+3
-2
@@ -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,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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user