docs: @Override
  	public void process(GrayF32 intensityImage, @Nullable QueueCorner localMin, @Nullable QueueCorner localMax) {
  
  		if( localMin != null )
  			localMin.reset();
  		if( localMax != null )
  			localMax.reset();
  
  		// the defines the region that can be processed
  		int endX = intensityImage.width - border;
  		int endY = intensityImage.height - border;
  
  		int step = configuration.radius+1;
  
  		search.initialize(configuration,intensityImage,localMin,localMax);
  
  		// Compute number of y iterations
  		int range = endY-border;
  		int N = range/step;
  		if( range > N*step )
  			N += 1;
  
  		BoofConcurrency.loopFor(0,N, iterY -> {
  
  			NonMaxBlock.Search search;
  			QueueCorner threadMin=null,threadMax=null;
  
  			// get work space for this thread
  			synchronized (lock) {
  				if( searches.isEmpty() ) {
  					search = this.search.newInstance();
  				} else {
  					search = searches.remove( searches.size()-1 );
  				}
  				if( search.isDetectMinimums() ) {
  					threadMin = pop();
  				}
  				if( search.isDetectMaximums() ) {
  					threadMax = pop();
  				}
  			}
  			search.initialize(configuration,intensityImage,threadMin,threadMax);
  
  			// search for local peaks along this block row
  			int y = border + iterY*step;
  			int y1 = y + step;
  			if( y1 > endY) y1 = endY;
  
  			for(int x = border; x < endX; x += step ) {
  				int x1 = x + step;
  				if( x1 > endX) x1 = endX;
  				search.searchBlock(x,y,x1,y1);
  			}
  
  			// Save the results and recycle thread working space
  			synchronized (lock) {
  				saveResults(localMin, threadMin);
  				saveResults(localMax, threadMax);
  
  				searches.add(search);
  				if( threadMin != null )
  					cornerLists.add(threadMin);
  				if( threadMax != null )
  					cornerLists.add(threadMax);
  			}
  		});
  	}