docs: public static void gradientInner(GrayF32 ii, double tl_x, double tl_y, double samplePeriod ,
  									 int regionSize, double kernelSize,
  									 float[] derivX, float derivY[])
  	{
  		// add 0.5 to c_x and c_y to have it round when converted to an integer pixel
  		// this is faster than the straight forward method
  		tl_x += 0.5;
  		tl_y += 0.5;
  
  		// round the kernel size
  		int w = (int)(kernelSize+0.5);
  		int r = w/2;
  		if( r <= 0 ) r = 1;
  		w = r*2+1;
  
  		int i = 0;
  		for( int y = 0; y < regionSize; y++ ) {
  			int pixelsY = (int)(tl_y + y * samplePeriod);
  			int indexRow1 = ii.startIndex + (pixelsY-r-1)*ii.stride - r - 1;
  			int indexRow2 = indexRow1 + r*ii.stride;
  			int indexRow3 = indexRow2 + ii.stride;
  			int indexRow4 = indexRow3 + r*ii.stride;
  
  			for( int x = 0; x < regionSize; x++ , i++) {
  				int pixelsX = (int)(tl_x + x * samplePeriod);
  
  				final int indexSrc1 = indexRow1 + pixelsX;
  				final int indexSrc2 = indexRow2 + pixelsX;
  				final int indexSrc3 = indexRow3 + pixelsX;
  				final int indexSrc4 = indexRow4 + pixelsX;
  
  				final float p0 = ii.data[indexSrc1];
  				final float p1 = ii.data[indexSrc1+r];
  				final float p2 = ii.data[indexSrc1+r+1];
  				final float p3 = ii.data[indexSrc1+w];
  				final float p11 = ii.data[indexSrc2];
  				final float p4 = ii.data[indexSrc2+w];
  				final float p10 = ii.data[indexSrc3];
  				final float p5 = ii.data[indexSrc3+w];
  				final float p9 = ii.data[indexSrc4];
  				final float p8 = ii.data[indexSrc4+r];
  				final float p7 = ii.data[indexSrc4+r+1];
  				final float p6 = ii.data[indexSrc4+w];
  
  				final float left = p8-p9-p1+p0;
  				final float right = p6-p7-p3+p2;
  				final float top = p4-p11-p3+p0;
  				final float bottom = p6-p9-p5+p10;
  
  				derivX[i] = right-left;
  				derivY[i] = bottom-top;
  //				System.out.printf("%2d %2d %2d %2d dx = %6.2f  dy = %6.2f\n",x,y,pixelsX,pixelsY,derivX[i],derivY[i]);
  			}
  		}
  	}