Пример #1
0
  public Image run(final Image image, final double scale) {
    System.out.println(scale);
    if (scale <= 0) throw new IllegalArgumentException("Smoothing scale less than or equal to 0");
    final Dimensions dims = image.dimensions();
    final Aspects asps = image.aspects();

    if (asps.x <= 0)
      throw new IllegalStateException("Aspect-ratio value in x-dimension less than or equal to 0");
    if (asps.y <= 0)
      throw new IllegalStateException("Aspect-ratio value in y-dimension less than or equal to 0");
    if (asps.z <= 0)
      throw new IllegalStateException("Aspect-ratio value in z-dimension less than or equal to 0");
    /*
     * It's very important to annotate whether it is a reference soft copy
     * or a deep copy. The code shows if image is the type of FloatImage,
     * just use the "object" if not, create a new FloatImage object which
     * don't share the pixels data.
     */
    final Image smoothImage =
        (image instanceof FloatImage)
            ? image
            : new FloatImage(image); // It's relationship of Deep Copy not just Reference

    final Image Hxx = differentiator.run(smoothImage.duplicate(), scale, 2, 0, 0);
    final Image Hxy = differentiator.run(smoothImage.duplicate(), scale, 1, 1, 0);

    final Image Hxz = differentiator.run(smoothImage.duplicate(), scale, 1, 0, 1);
    final Image Hyy = differentiator.run(smoothImage.duplicate(), scale, 0, 2, 0);
    final Image Hyz = differentiator.run(smoothImage.duplicate(), scale, 0, 1, 1);
    final Image Hzz = differentiator.run(smoothImage, scale, 0, 0, 2);

    Hxx.axes(Axes.X);
    Hxy.axes(Axes.X);
    Hxz.axes(Axes.X);
    Hyy.axes(Axes.X);
    Hyz.axes(Axes.X);
    Hzz.axes(Axes.X);
    final double[] ahxx = new double[dims.x];
    final double[] ahxy = new double[dims.x];
    final double[] ahxz = new double[dims.x];
    final double[] ahyy = new double[dims.x];
    final double[] ahyz = new double[dims.x];
    final double[] ahzz = new double[dims.x];
    final Coordinates coords = new Coordinates();

    for (coords.c = 0; coords.c < dims.c; ++coords.c)
      for (coords.t = 0; coords.t < dims.t; ++coords.t)
        for (coords.z = 0; coords.z < dims.z; ++coords.z)
          for (coords.y = 0; coords.y < dims.y; ++coords.y) {
            Hxx.get(coords, ahxx);
            Hxy.get(coords, ahxy);
            Hxz.get(coords, ahxz);
            Hyy.get(coords, ahyy);
            Hyz.get(coords, ahyz);
            Hzz.get(coords, ahzz);
            for (int x = 0; x < dims.x; ++x) {
              final double fhxx = ahxx[x];
              final double fhxy = ahxy[x];
              final double fhxz = ahxz[x];
              final double fhyy = ahyy[x];
              final double fhyz = ahyz[x];
              final double fhzz = ahzz[x];
              final double a = -(fhxx + fhyy + fhzz);
              final double b =
                  fhxx * fhyy + fhxx * fhzz + fhyy * fhzz - fhxy * fhxy - fhxz * fhxz - fhyz * fhyz;
              final double c =
                  fhxx * (fhyz * fhyz - fhyy * fhzz)
                      + fhyy * fhxz * fhxz
                      + fhzz * fhxy * fhxy
                      - 2 * fhxy * fhxz * fhyz;
              final double q = (a * a - 3 * b) / 9;
              final double r = (a * a * a - 4.5 * a * b + 13.5 * c) / 27;
              final double sqrtq = (q > 0) ? Math.sqrt(q) : 0;
              final double sqrtq3 = sqrtq * sqrtq * sqrtq;

              double absh1, absh2, absh3;
              double value1, value2, value3;
              if (sqrtq3 == 0) {
                absh1 = absh2 = absh3 = 0;
                value1 = value2 = value3 = 0;
              } else {
                final double rsqq3 = r / sqrtq3;
                final double angle =
                    (rsqq3 * rsqq3 <= 1) ? Math.acos(rsqq3) : Math.acos(rsqq3 < 0 ? -1 : 1);

                value1 = -2 * sqrtq * Math.cos(angle / 3) - a / 3;
                value2 = -2 * sqrtq * Math.cos((angle + TWOPI) / 3) - a / 3;
                value3 = -2 * sqrtq * Math.cos((angle - TWOPI) / 3) - a / 3;

                absh1 = Math.abs(value1);
                absh2 = Math.abs(value2);
                absh3 = Math.abs(value3);
              } // get the characteristic value's absolute value be ordered by |a1| >= |a2| >= |a3|

              if (absh2 < absh3) {
                final double tmp = value2;
                value2 = value3;
                value3 = tmp;
              }
              if (absh1 < absh2) {
                final double tmp1 = value1;
                value1 = value2;
                value2 = tmp1;
                if (absh2 < absh3) {
                  final double tmp2 = value2;
                  value2 = value3;
                  value3 = tmp2;
                }
              }

              ahxx[x] = frangi(value1, value2, value3);
            }
            Hxx.set(coords, ahxx);
          }
    return Hxx;
  }
