diff --git a/modules/imgproc/include/opencv2/imgproc/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc/imgproc.hpp index 8920ed2a12..3c682452ba 100644 --- a/modules/imgproc/include/opencv2/imgproc/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc/imgproc.hpp @@ -1091,13 +1091,13 @@ enum { TM_SQDIFF=0, TM_SQDIFF_NORMED=1, TM_CCORR=2, TM_CCORR_NORMED=3, TM_CCOEFF CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ, OutputArray result, int method ); -enum { CC_STAT_LEFT=0, CC_STAT_TOP=1, CC_STAT_WIDTH=2, CC_STAT_HEIGHT=3, CC_STAT_CX=4, CC_STAT_CY=5, CC_STAT_AREA=6, CC_STAT_INTEGRAL_X=7, CC_STAT_INTEGRAL_Y=8, CC_STAT_MAX = 9}; +enum { CC_STAT_LEFT=0, CC_STAT_TOP=1, CC_STAT_WIDTH=2, CC_STAT_HEIGHT=3, CC_STAT_AREA=4, CC_STAT_MAX = 5}; //! computes the connected components labeled image of boolean image I with 4 or 8 way connectivity - returns N, the total //number of labels [0, N-1] where 0 represents the background label. L's value type determines the label type, an important //consideration based on the total number of labels or alternatively the total number of pixels. -CV_EXPORTS_W int connectedComponents(InputArray image, OutputArray labels, int connectivity = 8); -CV_EXPORTS_W int connectedComponentsWithStats(InputArray image, OutputArray labels, OutputArray stats, int connectivity = 8); +CV_EXPORTS_W int connectedComponents(InputArray image, OutputArray labels, int connectivity = 8, int ltype=CV_32S); +CV_EXPORTS_W int connectedComponentsWithStats(InputArray image, OutputArray labels, OutputArray stats, OutputArray centroids, int connectivity = 8, int ltype=CV_32S); //! mode of the contour retrieval algorithm diff --git a/modules/imgproc/src/connectedcomponents.cpp b/modules/imgproc/src/connectedcomponents.cpp index b52a6c7293..6418337c53 100644 --- a/modules/imgproc/src/connectedcomponents.cpp +++ b/modules/imgproc/src/connectedcomponents.cpp @@ -69,29 +69,42 @@ namespace cv{ } void finish(){} }; + struct Point2ui64{ + uint64_t x, y; + Point2ui64(uint64_t _x, uint64_t _y):x(_x), y(_y){} + }; template struct CCStatsOp{ + OutputArray _mstatsv; cv::Mat statsv; - CCStatsOp(OutputArray _statsv): statsv(_statsv.getMat()){ + OutputArray _mcentroidsv; + cv::Mat centroidsv; + std::vector integrals; + + CCStatsOp(OutputArray _statsv, OutputArray _centroidsv): _mstatsv(_statsv), _mcentroidsv(_centroidsv){ } inline void init(const LabelT nlabels){ - statsv = cv::Mat(nlabels, CC_STAT_MAX, cv::DataType::type); + _mstatsv.create(cv::Size(nlabels, CC_STAT_MAX), cv::DataType::type); + statsv = _mstatsv.getMat(); + _mcentroidsv.create(cv::Size(nlabels, 2), cv::DataType::type); + centroidsv = _mcentroidsv.getMat(); + for(int l = 0; l < (int) nlabels; ++l){ - double *row = &statsv.at(l, 0); + unsigned int *row = (unsigned int *) &statsv.at(l, 0); row[CC_STAT_LEFT] = std::numeric_limits::max(); row[CC_STAT_TOP] = std::numeric_limits::max(); row[CC_STAT_WIDTH] = std::numeric_limits::min(); row[CC_STAT_HEIGHT] = std::numeric_limits::min(); - row[CC_STAT_CX] = 0; - row[CC_STAT_CY] = 0; + //row[CC_STAT_CX] = 0; + //row[CC_STAT_CY] = 0; row[CC_STAT_AREA] = 0; - row[CC_STAT_INTEGRAL_X] = 0; - row[CC_STAT_INTEGRAL_Y] = 0; } + integrals.resize(nlabels, Point2ui64(0, 0)); } void operator()(int r, int c, LabelT l){ - double *row = &statsv.at(l, 0); + int *row = &statsv.at(l, 0); + unsigned int *urow = (unsigned int *) row; if(c > row[CC_STAT_WIDTH]){ row[CC_STAT_WIDTH] = c; }else{ @@ -106,19 +119,23 @@ namespace cv{ row[CC_STAT_TOP] = r; } } - row[CC_STAT_INTEGRAL_X] += c; - row[CC_STAT_INTEGRAL_Y] += r; - row[CC_STAT_AREA]++; + urow[CC_STAT_AREA]++; + Point2ui64 &integral = integrals[l]; + integral.x += c; + integral.y += r; } void finish(){ for(int l = 0; l < statsv.rows; ++l){ - double *row = &statsv.at(l, 0); + unsigned int *row = (unsigned int *) &statsv.at(l, 0); row[CC_STAT_LEFT] = std::min(row[CC_STAT_LEFT], row[CC_STAT_WIDTH]); row[CC_STAT_WIDTH] = row[CC_STAT_WIDTH] - row[CC_STAT_LEFT] + 1; row[CC_STAT_TOP] = std::min(row[CC_STAT_TOP], row[CC_STAT_HEIGHT]); row[CC_STAT_HEIGHT] = row[CC_STAT_HEIGHT] - row[CC_STAT_TOP] + 1; - row[CC_STAT_CX] = row[CC_STAT_INTEGRAL_X] / double(row[CC_STAT_AREA]); - row[CC_STAT_CY] = row[CC_STAT_INTEGRAL_Y] / double(row[CC_STAT_AREA]); + + Point2ui64 &integral = integrals[l]; + double *centroid = ¢roidsv.at(l, 0); + centroid[0] = double(integral.x) / row[CC_STAT_AREA]; + centroid[1] = double(integral.y) / row[CC_STAT_AREA]; } } }; @@ -196,9 +213,7 @@ namespace cv{ const int G8[4][2] = {{1, -1}, {1, 0}, {1, 1}, {0, -1}};//a, b, c, d neighborhoods template, int connectivity = 8> struct LabelingImpl{ - LabelT operator()(InputArray _I, OutputArray _L, StatsOp &sop){ - cv::Mat I = _I.getMat(); - cv::Mat L = _L.getMat(); + LabelT operator()(const cv::Mat &I, cv::Mat &L, StatsOp &sop){ CV_Assert(L.rows == I.rows); CV_Assert(L.cols == I.cols); const int rows = L.rows; @@ -347,7 +362,8 @@ namespace cv{ //L's type must have an appropriate depth for the number of pixels in I template -int connectedComponents_sub1(InputArray I, OutputArray L, int connectivity, StatsOp &sop){ +static +int connectedComponents_sub1(const cv::Mat &I, cv::Mat &L, int connectivity, StatsOp &sop){ CV_Assert(L.channels() == 1 && I.channels() == 1); CV_Assert(connectivity == 8 || connectivity == 4); @@ -394,13 +410,15 @@ int connectedComponents_sub1(InputArray I, OutputArray L, int connectivity, Stat return -1; } -int connectedComponents(InputArray I, OutputArray L, int connectivity){ - int lDepth = L.depth(); - if(lDepth == CV_8U){ +int connectedComponents(InputArray _I, OutputArray _L, int connectivity, int ltype){ + const cv::Mat I = _I.getMat(); + _L.create(I.size(), CV_MAT_TYPE(ltype)); + cv::Mat L = _L.getMat(); + if(ltype == CV_8U){ connectedcomponents::NoOp sop; return connectedComponents_sub1(I, L, connectivity, sop); - }else if(lDepth == CV_16U){ + }else if(ltype == CV_16U){ connectedcomponents::NoOp sop; return connectedComponents_sub1(I, L, connectivity, sop); - }else if(lDepth == CV_32S){ + }else if(ltype == CV_32S){ connectedcomponents::NoOp sop; return connectedComponents_sub1(I, L, connectivity, sop); }else{ CV_Assert(false); @@ -408,14 +426,16 @@ int connectedComponents(InputArray I, OutputArray L, int connectivity){ } } -int connectedComponentsWithStats(InputArray I, OutputArray L, OutputArray statsv, int connectivity){ - int lDepth = L.depth(); - if(lDepth == CV_8U){ - connectedcomponents::CCStatsOp sop(statsv); return connectedComponents_sub1(I, L, connectivity, sop); - }else if(lDepth == CV_16U){ - connectedcomponents::CCStatsOp sop(statsv); return connectedComponents_sub1(I, L, connectivity, sop); - }else if(lDepth == CV_32S){ - connectedcomponents::CCStatsOp sop(statsv); return connectedComponents_sub1(I, L, connectivity, sop); +int connectedComponentsWithStats(InputArray _I, OutputArray _L, OutputArray statsv, OutputArray centroids, int connectivity, int ltype){ + const cv::Mat I = _I.getMat(); + _L.create(I.size(), CV_MAT_TYPE(ltype)); + cv::Mat L = _L.getMat(); + if(ltype == CV_8U){ + connectedcomponents::CCStatsOp sop(statsv, centroids); return connectedComponents_sub1(I, L, connectivity, sop); + }else if(ltype == CV_16U){ + connectedcomponents::CCStatsOp sop(statsv, centroids); return connectedComponents_sub1(I, L, connectivity, sop); + }else if(ltype == CV_32S){ + connectedcomponents::CCStatsOp sop(statsv, centroids); return connectedComponents_sub1(I, L, connectivity, sop); }else{ CV_Assert(false); return 0;