diff --git a/modules/core/include/opencv2/core/cvdef.h b/modules/core/include/opencv2/core/cvdef.h index 30f2ce5649..748ecb9ece 100644 --- a/modules/core/include/opencv2/core/cvdef.h +++ b/modules/core/include/opencv2/core/cvdef.h @@ -201,6 +201,14 @@ namespace cv { # define CV_ICC __INTEL_COMPILER #endif +#if defined _WIN32 +# define CV_CDECL __cdecl +# define CV_STDCALL __stdcall +#else +# define CV_CDECL +# define CV_STDCALL +#endif + #ifndef CV_INLINE # if defined __cplusplus # define CV_INLINE static inline @@ -482,6 +490,7 @@ Cv64suf; * Matrix type (Mat) * \****************************************************************************************/ +#define CV_MAX_DIM 32 #define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT) #define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1) #define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1) @@ -508,6 +517,13 @@ Cv64suf; # define MAX(a,b) ((a) < (b) ? (b) : (a)) #endif +/** min & max without jumps */ +#define CV_IMIN(a, b) ((a) ^ (((a)^(b)) & (((a) < (b)) - 1))) +#define CV_IMAX(a, b) ((a) ^ (((a)^(b)) & (((a) > (b)) - 1))) +#define CV_SWAP(a,b,t) ((t) = (a), (a) = (b), (b) = (t)) +#define CV_CMP(a,b) (((a) > (b)) - ((a) < (b))) +#define CV_SIGN(a) CV_CMP((a),0) + ///////////////////////////////////////// Enum operators /////////////////////////////////////// /** diff --git a/modules/core/include/opencv2/core/types_c.h b/modules/core/include/opencv2/core/types_c.h index 32f3c8c999..02d4a4f680 100644 --- a/modules/core/include/opencv2/core/types_c.h +++ b/modules/core/include/opencv2/core/types_c.h @@ -90,13 +90,7 @@ #include #endif // SKIP_INCLUDES -#if defined _WIN32 -# define CV_CDECL __cdecl -# define CV_STDCALL __stdcall -#else -# define CV_CDECL -# define CV_STDCALL -#endif + #ifndef CV_DEFAULT # ifdef __cplusplus @@ -203,21 +197,13 @@ enum { * Common macros and inline functions * \****************************************************************************************/ -#define CV_SWAP(a,b,t) ((t) = (a), (a) = (b), (b) = (t)) - -/** min & max without jumps */ -#define CV_IMIN(a, b) ((a) ^ (((a)^(b)) & (((a) < (b)) - 1))) - -#define CV_IMAX(a, b) ((a) ^ (((a)^(b)) & (((a) > (b)) - 1))) - /** absolute value without jumps */ #ifndef __cplusplus # define CV_IABS(a) (((a) ^ ((a) < 0 ? -1 : 0)) - ((a) < 0 ? -1 : 0)) #else # define CV_IABS(a) abs(a) #endif -#define CV_CMP(a,b) (((a) > (b)) - ((a) < (b))) -#define CV_SIGN(a) CV_CMP((a),0) + #define cvInvSqrt(value) ((float)(1./sqrt(value))) #define cvSqrt(value) ((float)sqrt(value)) @@ -675,8 +661,6 @@ CV_INLINE int cvIplDepth( int type ) #define CV_MATND_MAGIC_VAL 0x42430000 #define CV_TYPE_NAME_MATND "opencv-nd-matrix" -#define CV_MAX_DIM 32 - #ifdef __cplusplus typedef struct CvMatND CvMatND; CV_EXPORTS CvMatND cvMatND(const cv::Mat& m); diff --git a/modules/imgproc/src/cornersubpix.cpp b/modules/imgproc/src/cornersubpix.cpp index 24fd59910b..af5bd999dc 100644 --- a/modules/imgproc/src/cornersubpix.cpp +++ b/modules/imgproc/src/cornersubpix.cpp @@ -49,8 +49,8 @@ void cv::cornerSubPix( InputArray _image, InputOutputArray _corners, const int MAX_ITERS = 100; int win_w = win.width * 2 + 1, win_h = win.height * 2 + 1; int i, j, k; - int max_iters = (criteria.type & CV_TERMCRIT_ITER) ? MIN(MAX(criteria.maxCount, 1), MAX_ITERS) : MAX_ITERS; - double eps = (criteria.type & CV_TERMCRIT_EPS) ? MAX(criteria.epsilon, 0.) : 0; + int max_iters = (criteria.type & TermCriteria::MAX_ITER) ? MIN(MAX(criteria.maxCount, 1), MAX_ITERS) : MAX_ITERS; + double eps = (criteria.type & TermCriteria::EPS) ? MAX(criteria.epsilon, 0.) : 0; eps *= eps; // use square of error in comparison operations cv::Mat src = _image.getMat(), cornersmat = _corners.getMat(); diff --git a/modules/imgproc/src/drawing.cpp b/modules/imgproc/src/drawing.cpp index 355525eb6c..4d0f26f7a0 100644 --- a/modules/imgproc/src/drawing.cpp +++ b/modules/imgproc/src/drawing.cpp @@ -39,6 +39,7 @@ // //M*/ #include "precomp.hpp" +using namespace cv; namespace cv { @@ -2468,35 +2469,6 @@ void cv::polylines(InputOutputArray img, InputArrayOfArrays pts, polylines(img, (const Point**)ptsptr, npts, (int)ncontours, isClosed, color, thickness, lineType, shift); } -namespace -{ -using namespace cv; - -static void addChildContour(InputArrayOfArrays contours, - size_t ncontours, - const Vec4i* hierarchy, - int i, std::vector& seq, - std::vector& block) -{ - for( ; i >= 0; i = hierarchy[i][0] ) - { - Mat ci = contours.getMat(i); - cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point), - !ci.empty() ? (void*)ci.ptr() : 0, (int)ci.total(), - &seq[i], &block[i] ); - - int h_next = hierarchy[i][0], h_prev = hierarchy[i][1], - v_next = hierarchy[i][2], v_prev = hierarchy[i][3]; - seq[i].h_next = (0 <= h_next && h_next < (int)ncontours) ? &seq[h_next] : 0; - seq[i].h_prev = (0 <= h_prev && h_prev < (int)ncontours) ? &seq[h_prev] : 0; - seq[i].v_next = (0 <= v_next && v_next < (int)ncontours) ? &seq[v_next] : 0; - seq[i].v_prev = (0 <= v_prev && v_prev < (int)ncontours) ? &seq[v_prev] : 0; - - if( v_next >= 0 ) - addChildContour(contours, ncontours, hierarchy, v_next, seq, block); - } -} -} void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours, int contourIdx, const Scalar& color, int thickness, @@ -2504,83 +2476,99 @@ void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours, int maxLevel, Point offset ) { CV_INSTRUMENT_REGION(); - - Mat image = _image.getMat(), hierarchy = _hierarchy.getMat(); - CvMat _cimage = cvMat(image); - - size_t ncontours = _contours.total(); - size_t i = 0, first = 0, last = ncontours; - std::vector seq; - std::vector block; - - if( !last ) + CV_Assert( thickness <= MAX_THICKNESS ); + const size_t ncontours = _contours.total(); + if (!ncontours) return; + CV_Assert(ncontours <= (size_t)std::numeric_limits::max()); + if (lineType == cv::LINE_AA && _image.depth() != CV_8U) + lineType = 8; + Mat image = _image.getMat(), hierarchy = _hierarchy.getMat(); - seq.resize(last); - block.resize(last); - - for( i = first; i < last; i++ ) - seq[i].first = 0; - - if( contourIdx >= 0 ) + if (thickness >= 0) // contour lines { - CV_Assert( 0 <= contourIdx && contourIdx < (int)last ); - first = contourIdx; - last = contourIdx + 1; - } - - for( i = first; i < last; i++ ) - { - Mat ci = _contours.getMat((int)i); - if( ci.empty() ) - continue; - int npoints = ci.checkVector(2, CV_32S); - CV_Assert( npoints > 0 ); - cvMakeSeqHeaderForArray( CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point), - ci.ptr(), npoints, &seq[i], &block[i] ); - } - - if( hierarchy.empty() || maxLevel == 0 ) - for( i = first; i < last; i++ ) + double color_buf[4] {}; + scalarToRawData(color, color_buf, _image.type(), 0 ); + int i = 0, end = (int)ncontours; + if (contourIdx >= 0) { - seq[i].h_next = i < last-1 ? &seq[i+1] : 0; - seq[i].h_prev = i > first ? &seq[i-1] : 0; + i = contourIdx; + end = i + 1; } - else - { - size_t count = last - first; - CV_Assert(hierarchy.total() == ncontours && hierarchy.type() == CV_32SC4 ); - const Vec4i* h = hierarchy.ptr(); - - if( count == ncontours ) + for (; i < end; ++i) { - for( i = first; i < last; i++ ) + Mat cnt = _contours.getMat(i); + if (cnt.empty()) + continue; + const int npoints = cnt.checkVector(2, CV_32S); + CV_Assert(npoints > 0); + for (int j = 0; j < npoints; ++j) { - int h_next = h[i][0], h_prev = h[i][1], - v_next = h[i][2], v_prev = h[i][3]; - seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0; - seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0; - seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0; - seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0; + const bool isLastIter = j == npoints - 1; + const Point pt1 = cnt.at(j); + const Point pt2 = cnt.at(isLastIter ? 0 : j + 1); + cv::ThickLine(image, pt1 + offset, pt2 + offset, color_buf, thickness, lineType, 2, 0); } } + } + else // filled polygons + { + int i = 0, end = (int)ncontours; + if (contourIdx >= 0) + { + i = contourIdx; + end = i + 1; + } + std::vector indexesToFill; + if (hierarchy.empty() || maxLevel == 0) + { + for (; i != end; ++i) + indexesToFill.push_back(i); + } else { - int child = h[first][2]; - if( child >= 0 ) + std::stack indexes; + for (; i != end; ++i) { - addChildContour(_contours, ncontours, h, child, seq, block); - seq[first].v_next = &seq[child]; + // either all from the top level or a single contour + if (hierarchy.at(i)[3] < 0 || contourIdx >= 0) + indexes.push(i); + } + while (!indexes.empty()) + { + // get current element + const int cur = indexes.top(); + indexes.pop(); + + // check current element depth + int curLevel = -1; + int par = cur; + while (par >= 0) + { + par = hierarchy.at(par)[3]; // parent + ++curLevel; + } + if (curLevel <= maxLevel) + { + indexesToFill.push_back(cur); + } + + int next = hierarchy.at(cur)[2]; // first child + while (next > 0) + { + indexes.push(next); + next = hierarchy.at(next)[0]; // next sibling + } } } + std::vector contoursToFill; + for (const int & idx : indexesToFill) + contoursToFill.push_back(_contours.getMat(idx)); + fillPoly(image, contoursToFill, color, lineType, 0, offset); } - - cvDrawContours( &_cimage, &seq[first], cvScalar(color), cvScalar(color), contourIdx >= 0 ? - -maxLevel : maxLevel, thickness, lineType, cvPoint(offset) ); } - static const int CodeDeltas[8][2] = { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} }; diff --git a/modules/imgproc/src/grabcut.cpp b/modules/imgproc/src/grabcut.cpp index 695c0dd6c5..358747843e 100644 --- a/modules/imgproc/src/grabcut.cpp +++ b/modules/imgproc/src/grabcut.cpp @@ -389,14 +389,14 @@ static void initGMMs( const Mat& img, const Mat& mask, GMM& bgdGMM, GMM& fgdGMM int num_clusters = GMM::componentsCount; num_clusters = std::min(num_clusters, (int)bgdSamples.size()); kmeans( _bgdSamples, num_clusters, bgdLabels, - TermCriteria( CV_TERMCRIT_ITER, kMeansItCount, 0.0), 0, kMeansType ); + TermCriteria( TermCriteria::MAX_ITER, kMeansItCount, 0.0), 0, kMeansType ); } { Mat _fgdSamples( (int)fgdSamples.size(), 3, CV_32FC1, &fgdSamples[0][0] ); int num_clusters = GMM::componentsCount; num_clusters = std::min(num_clusters, (int)fgdSamples.size()); kmeans( _fgdSamples, num_clusters, fgdLabels, - TermCriteria( CV_TERMCRIT_ITER, kMeansItCount, 0.0), 0, kMeansType ); + TermCriteria( TermCriteria::MAX_ITER, kMeansItCount, 0.0), 0, kMeansType ); } bgdGMM.initLearning(); diff --git a/modules/imgproc/src/moments.cpp b/modules/imgproc/src/moments.cpp index e485104a26..786573bbcb 100644 --- a/modules/imgproc/src/moments.cpp +++ b/modules/imgproc/src/moments.cpp @@ -651,7 +651,7 @@ cv::Moments cv::moments( InputArray _src, bool binary ) if( binary ) { cv::Mat tmp(tileSize, CV_8U, nzbuf); - cv::compare( src, 0, tmp, CV_CMP_NE ); + cv::compare( src, 0, tmp, cv::CMP_NE ); src = tmp; } diff --git a/modules/imgproc/src/precomp.hpp b/modules/imgproc/src/precomp.hpp index df35da529c..33a921c78a 100644 --- a/modules/imgproc/src/precomp.hpp +++ b/modules/imgproc/src/precomp.hpp @@ -61,6 +61,7 @@ #include #include #include +#include #define GET_OPTIMIZED(func) (func) diff --git a/modules/imgproc/src/segmentation.cpp b/modules/imgproc/src/segmentation.cpp index 0476c4a244..c6dad4ba57 100644 --- a/modules/imgproc/src/segmentation.cpp +++ b/modules/imgproc/src/segmentation.cpp @@ -373,11 +373,11 @@ void cv::pyrMeanShiftFiltering( InputArray _src, OutputArray _dst, if( src0.size() != dst0.size() ) CV_Error( cv::Error::StsUnmatchedSizes, "The input and output images must have the same size" ); - if( !(termcrit.type & CV_TERMCRIT_ITER) ) + if( !(termcrit.type & TermCriteria::MAX_ITER) ) termcrit.maxCount = 5; termcrit.maxCount = MAX(termcrit.maxCount,1); termcrit.maxCount = MIN(termcrit.maxCount,100); - if( !(termcrit.type & CV_TERMCRIT_EPS) ) + if( !(termcrit.type & TermCriteria::EPS) ) termcrit.epsilon = 1.f; termcrit.epsilon = MAX(termcrit.epsilon, 0.f); diff --git a/modules/imgproc/test/test_contours.cpp b/modules/imgproc/test/test_contours.cpp index 8c6ddc7df7..fbd3cabff8 100644 --- a/modules/imgproc/test/test_contours.cpp +++ b/modules/imgproc/test/test_contours.cpp @@ -289,7 +289,7 @@ int CV_FindContourTest::validate_test_results( int /*test_case_idx*/ ) { int code = cvtest::TS::OK; - cvCmpS( img[0], 0, img[0], CV_CMP_GT ); + cvCmpS( img[0], 0, img[0], cv::CMP_GT ); if( count != count2 ) { diff --git a/modules/imgproc/test/test_convhull.cpp b/modules/imgproc/test/test_convhull.cpp index 2501a38075..de45bf2c72 100644 --- a/modules/imgproc/test/test_convhull.cpp +++ b/modules/imgproc/test/test_convhull.cpp @@ -1956,12 +1956,6 @@ int CV_ContourMomentsTest::validate_test_results( int test_case_idx ) if( code < 0 ) { -#if 0 - cvCmpS( img, 0, img, CV_CMP_GT ); - cvNamedWindow( "test", 1 ); - cvShowImage( "test", img ); - cvWaitKey(); -#endif ts->set_failed_test_info( code ); } diff --git a/modules/imgproc/test/test_drawing.cpp b/modules/imgproc/test/test_drawing.cpp index cdd2a01b4b..a6b125bcd1 100644 --- a/modules/imgproc/test/test_drawing.cpp +++ b/modules/imgproc/test/test_drawing.cpp @@ -928,4 +928,111 @@ TEST(Drawing, circle_memory_access) cv::circle(matrix, cv::Point(-1, -1), 0, kBlue, 2, 8, 16); } +inline static Mat mosaic2x2(Mat &img) +{ + const Size sz = img.size(); + Mat res(sz * 2, img.type(), Scalar::all(0)); + img.copyTo(res(Rect(Point(0, 0), sz))); + img.copyTo(res(Rect(Point(0, sz.height), sz))); + img.copyTo(res(Rect(Point(sz.width, 0), sz))); + img.copyTo(res(Rect(Point(sz.width, sz.height), sz))); + return res; +} + +TEST(Drawing, contours_filled) +{ + const Scalar white(255); + const Scalar black(0); + const Size sz(100, 100); + + Mat img(sz, CV_8UC1, black); + rectangle(img, Point(20, 20), Point(80, 80), white, -1); + rectangle(img, Point(30, 30), Point(70, 70), black, -1); + rectangle(img, Point(40, 40), Point(60, 60), white, -1); + img = mosaic2x2(img); + + Mat img1(sz, CV_8UC1, black); + rectangle(img1, Point(20, 20), Point(80, 80), white, -1); + img1 = mosaic2x2(img1); + + Mat img2(sz, CV_8UC1, black); + rectangle(img2, Point(20, 20), Point(80, 80), white, -1); + rectangle(img2, Point(30, 30), Point(70, 70), black, -1); + img2 = mosaic2x2(img2); + + Mat img3(sz, CV_8UC1, black); + rectangle(img3, Point(40, 40), Point(60, 60), white, -1); + img3 = mosaic2x2(img3); + + // inverted contours - corners and left edge adjusted + Mat imgi(sz, CV_8UC1, black); + rectangle(imgi, Point(29, 29), Point(71, 71), white, -1); + rectangle(imgi, Point(41, 41), Point(59, 59), black, -1); + imgi.at(Point(29, 29)) = 0; + imgi.at(Point(29, 71)) = 0; + imgi = mosaic2x2(imgi); + + vector> contours; + vector hierarchy; + findContours(img, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE); + ASSERT_EQ(12u, contours.size()); + + // NOTE: + // assuming contour tree has following structure (idx = 0, 1, ...): + // idx (top level) + // - idx + 1 + // - idx + 2 + // idx + 3 (top level) + // - idx + 4 + // - idx + 5 + // ... + const vector top_contours {0, 3, 6, 9}; + { + // all contours + Mat res(img.size(), CV_8UC1, Scalar::all(0)); + drawContours(res, contours, -1, white, -1, cv::LINE_8, hierarchy); + EXPECT_LT(cvtest::norm(img, res, NORM_INF), 1); + } + { + // all contours + Mat res(img.size(), CV_8UC1, Scalar::all(0)); + drawContours(res, contours, -1, white, -1, cv::LINE_8, hierarchy, 3); + EXPECT_LT(cvtest::norm(img, res, NORM_INF), 1); + } + { + // all contours + Mat res(img.size(), CV_8UC1, Scalar::all(0)); + drawContours(res, contours, -1, white, -1, cv::LINE_8, hierarchy, 0); + EXPECT_LT(cvtest::norm(img, res, NORM_INF), 1); + } + { + // all external contours one by one + Mat res(img.size(), CV_8UC1, Scalar::all(0)); + for (int idx : top_contours) + drawContours(res, contours, idx, white, -1, cv::LINE_8, hierarchy, 0); + EXPECT_LT(cvtest::norm(img1, res, NORM_INF), 1); + } + { + // all external contours + 1-level deep hole (one by one) + Mat res(img.size(), CV_8UC1, Scalar::all(0)); + for (int idx : top_contours) + drawContours(res, contours, idx, white, -1, cv::LINE_8, hierarchy, 1); + EXPECT_LT(cvtest::norm(img2, res, NORM_INF), 1); + } + { + // 2-level deep contours + Mat res(img.size(), CV_8UC1, Scalar::all(0)); + for (int idx : top_contours) + drawContours(res, contours, idx + 2, white, -1, cv::LINE_8, hierarchy); + EXPECT_LT(cvtest::norm(img3, res, NORM_INF), 1); + } + { + // holes become inverted here, LINE_8 -> LINE_4 + Mat res(img.size(), CV_8UC1, Scalar::all(0)); + for (int idx : top_contours) + drawContours(res, contours, idx + 1, white, -1, cv::LINE_4, hierarchy); + EXPECT_LT(cvtest::norm(imgi, res, NORM_INF), 1); + } +} + }} // namespace