Пример #2
0
  /**
   * Mirrors an image.
   *
   * @param image the input image to be mirrored. The image is overwritten with the results of
   *     mirroring.
   * @param axes indicates the axes along which to mirror. The image is mirrored in each dimension
   *     for which the corresponding boolean field of this parameter is {@code true}.
   * @exception NullPointerException if any of the parameters is {@code null}.
   */
  public void run(final Image image, final Axes axes) {

    messenger.log(ImageScience.prelude() + "Mirror");

    // Initialize timer:
    final Timer timer = new Timer();
    timer.messenger.log(messenger.log());
    timer.start();

    // Check parameters:
    messenger.log("Checking parameters");
    final Dimensions dims = image.dimensions();
    messenger.log(
        "Input image dimensions: (x,y,z,t,c) = ("
            + dims.x
            + ","
            + dims.y
            + ","
            + dims.z
            + ","
            + dims.t
            + ","
            + dims.c
            + ")");

    // Mirror input image:
    messenger.log("Mirroring " + image.type());
    progressor.steps(
        (axes.x ? dims.c * dims.t * dims.z : 0)
            + (axes.y ? dims.c * dims.t * dims.z : 0)
            + (axes.z ? dims.c * dims.t * (1 + (dims.z - 1) / 2) : 0)
            + (axes.t ? dims.c * (1 + (dims.t - 1) / 2) * dims.z : 0)
            + (axes.c ? (1 + (dims.c - 1) / 2) * dims.t * dims.z : 0));
    progressor.start();
    image.axes(Axes.X);

    // Mirror in x-dimension if requested:
    if (axes.x) {
      messenger.log("Mirroring in x-dimension");
      messenger.status("Mirroring in x-dimension...");
      final Coordinates c = new Coordinates();
      final double[] a = new double[dims.x];
      final int dimsxm1 = dims.x - 1;
      final int maxx = dimsxm1 / 2;
      for (c.c = 0; c.c < dims.c; ++c.c) {
        for (c.t = 0; c.t < dims.t; ++c.t) {
          for (c.z = 0; c.z < dims.z; ++c.z) {
            for (c.y = 0; c.y < dims.y; ++c.y) {
              image.get(c, a);
              for (int x1 = 0, x2 = dimsxm1; x1 <= maxx; ++x1, --x2) {
                final double tmp = a[x2];
                a[x2] = a[x1];
                a[x1] = tmp;
              }
              image.set(c, a);
            }
            progressor.step();
          }
        }
      }
    }

    // Mirror in y-dimension if requested:
    if (axes.y) {
      messenger.log("Mirroring in y-dimension");
      messenger.status("Mirroring in y-dimension...");
      final Coordinates c1 = new Coordinates();
      final Coordinates c2 = new Coordinates();
      final double[] a1 = new double[dims.x];
      final double[] a2 = new double[dims.x];
      final int dimsym1 = dims.y - 1;
      final int maxy = dimsym1 / 2;
      for (c1.c = c2.c = 0; c1.c < dims.c; ++c1.c, ++c2.c) {
        for (c1.t = c2.t = 0; c1.t < dims.t; ++c1.t, ++c2.t) {
          for (c1.z = c2.z = 0; c1.z < dims.z; ++c1.z, ++c2.z) {
            for (c1.y = 0, c2.y = dimsym1; c1.y <= maxy; ++c1.y, --c2.y) {
              image.get(c1, a1);
              image.get(c2, a2);
              image.set(c1, a2);
              image.set(c2, a1);
            }
            progressor.step();
          }
        }
      }
    }

    // Mirror in z-dimension if requested:
    if (axes.z) {
      messenger.log("Mirroring in z-dimension");
      messenger.status("Mirroring in z-dimension...");
      final Coordinates c1 = new Coordinates();
      final Coordinates c2 = new Coordinates();
      final double[] a1 = new double[dims.x];
      final double[] a2 = new double[dims.x];
      final int dimszm1 = dims.z - 1;
      final int maxz = dimszm1 / 2;
      for (c1.c = c2.c = 0; c1.c < dims.c; ++c1.c, ++c2.c) {
        for (c1.t = c2.t = 0; c1.t < dims.t; ++c1.t, ++c2.t) {
          for (c1.z = 0, c2.z = dimszm1; c1.z <= maxz; ++c1.z, --c2.z) {
            for (c1.y = c2.y = 0; c1.y < dims.y; ++c1.y, ++c2.y) {
              image.get(c1, a1);
              image.get(c2, a2);
              image.set(c1, a2);
              image.set(c2, a1);
            }
            progressor.step();
          }
        }
      }
    }

    // Mirror in t-dimension if requested:
    if (axes.t) {
      messenger.log("Mirroring in t-dimension");
      messenger.status("Mirroring in t-dimension...");
      final Coordinates c1 = new Coordinates();
      final Coordinates c2 = new Coordinates();
      final double[] a1 = new double[dims.x];
      final double[] a2 = new double[dims.x];
      final int dimstm1 = dims.t - 1;
      final int maxt = dimstm1 / 2;
      for (c1.c = c2.c = 0; c1.c < dims.c; ++c1.c, ++c2.c) {
        for (c1.t = 0, c2.t = dimstm1; c1.t <= maxt; ++c1.t, --c2.t) {
          for (c1.z = c2.z = 0; c1.z < dims.z; ++c1.z, ++c2.z) {
            for (c1.y = c2.y = 0; c1.y < dims.y; ++c1.y, ++c2.y) {
              image.get(c1, a1);
              image.get(c2, a2);
              image.set(c1, a2);
              image.set(c2, a1);
            }
            progressor.step();
          }
        }
      }
    }

    // Mirror in c-dimension if requested:
    if (axes.c) {
      messenger.log("Mirroring in c-dimension");
      messenger.status("Mirroring in c-dimension...");
      final Coordinates c1 = new Coordinates();
      final Coordinates c2 = new Coordinates();
      final double[] a1 = new double[dims.x];
      final double[] a2 = new double[dims.x];
      final int dimscm1 = dims.c - 1;
      final int maxc = dimscm1 / 2;
      for (c1.c = 0, c2.c = dimscm1; c1.c <= maxc; ++c1.c, --c2.c) {
        for (c1.t = c2.t = 0; c1.t < dims.t; ++c1.t, ++c2.t) {
          for (c1.z = c2.z = 0; c1.z < dims.z; ++c1.z, ++c2.z) {
            for (c1.y = c2.y = 0; c1.y < dims.y; ++c1.y, ++c2.y) {
              image.get(c1, a1);
              image.get(c2, a2);
              image.set(c1, a2);
              image.set(c2, a1);
            }
            progressor.step();
          }
        }
      }
    }

    // Finish up:
    image.name(image.name() + " mirrored");
    messenger.status("");
    progressor.stop();
    timer.stop();
  }
Пример #3
0
  /**
   * Finds local extrema in an image. A local extremum is defined as an image element whose value is
   * either larger (maximum) or smaller (minimum) than those of all its neighboring elements. If the
   * size of the image in the z-dimension equals {@code 1}, this method considers 8-connected
   * neighbors in x-y space, otherwise it considers 26-connected neighbors in x-y-z space. For
   * border elements, neighboring positions outside the image are ignored. The method searches for
   * local extrema in every x-y(-z) subimage in a 5D image.
   *
   * @param image the input image in which local extrema are to be found.
   * @param type the type of extrema to be found. Can be any or both (by addition) of {@link
   *     #MAXIMA} or {@link #MINIMA}.
   * @param mode determines how the found extrema are stored and returned. Can be any or both (by
   *     addition) of {@link #DETECT} or {@link #EXTRACT}.
   * @return if {@code mode} includes {@code DETECT}, the {@code image} is overwritten with the
   *     detection results: local maxima are set to {@code 255}, local minima to {@code 127}, and
   *     all other elements to {@code 0}. Otherwise the image is left unaltered. If {@code mode}
   *     includes {@code EXTRACT}, a new two-element {@code Vector} of {@code Vector<Coordinates>}
   *     objects is returned, containing the coordinates of all found local maxima (element {@code
   *     0}) and local minima (element {@code 1}). Otherwise the method returns {@code null}.
   * @exception NullPointerException if {@code image} is {@code null}.
   */
  public Vector<Vector<Coordinates>> run(final Image image, final int type, final int mode) {

    messenger.log(ImageScience.prelude() + "Extremizer");

    final Timer timer = new Timer();
    timer.messenger.log(messenger.log());
    timer.start();

    // Initialize:
    final Dimensions dims = image.dimensions();
    messenger.log(
        "Input image dimensions: (x,y,z,t,c) = ("
            + dims.x
            + ","
            + dims.y
            + ","
            + dims.z
            + ","
            + dims.t
            + ","
            + dims.c
            + ")");

    final boolean detect = (mode & DETECT) > 0;
    final boolean extract = (mode & EXTRACT) > 0;
    String detex = null;
    if (detect) {
      detex = extract ? "Detecting and extracting" : "Detecting";
    } else if (extract) {
      detex = "Extracting";
    } else {
      messenger.log("Neither detection nor extraction mode was selected");
      return null;
    }

    final boolean maxima = (type & MAXIMA) > 0;
    final boolean minima = (type & MINIMA) > 0;
    String maxmin = null;
    if (maxima) {
      maxmin = minima ? "maxima and minima" : "maxima";
    } else if (minima) {
      maxmin = "minima";
    } else {
      messenger.log("Neither maxima nor minima type was selected");
      return null;
    }

    final String demm = detex + " " + maxmin;

    final Vector<Coordinates> camax = extract ? new Vector<Coordinates>(dims.x, dims.x) : null;
    final Vector<Coordinates> camin = extract ? new Vector<Coordinates>(dims.x, dims.x) : null;

    messenger.status("Finding extrema...");

    // Find extrema:
    if (dims.z == 1) { // 2D case

      messenger.log(demm + " in 2D using 8-connectivity");
      progressor.steps(dims.c * dims.t * dims.y);
      progressor.start();
      image.axes(Axes.X);
      final Coordinates c0 = new Coordinates();
      c0.x = -1;
      final Coordinates c1 = new Coordinates();
      c1.x = -1;
      double[] mm = new double[dims.x + 2];
      double[] a0 = new double[dims.x + 2];
      double[] a1 = new double[dims.x + 2];
      double[] a2 = new double[dims.x + 2];
      double[] at = null;
      final int dimsxp1 = dims.x + 1;
      final int dimsym1 = dims.y - 1;
      final boolean dimsyis1 = (dims.y == 1);

      for (c0.c = c1.c = 0; c0.c < dims.c; ++c0.c, ++c1.c) {
        for (c0.t = c1.t = 0; c0.t < dims.t; ++c0.t, ++c1.t) {
          for (c0.y = 0, c1.y = 1; c0.y < dims.y; ++c0.y, ++c1.y) {
            set(mm, NEX);
            if (c0.y == 0) {
              image.get(c0, a1);
              if (!dimsyis1) image.get(c1, a2);
            } else {
              at = a0;
              a0 = a1;
              a1 = a2;
              a2 = at;
              if (c0.y < dimsym1) image.get(c1, a2);
            }
            // Find maxima:
            if (maxima) {
              if (c0.y == 0) {
                set(a0, DMIN);
                if (dimsyis1) set(a2, DMIN);
              } else if (c0.y == dimsym1) set(a2, DMIN);
              border(a0, DMIN);
              border(a1, DMIN);
              border(a2, DMIN);
              for (int x = 1, xm1 = 0, xp1 = 2; x < dimsxp1; ++x, ++xm1, ++xp1) {
                final double vx = a1[x];
                if (vx > a0[xm1]
                    && vx > a0[x]
                    && vx > a0[xp1]
                    && vx > a2[xm1]
                    && vx > a2[x]
                    && vx > a2[xp1]
                    && vx > a1[xm1]
                    && vx > a1[xp1]) {
                  if (extract) camax.add(new Coordinates(xm1, c0.y, 0, c0.t, c0.c));
                  mm[x] = MAX;
                }
              }
            }
            // Find minima:
            if (minima) {
              if (c0.y == 0) {
                set(a0, DMAX);
                if (dimsyis1) set(a2, DMAX);
              } else if (c0.y == dimsym1) set(a2, DMAX);
              border(a0, DMAX);
              border(a1, DMAX);
              border(a2, DMAX);
              for (int x = 1, xm1 = 0, xp1 = 2; x < dimsxp1; ++x, ++xm1, ++xp1) {
                final double vx = a1[x];
                if (vx < a0[xm1]
                    && vx < a0[x]
                    && vx < a0[xp1]
                    && vx < a2[xm1]
                    && vx < a2[x]
                    && vx < a2[xp1]
                    && vx < a1[xm1]
                    && vx < a1[xp1]) {
                  if (extract) camin.add(new Coordinates(xm1, c0.y, 0, c0.t, c0.c));
                  mm[x] = MIN;
                }
              }
            }
            if (detect) image.set(c0, mm);
            progressor.step();
          }
        }
      }
    } else { // 3D case

      messenger.log(demm + " in 3D using 26-connectivity");
      final int ysteps = (maxima ? dims.y : 0) + (minima ? dims.y : 0);
      progressor.steps(dims.c * dims.t * dims.z * ysteps);
      progressor.start();
      image.axes(Axes.X + Axes.Y);
      final Coordinates c0 = new Coordinates();
      c0.x = c0.y = -1;
      final Coordinates c1 = new Coordinates();
      c1.x = c1.y = -1;
      double[][] mm = new double[dims.y + 2][dims.x + 2];
      double[][] a0 = new double[dims.y + 2][dims.x + 2];
      double[][] a1 = new double[dims.y + 2][dims.x + 2];
      double[][] a2 = new double[dims.y + 2][dims.x + 2];
      double[][] at = null;
      final int dimsxp1 = dims.x + 1;
      final int dimsyp1 = dims.y + 1;
      final int dimszm1 = dims.z - 1;

      for (c0.c = c1.c = 0; c0.c < dims.c; ++c0.c, ++c1.c) {
        for (c0.t = c1.t = 0; c0.t < dims.t; ++c0.t, ++c1.t) {
          for (c0.z = 0, c1.z = 1; c0.z < dims.z; ++c0.z, ++c1.z) {
            set(mm, NEX);
            if (c0.z == 0) {
              image.get(c0, a1);
              image.get(c1, a2);
            } else {
              at = a0;
              a0 = a1;
              a1 = a2;
              a2 = at;
              if (c0.z < dimszm1) image.get(c1, a2);
            }
            // Find maxima:
            if (maxima) {
              if (c0.z == 0) set(a0, DMIN);
              else if (c0.z == dimszm1) set(a2, DMIN);
              border(a0, DMIN);
              border(a1, DMIN);
              border(a2, DMIN);
              for (int y = 1, ym1 = 0, yp1 = 2; y < dimsyp1; ++y, ++ym1, ++yp1) {
                final double[] a0ym1 = a0[ym1], a0y = a0[y], a0yp1 = a0[yp1];
                final double[] a1ym1 = a1[ym1], a1y = a1[y], a1yp1 = a1[yp1];
                final double[] a2ym1 = a2[ym1], a2y = a2[y], a2yp1 = a2[yp1];
                final double[] mmy = mm[y];
                for (int x = 1, xm1 = 0, xp1 = 2; x < dimsxp1; ++x, ++xm1, ++xp1) {
                  final double vx = a1y[x];
                  if (vx > a0ym1[xm1]
                      && vx > a0ym1[x]
                      && vx > a0ym1[xp1]
                      && vx > a0y[xm1]
                      && vx > a0y[x]
                      && vx > a0y[xp1]
                      && vx > a0yp1[xm1]
                      && vx > a0yp1[x]
                      && vx > a0yp1[xp1]
                      && vx > a1ym1[xm1]
                      && vx > a1ym1[x]
                      && vx > a1ym1[xp1]
                      && vx > a1y[xm1]
                      && vx > a1y[xp1]
                      && vx > a1yp1[xm1]
                      && vx > a1yp1[x]
                      && vx > a1yp1[xp1]
                      && vx > a2ym1[xm1]
                      && vx > a2ym1[x]
                      && vx > a2ym1[xp1]
                      && vx > a2y[xm1]
                      && vx > a2y[x]
                      && vx > a2y[xp1]
                      && vx > a2yp1[xm1]
                      && vx > a2yp1[x]
                      && vx > a2yp1[xp1]) {
                    if (extract) camax.add(new Coordinates(xm1, ym1, c0.z, c0.t, c0.c));
                    mmy[x] = MAX;
                  }
                }
                progressor.step();
              }
            }
            // Find minima:
            if (minima) {
              if (c0.z == 0) set(a0, DMAX);
              else if (c0.z == dimszm1) set(a2, DMAX);
              border(a0, DMAX);
              border(a1, DMAX);
              border(a2, DMAX);
              for (int y = 1, ym1 = 0, yp1 = 2; y < dimsyp1; ++y, ++ym1, ++yp1) {
                final double[] a0ym1 = a0[ym1], a0y = a0[y], a0yp1 = a0[yp1];
                final double[] a1ym1 = a1[ym1], a1y = a1[y], a1yp1 = a1[yp1];
                final double[] a2ym1 = a2[ym1], a2y = a2[y], a2yp1 = a2[yp1];
                final double[] mmy = mm[y];
                for (int x = 1, xm1 = 0, xp1 = 2; x < dimsxp1; ++x, ++xm1, ++xp1) {
                  final double vx = a1y[x];
                  if (vx < a0ym1[xm1]
                      && vx < a0ym1[x]
                      && vx < a0ym1[xp1]
                      && vx < a0y[xm1]
                      && vx < a0y[x]
                      && vx < a0y[xp1]
                      && vx < a0yp1[xm1]
                      && vx < a0yp1[x]
                      && vx < a0yp1[xp1]
                      && vx < a1ym1[xm1]
                      && vx < a1ym1[x]
                      && vx < a1ym1[xp1]
                      && vx < a1y[xm1]
                      && vx < a1y[xp1]
                      && vx < a1yp1[xm1]
                      && vx < a1yp1[x]
                      && vx < a1yp1[xp1]
                      && vx < a2ym1[xm1]
                      && vx < a2ym1[x]
                      && vx < a2ym1[xp1]
                      && vx < a2y[xm1]
                      && vx < a2y[x]
                      && vx < a2y[xp1]
                      && vx < a2yp1[xm1]
                      && vx < a2yp1[x]
                      && vx < a2yp1[xp1]) {
                    if (extract) camin.add(new Coordinates(xm1, ym1, c0.z, c0.t, c0.c));
                    mmy[x] = MIN;
                  }
                }
                progressor.step();
              }
            }
            if (detect) image.set(c0, mm);
          }
        }
      }
    }

    // Finish up:
    messenger.status("");
    progressor.stop();
    timer.stop();

    if (detect) image.name(image.name() + " extrema");

    final Vector<Vector<Coordinates>> vvc = new Vector<Vector<Coordinates>>(2);
    vvc.add(camax);
    vvc.add(camin);
    return vvc;
  }
