docs: public void process( GrayU8 input ) {
  		// input = im_0
  
  		removedWatersheds = false;
  		output.reshape(input.width+2,input.height+2);
  		distance.reshape(input.width+2,input.height+2);
  
  		ImageMiscOps.fill(output, INIT);
  		ImageMiscOps.fill(distance, 0);
  		fifo.reset();
  
  		// sort pixels
  		sortPixels(input);
  
  		currentLabel = 0;
  
  		for( int i = 0; i < histogram.length; i++ ) {
  			GrowQueue_I32 level = histogram[i];
  			if( level.size == 0 )
  				continue;
  
  			// Go through each pixel at this level and mark them according to their neighbors
  			for( int j = 0; j < level.size; j++ ) {
  				int index = level.data[j];
  				output.data[index] = MASK;
  
  				// see if its neighbors has been labeled, if so set its distance and add to queue
  				assignNewToNeighbors(index);
  			}
  
  			currentDistance = 1;
  			fifo.add(MARKER_PIXEL);
  
  			while( true ) {
  				int p = fifo.popHead();
  
  				// end of a cycle.  Exit the loop if it is done or increase the distance and continue processing
  				if( p == MARKER_PIXEL) {
  					if( fifo.isEmpty() )
  						break;
  					else {
  						fifo.add(MARKER_PIXEL);
  						currentDistance++;
  						p = fifo.popHead();
  					}
  				}
  
  				// look at its neighbors and see if they have been labeled or belong to a watershed
  				// and update its distance
  				checkNeighborsAssign(p);
  			}
  
  			// see if new minima have been discovered
  			for( int j = 0; j < level.size; j++ ) {
  				int index = level.get(j);
  				// distance associated with p is reset to 0
  				distance.data[index] = 0;
  
  				if( output.data[index] == MASK ) {
  					currentLabel++;
  					fifo.add(index);
  					output.data[index] = currentLabel;
  
  					// grow the new region into the surrounding connected pixels
  					while( !fifo.isEmpty() ) {
  						checkNeighborsMasks(fifo.popHead());
  					}
  				}
  			}
  		}
  	}