docs: @Override
  	public void process(GrayF32 input , GrayU8 output ) {
  		inputPow2.reshape(input.width,input.height);
  		inputMean.reshape(input.width,input.height);
  		inputMeanPow2.reshape(input.width,input.height);
  		inputPow2Mean.reshape(input.width,input.height);
  		stdev.reshape(input.width,input.height);
  		tmp.reshape(input.width,input.height);
  		inputPow2.reshape(input.width,input.height);
  
  		int radius = width.computeI(Math.min(input.width,input.height))/2;
  
  		// mean of input image = E[X]
  		BlurImageOps.mean(input, inputMean, radius, tmp, work);
  
  		// standard deviation = sqrt( E[X^2] + E[X]^2)
  		PixelMath.pow2(input, inputPow2);
  		BlurImageOps.mean(inputPow2,inputPow2Mean,radius,tmp, work);
  		PixelMath.pow2(inputMean,inputMeanPow2);
  		PixelMath.subtract(inputPow2Mean, inputMeanPow2, stdev);
  		PixelMath.sqrt(stdev, stdev);
  
  		float R = ImageStatistics.max(stdev);
  
  		if( down ) {
  			BoofConcurrency.loopFor(0, input.height, y -> {
  				int i = y * stdev.width;
  				int indexIn = input.startIndex + y * input.stride;
  				int indexOut = output.startIndex + y * output.stride;
  
  				for (int x = 0; x < input.width; x++, i++) {
  					// threshold = mean.*(1 + k * ((deviation/R)-1));
  					float threshold = inputMean.data[i] * (1.0f + k * (stdev.data[i] / R - 1.0f));
  					output.data[indexOut++] = (byte) (input.data[indexIn++] <= threshold ? 1 : 0);
  				}
  			});
  		} else {
  			BoofConcurrency.loopFor(0, input.height, y -> {
  				int i = y * stdev.width;
  				int indexIn = input.startIndex + y * input.stride;
  				int indexOut = output.startIndex + y * output.stride;
  
  				for (int x = 0; x < input.width; x++, i++) {
  					// threshold = mean.*(1 + k * ((deviation/R)-1));
  					float threshold = inputMean.data[i] * (1.0f + k * (stdev.data[i] / R - 1.0f));
  					output.data[indexOut++] = (byte) (input.data[indexIn++] >= threshold ? 1 : 0);
  				}
  			});
  		}
  	}