From 00bdca76846cffea00febfb533f77ccb96d18592 Mon Sep 17 00:00:00 2001 From: Jason Newton Date: Tue, 27 Nov 2012 02:25:52 -0800 Subject: [PATCH] A few changes to comply with upstream requirements for merge. -Change input/output order from (out Labeled, in Image) -> (in Image, Out Labeled) and convert to Input/OutputArrays in the process. -Adopt OutputArray for statistics export so that the algorithm is "wrapper friendly" and not requiring a new struct in language bindings at the expense of using doubles for everything and slowing statistics computation down.. --- .../imgproc/include/opencv2/imgproc/imgproc.hpp | 17 +--- modules/imgproc/src/connectedcomponents.cpp | 105 +++++++++++---------- modules/python/src2/cv2.cpp | 1 - samples/cpp/connected_components.cpp | 2 +- 4 files changed, 59 insertions(+), 66 deletions(-) diff --git a/modules/imgproc/include/opencv2/imgproc/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc/imgproc.hpp index 5e3da26..8920ed2 100644 --- a/modules/imgproc/include/opencv2/imgproc/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc/imgproc.hpp @@ -1091,24 +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 ); -struct CV_EXPORTS ConnectedComponentStats -{ - int lower_x;//!< lower left corner column - int lower_y;//!< lower left corner row - int upper_x;//!< upper right corner column - int upper_y;//!< upper right corner row - double centroid_x;//!< centroid column - double centroid_y;//!< centroid row - uint64 integral_x;//!< sum of all columns where the image was non-zero - uint64 integral_y;//!< sum of all rows where the image was non-zero - unsigned int area;//!< count of all non-zero pixels -}; +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}; //! 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(CV_OUT Mat &L, const Mat &I, int connectivity = 8); -CV_EXPORTS_W int connectedComponentsWithStats(CV_OUT Mat &L, const Mat &I, CV_OUT std::vector &statsv, int connectivity = 8); +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); //! mode of the contour retrieval algorithm diff --git a/modules/imgproc/src/connectedcomponents.cpp b/modules/imgproc/src/connectedcomponents.cpp index db118f5..b52a6c7 100644 --- a/modules/imgproc/src/connectedcomponents.cpp +++ b/modules/imgproc/src/connectedcomponents.cpp @@ -71,51 +71,54 @@ namespace cv{ }; template struct CCStatsOp{ - std::vector &statsv; - CCStatsOp(std::vector &_statsv): statsv(_statsv){ + cv::Mat statsv; + CCStatsOp(OutputArray _statsv): statsv(_statsv.getMat()){ } inline void init(const LabelT nlabels){ - statsv.clear(); - cv::ConnectedComponentStats stats = cv::ConnectedComponentStats(); - stats.lower_x = std::numeric_limits::max(); - stats.lower_y = std::numeric_limits::max(); - stats.upper_x = std::numeric_limits::min(); - stats.upper_y = std::numeric_limits::min(); - stats.centroid_x = 0; - stats.centroid_y = 0; - stats.integral_x = 0; - stats.integral_y = 0; - stats.area = 0; - statsv.resize(nlabels, stats); + statsv = cv::Mat(nlabels, CC_STAT_MAX, cv::DataType::type); + for(int l = 0; l < (int) nlabels; ++l){ + double *row = &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_AREA] = 0; + row[CC_STAT_INTEGRAL_X] = 0; + row[CC_STAT_INTEGRAL_Y] = 0; + } } void operator()(int r, int c, LabelT l){ - ConnectedComponentStats &stats = statsv[l]; - if(c > stats.upper_x){ - stats.upper_x = c; + double *row = &statsv.at(l, 0); + if(c > row[CC_STAT_WIDTH]){ + row[CC_STAT_WIDTH] = c; }else{ - if(c < stats.lower_x){ - stats.lower_x = c; + if(c < row[CC_STAT_LEFT]){ + row[CC_STAT_LEFT] = c; } } - if(r > stats.upper_y){ - stats.upper_y = r; + if(r > row[CC_STAT_HEIGHT]){ + row[CC_STAT_HEIGHT] = r; }else{ - if(r < stats.lower_y){ - stats.lower_y = r; + if(r < row[CC_STAT_TOP]){ + row[CC_STAT_TOP] = r; } } - stats.integral_x += c; - stats.integral_y += r; - stats.area++; + row[CC_STAT_INTEGRAL_X] += c; + row[CC_STAT_INTEGRAL_Y] += r; + row[CC_STAT_AREA]++; } void finish(){ - for(size_t l = 0; l < statsv.size(); ++l){ - ConnectedComponentStats &stats = statsv[l]; - stats.lower_x = std::min(stats.lower_x, stats.upper_x); - stats.lower_y = std::min(stats.lower_y, stats.upper_y); - stats.centroid_x = stats.integral_x / double(stats.area); - stats.centroid_y = stats.integral_y / double(stats.area); + for(int l = 0; l < statsv.rows; ++l){ + double *row = &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]); } } }; @@ -193,7 +196,11 @@ 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()(Mat &L, const Mat &I, StatsOp &sop){ + LabelT operator()(InputArray _I, OutputArray _L, StatsOp &sop){ + cv::Mat I = _I.getMat(); + cv::Mat L = _L.getMat(); + CV_Assert(L.rows == I.rows); + CV_Assert(L.cols == I.cols); const int rows = L.rows; const int cols = L.cols; size_t Plength = (size_t(rows + 3 - 1)/3) * (size_t(cols + 3 - 1)/3); @@ -340,9 +347,7 @@ namespace cv{ //L's type must have an appropriate depth for the number of pixels in I template -int connectedComponents_sub1(Mat &L, const Mat &I, int connectivity, StatsOp &sop){ - CV_Assert(L.rows == I.rows); - CV_Assert(L.cols == I.cols); +int connectedComponents_sub1(InputArray I, OutputArray L, int connectivity, StatsOp &sop){ CV_Assert(L.channels() == 1 && I.channels() == 1); CV_Assert(connectivity == 8 || connectivity == 4); @@ -354,9 +359,9 @@ int connectedComponents_sub1(Mat &L, const Mat &I, int connectivity, StatsOp &so if(lDepth == CV_8U){ if(iDepth == CV_8U || iDepth == CV_8S){ if(connectivity == 4){ - return (int) LabelingImpl()(L, I, sop); + return (int) LabelingImpl()(I, L, sop); }else{ - return (int) LabelingImpl()(L, I, sop); + return (int) LabelingImpl()(I, L, sop); } }else{ CV_Assert(false); @@ -364,9 +369,9 @@ int connectedComponents_sub1(Mat &L, const Mat &I, int connectivity, StatsOp &so }else if(lDepth == CV_16U){ if(iDepth == CV_8U || iDepth == CV_8S){ if(connectivity == 4){ - return (int) LabelingImpl()(L, I, sop); + return (int) LabelingImpl()(I, L, sop); }else{ - return (int) LabelingImpl()(L, I, sop); + return (int) LabelingImpl()(I, L, sop); } }else{ CV_Assert(false); @@ -376,9 +381,9 @@ int connectedComponents_sub1(Mat &L, const Mat &I, int connectivity, StatsOp &so //OpenCV: how should we proceed? .at typechecks in debug mode if(iDepth == CV_8U || iDepth == CV_8S){ if(connectivity == 4){ - return (int) LabelingImpl()(L, I, sop); + return (int) LabelingImpl()(I, L, sop); }else{ - return (int) LabelingImpl()(L, I, sop); + return (int) LabelingImpl()(I, L, sop); } }else{ CV_Assert(false); @@ -389,28 +394,28 @@ int connectedComponents_sub1(Mat &L, const Mat &I, int connectivity, StatsOp &so return -1; } -int connectedComponents(Mat &L, const Mat &I, int connectivity){ +int connectedComponents(InputArray I, OutputArray L, int connectivity){ int lDepth = L.depth(); if(lDepth == CV_8U){ - connectedcomponents::NoOp sop; return connectedComponents_sub1(L, I, connectivity, sop); + connectedcomponents::NoOp sop; return connectedComponents_sub1(I, L, connectivity, sop); }else if(lDepth == CV_16U){ - connectedcomponents::NoOp sop; return connectedComponents_sub1(L, I, connectivity, sop); + connectedcomponents::NoOp sop; return connectedComponents_sub1(I, L, connectivity, sop); }else if(lDepth == CV_32S){ - connectedcomponents::NoOp sop; return connectedComponents_sub1(L, I, connectivity, sop); + connectedcomponents::NoOp sop; return connectedComponents_sub1(I, L, connectivity, sop); }else{ CV_Assert(false); return 0; } } -int connectedComponentsWithStats(Mat &L, const Mat &I, std::vector &statsv, 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(L, I, connectivity, sop); + connectedcomponents::CCStatsOp sop(statsv); return connectedComponents_sub1(I, L, connectivity, sop); }else if(lDepth == CV_16U){ - connectedcomponents::CCStatsOp sop(statsv); return connectedComponents_sub1(L, I, connectivity, sop); + connectedcomponents::CCStatsOp sop(statsv); return connectedComponents_sub1(I, L, connectivity, sop); }else if(lDepth == CV_32S){ - connectedcomponents::CCStatsOp sop(statsv); return connectedComponents_sub1(L, I, connectivity, sop); + connectedcomponents::CCStatsOp sop(statsv); return connectedComponents_sub1(I, L, connectivity, sop); }else{ CV_Assert(false); return 0; diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index 5dbbbb4..bc52f30 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -123,7 +123,6 @@ typedef Ptr Ptr_FeatureDetector; typedef Ptr Ptr_DescriptorExtractor; typedef Ptr Ptr_Feature2D; typedef Ptr Ptr_DescriptorMatcher; -typedef vector vector_ConnectedComponentStats; typedef SimpleBlobDetector::Params SimpleBlobDetector_Params; diff --git a/samples/cpp/connected_components.cpp b/samples/cpp/connected_components.cpp index 7b362df..781ffec 100644 --- a/samples/cpp/connected_components.cpp +++ b/samples/cpp/connected_components.cpp @@ -12,7 +12,7 @@ static void on_trackbar(int, void*) { Mat bw = threshval < 128 ? (img < threshval) : (img > threshval); Mat labelImage(img.size(), CV_32S); - uint64_t nLabels = connectedComponents(labelImage, bw, 8); + int nLabels = connectedComponents(bw, labelImage, 8); Vec3b colors[nLabels]; colors[0] = Vec3b(0, 0, 0);//background for(int label = 1; label < nLabels; ++label){ -- 2.7.4