docs: @Override
  	public void process(GrayF32 input , GrayU8 output ) {
  		imageI2.reshape(input.width,input.height);
  		meanImage.reshape(input.width,input.height);
  		meanI2.reshape(input.width,input.height);
  		tmp.reshape(input.width,input.height);
  		imageI2.reshape(input.width,input.height);
  
  		int radius = width.computeI(Math.min(input.width,input.height))/2;
  
  		float NP = (radius*2+1)*(radius*2+1);
  
  		// mean of input image = E[X]
  		BlurImageOps.mean(input, meanImage, radius, tmp, work);
  
  		// Compute I^2
  		PixelMath.pow2(input, imageI2);
  
  		// Compute local mean of I^2
  		BlurImageOps.mean(imageI2, meanI2, radius, tmp, work);
  
  		if( down ) {
  			//CONCURRENT_BELOW BoofConcurrency.loopFor(0, input.height, y -> {
  			for (int y = 0; y < input.height; y++) {
  				int i = y * meanI2.width;
  				int indexIn = input.startIndex + y * input.stride;
  				int indexOut = output.startIndex + y * output.stride;
  
  				for (int x = 0; x < input.width; x++, i++) {
  					float mean = meanImage.data[i];
  					float A = meanI2.data[i] - (mean*mean/NP);
  
  					// threshold = mean + k*sqrt( A )
  					float threshold = mean + k*(float)Math.sqrt(A);
  					output.data[indexOut++] = (byte) (input.data[indexIn++] <= threshold ? 1 : 0);
  				}
  			}
  			//CONCURRENT_ABOVE });
  		} else {
  			//CONCURRENT_BELOW BoofConcurrency.loopFor(0, input.height, y -> {
  			for (int y = 0; y < input.height; y++) {
  				int i = y * meanI2.width;
  				int indexIn = input.startIndex + y * input.stride;
  				int indexOut = output.startIndex + y * output.stride;
  
  				for (int x = 0; x < input.width; x++, i++) {
  					float mean = meanImage.data[i];
  					float A = meanI2.data[i] - (mean*mean/NP);
  
  					// threshold = mean + k*sqrt( A )
  					float threshold = mean + k*(float)Math.sqrt(A);
  					output.data[indexOut++] = (byte) (input.data[indexIn++] >= threshold ? 1 : 0);
  				}
  			}
  			//CONCURRENT_ABOVE });
  		}
  	}