docs: @Override
  	protected void horizontal() {
  		float[] dataX = derivX.data;
  		float[] dataY = derivY.data;
  
  		float[] hXX = horizXX.data;
  		float[] hXY = horizXY.data;
  		float[] hYY = horizYY.data;
  
  		final int imgHeight = derivX.getHeight();
  		final int imgWidth = derivX.getWidth();
  
  		int windowWidth = radius * 2 + 1;
  
  		int radp1 = radius + 1;
  
  		BoofConcurrency.loopFor(0,imgHeight,row->{
  
  			int pix = row * imgWidth;
  			int end = pix + windowWidth;
  
  			float totalXX = 0;
  			float totalXY = 0;
  			float totalYY = 0;
  
  			int indexX = derivX.startIndex + row * derivX.stride;
  			int indexY = derivY.startIndex + row * derivY.stride;
  
  			for (; pix < end; pix++) {
  				float dx = dataX[indexX++];
  				float dy = dataY[indexY++];
  
  				totalXX += dx * dx;
  				totalXY += dx * dy;
  				totalYY += dy * dy;
  			}
  
  			hXX[pix - radp1] = totalXX;
  			hXY[pix - radp1] = totalXY;
  			hYY[pix - radp1] = totalYY;
  
  			end = row * imgWidth + imgWidth;
  			for (; pix < end; pix++, indexX++, indexY++) {
  
  				float dx = dataX[indexX - windowWidth];
  				float dy = dataY[indexY - windowWidth];
  
  				// saving these multiplications in an array to avoid recalculating them made
  				// the algorithm about 50% slower
  				totalXX -= dx * dx;
  				totalXY -= dx * dy;
  				totalYY -= dy * dy;
  
  				dx = dataX[indexX];
  				dy = dataY[indexY];
  
  				totalXX += dx * dx;
  				totalXY += dx * dy;
  				totalYY += dy * dy;
  
  				hXX[pix - radius] = totalXX;
  				hXY[pix - radius] = totalXY;
  				hYY[pix - radius] = totalYY;
  			}
  		});
  	}