docs: public static double[][] Kernel2D(int size, double wavelength, double orientation, double phaseOffset, double gaussVariance, double aspectRatio) {
          double sigmaX = gaussVariance;
          double sigmaY = gaussVariance / aspectRatio;
  
          int xMax = (int) Math.ceil(Math.max(1, Math.max(Math.abs(size * sigmaX * Math.cos(orientation)), Math.abs(size * sigmaY * Math.sin(orientation)))));
          int yMax = (int) Math.ceil(Math.max(1, Math.max(Math.abs(size * sigmaX * Math.sin(orientation)), Math.abs(size * sigmaY * Math.cos(orientation)))));
  
          double[][] kernel = new double[2 * xMax + 1][2 * yMax + 1];
  
          double sum = 0;
          for (int x = -xMax; x <= xMax; x++) {
              for (int y = -yMax; y <= yMax; y++) {
                  kernel[x + xMax][y + yMax] = Gabor.ImaginaryFunction2D(x, y, wavelength, orientation, phaseOffset, gaussVariance, aspectRatio);
                  sum += kernel[x + xMax][y + yMax];
              }
          }
          for (int x = -xMax; x <= xMax; x++) {
              for (int y = -yMax; y <= yMax; y++) {
                  kernel[x + xMax][y + yMax] /= sum;
              }
          }
          return kernel;
      }