Пример #4
0
  private void fft(final Image real, final Image imag, final Axes axes, final int sign) {

    final Timer timer = new Timer();
    timer.messenger.log(messenger.log());
    timer.start();

    // Initialize:
    check(real, imag, axes);
    final Coordinates c = new Coordinates();
    final Dimensions dims = real.dimensions();
    if (sign == -1) messenger.status("Forward FFT...");
    else messenger.status("Inverse FFT...");
    double[] re = null, im = null;
    double scale = 1;
    progressor.steps(
        (axes.x ? dims.c * dims.t * dims.z * dims.y : 0)
            + (axes.y ? dims.c * dims.t * dims.z * dims.x : 0)
            + (axes.z ? dims.c * dims.t * dims.z * dims.y : 0)
            + (axes.t ? dims.c * dims.t * dims.z * dims.y : 0)
            + (axes.c ? dims.c * dims.t * dims.z * dims.y : 0));
    progressor.start();

    // Transform in x-dimension if active:
    if (axes.x) {
      messenger.log("   FFT in x-dimension...");
      scale *= dims.x;
      c.reset();
      real.axes(Axes.X);
      imag.axes(Axes.X);
      re = new double[dims.x];
      im = new double[dims.x];
      for (c.c = 0; c.c < dims.c; ++c.c)
        for (c.t = 0; c.t < dims.t; ++c.t)
          for (c.z = 0; c.z < dims.z; ++c.z)
            for (c.y = 0; c.y < dims.y; ++c.y) {
              real.get(c, re);
              imag.get(c, im);
              fft(re, im, sign);
              real.set(c, re);
              imag.set(c, im);
              progressor.step();
            }
    }

    // Transform in y-dimension if active:
    if (axes.y) {
      messenger.log("   FFT in y-dimension...");
      scale *= dims.y;
      c.reset();
      real.axes(Axes.Y);
      imag.axes(Axes.Y);
      re = new double[dims.y];
      im = new double[dims.y];
      for (c.c = 0; c.c < dims.c; ++c.c)
        for (c.t = 0; c.t < dims.t; ++c.t)
          for (c.z = 0; c.z < dims.z; ++c.z)
            for (c.x = 0; c.x < dims.x; ++c.x) {
              real.get(c, re);
              imag.get(c, im);
              fft(re, im, sign);
              real.set(c, re);
              imag.set(c, im);
              progressor.step();
            }
    }

    // Transform in z-dimension if active:
    if (axes.z) {
      messenger.log("   FFT in z-dimension...");
      scale *= dims.z;
      c.reset();
      real.axes(Axes.Z);
      imag.axes(Axes.Z);
      re = new double[dims.z];
      im = new double[dims.z];
      for (c.c = 0; c.c < dims.c; ++c.c)
        for (c.t = 0; c.t < dims.t; ++c.t)
          for (c.y = 0; c.y < dims.y; ++c.y) {
            for (c.x = 0; c.x < dims.x; ++c.x) {
              real.get(c, re);
              imag.get(c, im);
              fft(re, im, sign);
              real.set(c, re);
              imag.set(c, im);
            }
            progressor.step(dims.z);
          }
    }

    // Transform in t-dimension if active:
    if (axes.t) {
      messenger.log("   FFT in t-dimension...");
      scale *= dims.t;
      c.reset();
      real.axes(Axes.T);
      imag.axes(Axes.T);
      re = new double[dims.t];
      im = new double[dims.t];
      for (c.c = 0; c.c < dims.c; ++c.c)
        for (c.z = 0; c.z < dims.z; ++c.z)
          for (c.y = 0; c.y < dims.y; ++c.y) {
            for (c.x = 0; c.x < dims.x; ++c.x) {
              real.get(c, re);
              imag.get(c, im);
              fft(re, im, sign);
              real.set(c, re);
              imag.set(c, im);
            }
            progressor.step(dims.t);
          }
    }

    // Transform in c-dimension if active:
    if (axes.c) {
      messenger.log("   FFT in c-dimension...");
      scale *= dims.c;
      c.reset();
      real.axes(Axes.C);
      imag.axes(Axes.C);
      re = new double[dims.c];
      im = new double[dims.c];
      for (c.t = 0; c.t < dims.t; ++c.t)
        for (c.z = 0; c.z < dims.z; ++c.z)
          for (c.y = 0; c.y < dims.y; ++c.y) {
            for (c.x = 0; c.x < dims.x; ++c.x) {
              real.get(c, re);
              imag.get(c, im);
              fft(re, im, sign);
              real.set(c, re);
              imag.set(c, im);
            }
            progressor.step(dims.c);
          }
    }

    // Scale correction in case of inverse transform:
    if (sign == 1) {
      messenger.log("   Scale correction...");
      real.divide(scale);
      imag.divide(scale);
    }

    messenger.log("Done");
    messenger.status("");
    progressor.stop();
    timer.stop();
  }