Commit e70b3ef5 authored by Jason Newton's avatar Jason Newton

use a ltype parameter to determine result Label image type; export stats with…

use a ltype parameter to determine result Label image type; export stats with differening types over different outputarrays
parent 6a4d881a
...@@ -1091,13 +1091,13 @@ enum { TM_SQDIFF=0, TM_SQDIFF_NORMED=1, TM_CCORR=2, TM_CCORR_NORMED=3, TM_CCOEFF ...@@ -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, CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ,
OutputArray result, int method ); 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 //! 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 //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. //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 connectedComponents(InputArray image, OutputArray labels, int connectivity = 8, int ltype=CV_32S);
CV_EXPORTS_W int connectedComponentsWithStats(InputArray image, OutputArray labels, OutputArray stats, int connectivity = 8); 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 //! mode of the contour retrieval algorithm
......
...@@ -69,29 +69,42 @@ namespace cv{ ...@@ -69,29 +69,42 @@ namespace cv{
} }
void finish(){} void finish(){}
}; };
struct Point2ui64{
uint64_t x, y;
Point2ui64(uint64_t _x, uint64_t _y):x(_x), y(_y){}
};
template<typename LabelT> template<typename LabelT>
struct CCStatsOp{ struct CCStatsOp{
OutputArray _mstatsv;
cv::Mat statsv; cv::Mat statsv;
CCStatsOp(OutputArray _statsv): statsv(_statsv.getMat()){ OutputArray _mcentroidsv;
cv::Mat centroidsv;
std::vector<Point2ui64> integrals;
CCStatsOp(OutputArray _statsv, OutputArray _centroidsv): _mstatsv(_statsv), _mcentroidsv(_centroidsv){
} }
inline inline
void init(const LabelT nlabels){ void init(const LabelT nlabels){
statsv = cv::Mat(nlabels, CC_STAT_MAX, cv::DataType<double>::type); _mstatsv.create(cv::Size(nlabels, CC_STAT_MAX), cv::DataType<int>::type);
statsv = _mstatsv.getMat();
_mcentroidsv.create(cv::Size(nlabels, 2), cv::DataType<double>::type);
centroidsv = _mcentroidsv.getMat();
for(int l = 0; l < (int) nlabels; ++l){ for(int l = 0; l < (int) nlabels; ++l){
double *row = &statsv.at<double>(l, 0); unsigned int *row = (unsigned int *) &statsv.at<int>(l, 0);
row[CC_STAT_LEFT] = std::numeric_limits<LabelT>::max(); row[CC_STAT_LEFT] = std::numeric_limits<LabelT>::max();
row[CC_STAT_TOP] = std::numeric_limits<LabelT>::max(); row[CC_STAT_TOP] = std::numeric_limits<LabelT>::max();
row[CC_STAT_WIDTH] = std::numeric_limits<LabelT>::min(); row[CC_STAT_WIDTH] = std::numeric_limits<LabelT>::min();
row[CC_STAT_HEIGHT] = std::numeric_limits<LabelT>::min(); row[CC_STAT_HEIGHT] = std::numeric_limits<LabelT>::min();
row[CC_STAT_CX] = 0; //row[CC_STAT_CX] = 0;
row[CC_STAT_CY] = 0; //row[CC_STAT_CY] = 0;
row[CC_STAT_AREA] = 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){ void operator()(int r, int c, LabelT l){
double *row = &statsv.at<double>(l, 0); int *row = &statsv.at<int>(l, 0);
unsigned int *urow = (unsigned int *) row;
if(c > row[CC_STAT_WIDTH]){ if(c > row[CC_STAT_WIDTH]){
row[CC_STAT_WIDTH] = c; row[CC_STAT_WIDTH] = c;
}else{ }else{
...@@ -106,19 +119,23 @@ namespace cv{ ...@@ -106,19 +119,23 @@ namespace cv{
row[CC_STAT_TOP] = r; row[CC_STAT_TOP] = r;
} }
} }
row[CC_STAT_INTEGRAL_X] += c; urow[CC_STAT_AREA]++;
row[CC_STAT_INTEGRAL_Y] += r; Point2ui64 &integral = integrals[l];
row[CC_STAT_AREA]++; integral.x += c;
integral.y += r;
} }
void finish(){ void finish(){
for(int l = 0; l < statsv.rows; ++l){ for(int l = 0; l < statsv.rows; ++l){
double *row = &statsv.at<double>(l, 0); unsigned int *row = (unsigned int *) &statsv.at<int>(l, 0);
row[CC_STAT_LEFT] = std::min(row[CC_STAT_LEFT], row[CC_STAT_WIDTH]); 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_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_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_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 = &centroidsv.at<double>(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{ ...@@ -196,9 +213,7 @@ namespace cv{
const int G8[4][2] = {{1, -1}, {1, 0}, {1, 1}, {0, -1}};//a, b, c, d neighborhoods const int G8[4][2] = {{1, -1}, {1, 0}, {1, 1}, {0, -1}};//a, b, c, d neighborhoods
template<typename LabelT, typename PixelT, typename StatsOp = NoOp<LabelT>, int connectivity = 8> template<typename LabelT, typename PixelT, typename StatsOp = NoOp<LabelT>, int connectivity = 8>
struct LabelingImpl{ struct LabelingImpl{
LabelT operator()(InputArray _I, OutputArray _L, StatsOp &sop){ LabelT operator()(const cv::Mat &I, cv::Mat &L, StatsOp &sop){
cv::Mat I = _I.getMat();
cv::Mat L = _L.getMat();
CV_Assert(L.rows == I.rows); CV_Assert(L.rows == I.rows);
CV_Assert(L.cols == I.cols); CV_Assert(L.cols == I.cols);
const int rows = L.rows; const int rows = L.rows;
...@@ -347,7 +362,8 @@ namespace cv{ ...@@ -347,7 +362,8 @@ namespace cv{
//L's type must have an appropriate depth for the number of pixels in I //L's type must have an appropriate depth for the number of pixels in I
template<typename StatsOp> template<typename StatsOp>
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(L.channels() == 1 && I.channels() == 1);
CV_Assert(connectivity == 8 || connectivity == 4); CV_Assert(connectivity == 8 || connectivity == 4);
...@@ -394,13 +410,15 @@ int connectedComponents_sub1(InputArray I, OutputArray L, int connectivity, Stat ...@@ -394,13 +410,15 @@ int connectedComponents_sub1(InputArray I, OutputArray L, int connectivity, Stat
return -1; return -1;
} }
int connectedComponents(InputArray I, OutputArray L, int connectivity){ int connectedComponents(InputArray _I, OutputArray _L, int connectivity, int ltype){
int lDepth = L.depth(); const cv::Mat I = _I.getMat();
if(lDepth == CV_8U){ _L.create(I.size(), CV_MAT_TYPE(ltype));
cv::Mat L = _L.getMat();
if(ltype == CV_8U){
connectedcomponents::NoOp<uint8_t> sop; return connectedComponents_sub1(I, L, connectivity, sop); connectedcomponents::NoOp<uint8_t> sop; return connectedComponents_sub1(I, L, connectivity, sop);
}else if(lDepth == CV_16U){ }else if(ltype == CV_16U){
connectedcomponents::NoOp<uint16_t> sop; return connectedComponents_sub1(I, L, connectivity, sop); connectedcomponents::NoOp<uint16_t> sop; return connectedComponents_sub1(I, L, connectivity, sop);
}else if(lDepth == CV_32S){ }else if(ltype == CV_32S){
connectedcomponents::NoOp<uint32_t> sop; return connectedComponents_sub1(I, L, connectivity, sop); connectedcomponents::NoOp<uint32_t> sop; return connectedComponents_sub1(I, L, connectivity, sop);
}else{ }else{
CV_Assert(false); CV_Assert(false);
...@@ -408,14 +426,16 @@ int connectedComponents(InputArray I, OutputArray L, int connectivity){ ...@@ -408,14 +426,16 @@ int connectedComponents(InputArray I, OutputArray L, int connectivity){
} }
} }
int connectedComponentsWithStats(InputArray I, OutputArray L, OutputArray statsv, int connectivity){ int connectedComponentsWithStats(InputArray _I, OutputArray _L, OutputArray statsv, OutputArray centroids, int connectivity, int ltype){
int lDepth = L.depth(); const cv::Mat I = _I.getMat();
if(lDepth == CV_8U){ _L.create(I.size(), CV_MAT_TYPE(ltype));
connectedcomponents::CCStatsOp<uint8_t> sop(statsv); return connectedComponents_sub1(I, L, connectivity, sop); cv::Mat L = _L.getMat();
}else if(lDepth == CV_16U){ if(ltype == CV_8U){
connectedcomponents::CCStatsOp<uint16_t> sop(statsv); return connectedComponents_sub1(I, L, connectivity, sop); connectedcomponents::CCStatsOp<uint8_t> sop(statsv, centroids); return connectedComponents_sub1(I, L, connectivity, sop);
}else if(lDepth == CV_32S){ }else if(ltype == CV_16U){
connectedcomponents::CCStatsOp<uint32_t> sop(statsv); return connectedComponents_sub1(I, L, connectivity, sop); connectedcomponents::CCStatsOp<uint16_t> sop(statsv, centroids); return connectedComponents_sub1(I, L, connectivity, sop);
}else if(ltype == CV_32S){
connectedcomponents::CCStatsOp<uint32_t> sop(statsv, centroids); return connectedComponents_sub1(I, L, connectivity, sop);
}else{ }else{
CV_Assert(false); CV_Assert(false);
return 0; return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment