diff --git a/modules/imgproc/src/segmentation.cpp b/modules/imgproc/src/segmentation.cpp index af1d777364..124aecdb2e 100644 --- a/modules/imgproc/src/segmentation.cpp +++ b/modules/imgproc/src/segmentation.cpp @@ -48,7 +48,7 @@ namespace cv { - +// A node represents a pixel to label struct WSNode { int next; @@ -56,6 +56,7 @@ struct WSNode int img_ofs; }; +// Queue for WSNodes struct WSQueue { WSQueue() { first = last = 0; } @@ -86,18 +87,26 @@ allocWSNodes( std::vector& storage ) void cv::watershed( InputArray _src, InputOutputArray _markers ) { - const int IN_QUEUE = -2; - const int WSHED = -1; + // Labels for pixels + const int IN_QUEUE = -2; // Pixel visited + const int WSHED = -1; // Pixel belongs to watershed + + // possible bit values = 2^8 const int NQ = 256; Mat src = _src.getMat(), dst = _markers.getMat(); Size size = src.size(); + // Vector of every created node std::vector storage; int free_node = 0, node; + // Priority queue of queues of nodes + // from high priority (0) to low priority (255) WSQueue q[NQ]; + // Non-empty queue with highest priority int active_queue; int i, j; + // Color differences int db, dg, dr; int subs_tab[513]; @@ -106,6 +115,7 @@ void cv::watershed( InputArray _src, InputOutputArray _markers ) // MIN(a,b) = a - MAX(a-b,0) #define ws_min(a,b) ((a) - subs_tab[(a)-(b)+NQ]) + // Create a new node with offsets mofs and iofs in queue idx #define ws_push(idx,mofs,iofs) \ { \ if( !free_node ) \ @@ -122,6 +132,7 @@ void cv::watershed( InputArray _src, InputOutputArray _markers ) q[idx].last = node; \ } + // Get next node from queue idx #define ws_pop(idx,mofs,iofs) \ { \ node = q[idx].first; \ @@ -134,6 +145,7 @@ void cv::watershed( InputArray _src, InputOutputArray _markers ) iofs = storage[node].img_ofs; \ } + // Get highest absolute channel difference in diff #define c_diff(ptr1,ptr2,diff) \ { \ db = std::abs((ptr1)[0] - (ptr2)[0]);\ @@ -147,9 +159,14 @@ void cv::watershed( InputArray _src, InputOutputArray _markers ) CV_Assert( src.type() == CV_8UC3 && dst.type() == CV_32SC1 ); CV_Assert( src.size() == dst.size() ); + // Current pixel in input image const uchar* img = src.ptr(); + // Step size to next row in input image int istep = int(src.step/sizeof(img[0])); + + // Current pixel in mask image int* mask = dst.ptr(); + // Step size to next row in mask image int mstep = int(dst.step / sizeof(mask[0])); for( i = 0; i < 256; i++ ) @@ -166,7 +183,7 @@ void cv::watershed( InputArray _src, InputOutputArray _markers ) for( i = 1; i < size.height-1; i++ ) { img += istep; mask += mstep; - mask[0] = mask[size.width-1] = WSHED; + mask[0] = mask[size.width-1] = WSHED; // boundary pixels for( j = 1; j < size.width-1; j++ ) { @@ -174,6 +191,7 @@ void cv::watershed( InputArray _src, InputOutputArray _markers ) if( m[0] < 0 ) m[0] = 0; if( m[0] == 0 && (m[-1] > 0 || m[1] > 0 || m[-mstep] > 0 || m[mstep] > 0) ) { + // Find smallest difference to adjacent markers const uchar* ptr = img + j*3; int idx = 256, t; if( m[-1] > 0 ) @@ -193,6 +211,8 @@ void cv::watershed( InputArray _src, InputOutputArray _markers ) c_diff( ptr, ptr + istep, t ); idx = ws_min( idx, t ); } + + // Add to according queue assert( 0 <= idx && idx <= 255 ); ws_push( idx, i*mstep + j, i*istep + j*3 ); m[0] = IN_QUEUE; @@ -221,6 +241,8 @@ void cv::watershed( InputArray _src, InputOutputArray _markers ) int* m; const uchar* ptr; + // Get non-empty queue with highest priority + // Exit condition: empty priority queue if( q[active_queue].first == 0 ) { for( i = active_queue+1; i < NQ; i++ ) @@ -231,35 +253,44 @@ void cv::watershed( InputArray _src, InputOutputArray _markers ) active_queue = i; } + // Get next node ws_pop( active_queue, mofs, iofs ); + // Calculate pointer to current pixel in input and marker image m = mask + mofs; ptr = img + iofs; - t = m[-1]; + + // Check surrounding pixels for labels + // to determine label for current pixel + t = m[-1]; // Left if( t > 0 ) lab = t; - t = m[1]; + t = m[1]; // Right if( t > 0 ) { if( lab == 0 ) lab = t; else if( t != lab ) lab = WSHED; } - t = m[-mstep]; + t = m[-mstep]; // Top if( t > 0 ) { if( lab == 0 ) lab = t; else if( t != lab ) lab = WSHED; } - t = m[mstep]; + t = m[mstep]; // Bottom if( t > 0 ) { if( lab == 0 ) lab = t; else if( t != lab ) lab = WSHED; } + + // Set label to current pixel in marker image assert( lab != 0 ); m[0] = lab; + if( lab == WSHED ) continue; + // Add adjacent, unlabeled pixels to corresponding queue if( m[-1] == 0 ) { c_diff( ptr, ptr - 3, t );