code: public static void process_sub(GrayU8 orig,
  								   GrayS16 derivX,
  								   GrayS16 derivY) {
  		final byte[] data = orig.data;
  		final short[] imgX = derivX.data;
  		final short[] imgY = derivY.data;
  
  		final int width = orig.getWidth();
  		final int height = orig.getHeight() - 1;
  		final int strideSrc = orig.getStride();
  
  		//CONCURRENT_BELOW BoofConcurrency.loopFor(1,height,y->{
  		for (int y = 1; y < height; y++) {
  			int indexSrc = orig.startIndex + orig.stride * y + 1;
  			final int endX = indexSrc + width - 2;
  
  			int indexX = derivX.startIndex + derivX.stride * y + 1;
  			int indexY = derivY.startIndex + derivY.stride * y + 1;
  
  			for (; indexSrc < endX; indexSrc++) {
  				int v = (data[indexSrc + strideSrc + 1] & 0xFF) - (data[indexSrc - strideSrc - 1] & 0xFF);
  				int w = (data[indexSrc + strideSrc - 1] & 0xFF) - (data[indexSrc - strideSrc + 1] & 0xFF);
  
  				imgY[indexY++] = (short) (((data[indexSrc + strideSrc] & 0xFF) - (data[indexSrc - strideSrc] & 0xFF)) * 2 + v + w);
  
  				imgX[indexX++] = (short) (((data[indexSrc + 1] & 0xFF) - (data[indexSrc - 1] & 0xFF)) * 2 + v - w);
  			}
  		}
  		//CONCURRENT_ABOVE });
  	}
docs: Computes derivative of GrayU8.  Inputs can be sub-images.