public void run(ImageProcessor ip) {

    dimz = stack.getSize();
    dimy = stack.getWidth();
    dimx = stack.getHeight();

    SaveDialog sd = new SaveDialog("Save Measurements as Text...", "res", ".dat");
    String name = sd.getFileName();
    if (name == null) return;

    String directory = sd.getDirectory();

    nb = calculnb(stack); // -1;
    IJ.showStatus("Measure parameters for the " + nb + " objects ...");
    if (nb < 1) {
      IJ.showMessage("volume must be labeled");
    } else {
      double[] volume_m = new double[nb];
      int[] volume_p = new int[nb];
      double[] surface = new double[nb];
      double[] surfacenb = new double[nb];
      double[][][] I = new double[3][3][nb];
      double[][] J = new double[3][nb];
      double[][][] dir = new double[3][3][nb];
      double[] xg = new double[nb];
      double[] yg = new double[nb];
      double[] zg = new double[nb];
      byte[] bord = new byte[nb];
      //       		double[] a = new double[nb];
      //       		double[] b = new double[nb];
      //       		double[] c = new double[nb];
      //       		double[] Fab = new double[nb];
      //       		double[] Fac = new double[nb];
      //       		double[] Fbc = new double[nb];
      //       		double[] sp = new double[nb];
      double[][] lmin = new double[nb][3];
      double[][] lmax = new double[nb][3];
      IJ.showStatus("Measure surfaces ...");
      calculmarchsurfstack(stack, nb, surface, volume_m);
      calculmarchsurfstacknb(stack, nb, surfacenb);
      // calculvolumestack(stack,nb,volume_p);
      IJ.showStatus("Measure volumes and inertia ...");
      calculcgstack(stack, nb, volume_p, xg, yg, zg);
      calculinertiestack(stack, nb, xg, yg, zg, I);
      inertie(nb, I, J, dir);
      IJ.showStatus("Measure bounding boxes ...");
      boitestack(stack, nb, xg, yg, zg, dir, lmin, lmax);
      borderstack(stack, nb, bord);
      IJ.showStatus("Save results ...");
      sauvegarde(
          volume_p, volume_m, surface, surfacenb, xg, yg, zg, J, dir, nb, bord, lmin, lmax,
          directory, name);
      volume_m = null;
      volume_p = null;
      surface = null;
      xg = null;
      yg = null;
      zg = null;
    }
  }
  void borderstack(final ImageStack stack1, int nb, byte[] b) {
    final AtomicInteger ai = new AtomicInteger(0);
    final int dimX = stack1.getWidth();
    final int dimY = stack1.getHeight();
    final int dimZ = stack1.getSize();
    final byte[][] bord = new byte[dimZ][nb];

    for (int ithread = 0; ithread < threads.length; ithread++) {

      // Concurrently run in as many threads as CPUs

      threads[ithread] =
          new Thread() {

            public void run() {
              for (int superi = ai.getAndIncrement();
                  superi < dimZ;
                  superi = ai.getAndIncrement()) {
                int k = superi;
                ImageProcessor ip = stack1.getProcessor(k + 1);
                for (int j = 0; j < dimY; j++) {
                  for (int i = 0; i < dimX; i++) {
                    int val = (int) (ip.getPixelValue(i, j));
                    if ((val != 0)
                        && (i == 0
                            || j == 0
                            || k == 0
                            || i == dimX - 1
                            || j == dimY - 1
                            || k == dimZ - 1))
                      // bord[k][val-2]=1;
                      bord[k][val - 1] = 1;
                  }
                }
              }
            }
          };
    }
    startAndJoin(threads);
    for (int i = 0; i < dimZ; i++) {
      for (int j = 0; j < nb; j++) {
        b[j] *= (1 - bord[i][j]);
      }
    }
    for (int j = 0; j < nb; j++) {
      b[j] = (byte) (1 - b[j]);
    }
  }
  public int calculnb(final ImageStack stack1) {
    final AtomicInteger ai = new AtomicInteger(1);
    final int dimX = stack1.getWidth();
    final int dimY = stack1.getHeight();
    final int dimZ = stack1.getSize();
    final int[] value = new int[dimZ];

    for (int ithread = 0; ithread < threads.length; ithread++) {

      // Concurrently run in as many threads as CPUs

      threads[ithread] =
          new Thread() {

            public void run() {
              for (int superi = ai.getAndIncrement();
                  superi <= dimZ;
                  superi = ai.getAndIncrement()) {
                int current = superi;
                ImageProcessor ip = stack1.getProcessor(current);
                for (int j = 0; j < dimY; j++) {
                  for (int i = 0; i < dimX; i++) {
                    int val = (int) (ip.getPixelValue(i, j));
                    if (val > value[current - 1]) value[current - 1] = val;
                  }
                }
              }
            }
          };
    }
    startAndJoin(threads);

    int val = 0;
    for (int i = 0; i < dimZ; i++) {
      if (val < value[i]) val = value[i];
    }
    return val;
  }
  void calculvolumestack(final ImageStack stack1, int nb, int v[]) {
    final AtomicInteger ai = new AtomicInteger(1);
    final int dimX = stack1.getWidth();
    final int dimY = stack1.getHeight();
    final int dimZ = stack1.getSize();
    final int[][] vol = new int[dimZ][nb];

    for (int ithread = 0; ithread < threads.length; ithread++) {

      // Concurrently run in as many threads as CPUs

      threads[ithread] =
          new Thread() {

            public void run() {
              for (int superi = ai.getAndIncrement();
                  superi <= dimZ;
                  superi = ai.getAndIncrement()) {
                int current = superi;
                ImageProcessor ip = stack1.getProcessor(current);
                for (int j = 0; j < dimY; j++) {
                  for (int i = 0; i < dimX; i++) {
                    int val = (int) (ip.getPixelValue(i, j));
                    // if (val!=0) vol[current-1][val-2]++;
                    if (val != 0) vol[current - 1][val - 1]++;
                  }
                }
              }
            }
          };
    }
    startAndJoin(threads);
    for (int i = 0; i < dimZ; i++) {
      for (int j = 0; j < nb; j++) {
        v[j] += vol[i][j];
      }
    }
  }
  void boitestack(
      final ImageStack stack1,
      final int nb,
      final double[] xg,
      final double[] yg,
      final double[] zg,
      final double[][][] dir,
      double[][] lmin,
      double[][] lmax) {
    final AtomicInteger ai = new AtomicInteger(0);
    final int dimX = stack1.getWidth();
    final int dimY = stack1.getHeight();
    final int dimZ = stack1.getSize();
    final double[][][] lmint = new double[dimZ][nb][3];
    final double[][][] lmaxt = new double[dimZ][nb][3];

    for (int k = 0; k < nb; k++) {
      lmin[k][0] = 100000;
      lmin[k][1] = 100000;
      lmin[k][2] = 100000;
      lmax[k][0] = -100000;
      lmax[k][1] = -100000;
      lmax[k][2] = -100000;
    }

    for (int ithread = 0; ithread < threads.length; ithread++) {

      // Concurrently run in as many threads as CPUs

      threads[ithread] =
          new Thread() {

            public void run() {
              for (int superi = ai.getAndIncrement();
                  superi < dimZ;
                  superi = ai.getAndIncrement()) {
                int k = superi;
                ImageProcessor ip = stack1.getProcessor(k + 1);
                for (int l = 0; l < nb; l++) {
                  lmint[k][l][0] = 100000;
                  lmint[k][l][1] = 100000;
                  lmint[k][l][2] = 100000;
                  lmaxt[k][l][0] = -100000;
                  lmaxt[k][l][1] = -100000;
                  lmaxt[k][l][2] = -100000;
                }
                for (int j = 0; j < dimY; j++) {
                  for (int i = 0; i < dimX; i++) {
                    int pix = (int) (ip.getPixelValue(i, j));
                    if (pix != 0) {
                      //								double v1 =
                      // (i-xg[pix-2])*dir[0][0][pix-2]+(j-yg[pix-2])*dir[1][0][pix-2]+(k-zg[pix-2])*dir[2][0][pix-2];
                      //							    double v2 =
                      // (i-xg[pix-2])*dir[0][1][pix-2]+(j-yg[pix-2])*dir[1][1][pix-2]+(k-zg[pix-2])*dir[2][1][pix-2];
                      //							    double v3 =
                      // (i-xg[pix-2])*dir[0][2][pix-2]+(j-yg[pix-2])*dir[1][2][pix-2]+(k-zg[pix-2])*dir[2][2][pix-2];
                      //							    if (v1<lmint[k][pix-2][0]) lmint[k][pix-2][0]=v1;
                      //							    if (v1>lmaxt[k][pix-2][0]) lmaxt[k][pix-2][0]=v1;
                      //							    if (v2<lmint[k][pix-2][1]) lmint[k][pix-2][1]=v2;
                      //							    if (v2>lmaxt[k][pix-2][1]) lmaxt[k][pix-2][1]=v2;
                      //							    if (v3<lmint[k][pix-2][2]) lmint[k][pix-2][2]=v3;
                      //							    if (v3>lmaxt[k][pix-2][2]) lmaxt[k][pix-2][2]=v3;
                      double v1 =
                          (i - xg[pix - 1]) * dir[0][0][pix - 1]
                              + (j - yg[pix - 1]) * dir[1][0][pix - 1]
                              + (k - zg[pix - 1]) * dir[2][0][pix - 1];
                      double v2 =
                          (i - xg[pix - 1]) * dir[0][1][pix - 1]
                              + (j - yg[pix - 1]) * dir[1][1][pix - 1]
                              + (k - zg[pix - 1]) * dir[2][1][pix - 1];
                      double v3 =
                          (i - xg[pix - 1]) * dir[0][2][pix - 1]
                              + (j - yg[pix - 1]) * dir[1][2][pix - 1]
                              + (k - zg[pix - 1]) * dir[2][2][pix - 1];
                      if (v1 < lmint[k][pix - 1][0]) lmint[k][pix - 1][0] = v1;
                      if (v1 > lmaxt[k][pix - 1][0]) lmaxt[k][pix - 1][0] = v1;
                      if (v2 < lmint[k][pix - 1][1]) lmint[k][pix - 1][1] = v2;
                      if (v2 > lmaxt[k][pix - 1][1]) lmaxt[k][pix - 1][1] = v2;
                      if (v3 < lmint[k][pix - 1][2]) lmint[k][pix - 1][2] = v3;
                      if (v3 > lmaxt[k][pix - 1][2]) lmaxt[k][pix - 1][2] = v3;
                    }
                  }
                }
              }
            }
          };
    }
    startAndJoin(threads);
    for (int i = 0; i < dimZ; i++) {
      for (int j = 0; j < nb; j++) {
        for (int l = 0; l < 3; l++) {
          if (lmint[i][j][l] < lmin[j][l]) lmin[j][l] = lmint[i][j][l];
          if (lmaxt[i][j][l] > lmax[j][l]) lmax[j][l] = lmaxt[i][j][l];
        }
      }
      lmint[i] = null;
      lmaxt[i] = null;
    }
  }
  void calculinertiestack(
      final ImageStack stack1,
      int nb,
      final double[] xg,
      final double[] yg,
      final double[] zg,
      double[][][] I) {
    final AtomicInteger ai = new AtomicInteger(0);
    final int dimX = stack1.getWidth();
    final int dimY = stack1.getHeight();
    final int dimZ = stack1.getSize();
    final double[][][][] inert = new double[dimZ][nb][3][3];

    for (int ithread = 0; ithread < threads.length; ithread++) {

      // Concurrently run in as many threads as CPUs

      threads[ithread] =
          new Thread() {

            public void run() {
              for (int superi = ai.getAndIncrement();
                  superi < dimZ;
                  superi = ai.getAndIncrement()) {
                int k = superi;
                ImageProcessor ip = stack1.getProcessor(k + 1);
                for (int j = 0; j < dimY; j++) {
                  for (int i = 0; i < dimX; i++) {
                    int pix = (int) (ip.getPixelValue(i, j));
                    if (pix != 0) {
                      //
                      // inert[k][pix-2][0][0]+=(i-yg[pix-2])*(i-yg[pix-2])+(k-zg[pix-2])*(k-zg[pix-2])+1.0/6.0;
                      //						         inert[k][pix-2][0][1]-=(j-xg[pix-2])*(i-yg[pix-2]);
                      //						         inert[k][pix-2][0][2]-=(j-xg[pix-2])*(k-zg[pix-2]);
                      //
                      // inert[k][pix-2][1][1]+=(j-xg[pix-2])*(j-xg[pix-2])+(k-zg[pix-2])*(k-zg[pix-2])+1.0/6.0;
                      //						         inert[k][pix-2][1][2]-=(i-yg[pix-2])*(k-zg[pix-2]);
                      //
                      // inert[k][pix-2][2][2]+=(j-xg[pix-2])*(j-xg[pix-2])+(i-yg[pix-2])*(i-yg[pix-2])+1.0/6.0;
                      inert[k][pix - 1][0][0] +=
                          (j - yg[pix - 1]) * (j - yg[pix - 1])
                              + (k - zg[pix - 1]) * (k - zg[pix - 1])
                              + 1.0 / 6.0;
                      inert[k][pix - 1][0][1] -= (i - xg[pix - 1]) * (j - yg[pix - 1]);
                      inert[k][pix - 1][0][2] -= (i - xg[pix - 1]) * (k - zg[pix - 1]);
                      inert[k][pix - 1][1][1] +=
                          (i - xg[pix - 1]) * (i - xg[pix - 1])
                              + (k - zg[pix - 1]) * (k - zg[pix - 1])
                              + 1.0 / 6.0;
                      inert[k][pix - 1][1][2] -= (j - yg[pix - 1]) * (k - zg[pix - 1]);
                      inert[k][pix - 1][2][2] +=
                          (i - xg[pix - 1]) * (i - xg[pix - 1])
                              + (j - yg[pix - 1]) * (j - yg[pix - 1])
                              + 1.0 / 6.0;
                    }
                  }
                }
              }
            }
          };
    }
    startAndJoin(threads);
    for (int i = 0; i < dimZ; i++) {
      for (int j = 0; j < nb; j++) {
        for (int l = 0; l < 3; l++) {
          for (int m = 0; m <= l; m++) {
            I[l][m][j] += inert[i][j][l][m];
          }
        }
      }
      inert[i] = null;
    }
    for (int j = 0; j < nb; j++) {
      I[1][0][j] = I[0][1][j];
      I[2][0][j] = I[0][2][j];
      I[2][1][j] = I[1][2][j];
    }
  }
  void calculcgstack(
      final ImageStack stack1,
      int nb,
      final int[] v,
      final double[] xg,
      final double[] yg,
      final double[] zg) {
    final AtomicInteger ai = new AtomicInteger(0);
    final int dimX = stack1.getWidth();
    final int dimY = stack1.getHeight();
    final int dimZ = stack1.getSize();
    final int[][] vol = new int[dimZ][nb];
    final int[][] tmpxg = new int[dimZ][nb];
    final int[][] tmpyg = new int[dimZ][nb];
    final int[][] tmpzg = new int[dimZ][nb];

    for (int ithread = 0; ithread < threads.length; ithread++) {

      // Concurrently run in as many threads as CPUs

      threads[ithread] =
          new Thread() {

            public void run() {
              for (int superi = ai.getAndIncrement();
                  superi < dimZ;
                  superi = ai.getAndIncrement()) {
                int k = superi;
                ImageProcessor ip = stack1.getProcessor(k + 1);
                for (int j = 0; j < dimY; j++) {
                  for (int i = 0; i < dimX; i++) {
                    int pix = (int) (ip.getPixelValue(i, j));
                    if (pix != 0) {
                      //						          tmpxg[k][pix-2] += j;
                      //						          tmpyg[k][pix-2] += i;
                      //						          tmpzg[k][pix-2] += k;
                      //						          vol[k][pix-2]++;
                      tmpxg[k][pix - 1] += i;
                      tmpyg[k][pix - 1] += j;
                      tmpzg[k][pix - 1] += k;
                      vol[k][pix - 1]++;
                    }
                  }
                }
              }
            }
          };
    }
    startAndJoin(threads);
    for (int i = 0; i < dimZ; i++) {
      for (int j = 0; j < nb; j++) {
        v[j] += vol[i][j];
        xg[j] += tmpxg[i][j];
        yg[j] += tmpyg[i][j];
        zg[j] += tmpzg[i][j];
      }
    }

    for (int i = 0; i < nb; i++) {
      xg[i] = (1.0 * xg[i] / v[i]);
      yg[i] = (1.0 * yg[i] / v[i]);
      zg[i] = (1.0 * zg[i] / v[i]);
    }
  }
  void calculsurfacemarch3stack(final ImageStack stack1, int nb, final double[] tri, double[] s2) {
    final AtomicInteger ai = new AtomicInteger(0);
    final int dimX = stack1.getWidth();
    final int dimY = stack1.getHeight();
    final int dimZ = stack1.getSize();
    final double[][] surf = new double[dimZ][nb];

    for (int ithread = 0; ithread < threads.length; ithread++) {

      // Concurrently run in as many threads as CPUs

      threads[ithread] =
          new Thread() {

            public void run() {
              for (int superi = ai.getAndIncrement();
                  superi < dimZ - 1;
                  superi = ai.getAndIncrement()) {
                int k = superi;
                ImageProcessor ip1, ip2;
                ip1 = stack1.getProcessor(k + 1);
                ip2 = stack1.getProcessor(k + 2);
                for (int j = 0; j < dimY - 1; j++) {
                  for (int i = 0; i < dimX - 1; i++) {
                    int[] p = new int[8];
                    int p1, p2, p3, p4, p5, p6, p7, p8, ptot;
                    int[] nontab = new int[8];

                    ptot = (short) 0;
                    p[0] = (int) ip1.getPixelValue(i, j);
                    p[1] = (int) ip1.getPixelValue(i, j + 1);
                    p[2] = (int) ip2.getPixelValue(i, j);
                    p[3] = (int) ip2.getPixelValue(i, j + 1);
                    p[4] = (int) ip1.getPixelValue(i + 1, j);
                    p[5] = (int) ip1.getPixelValue(i + 1, j + 1);
                    p[6] = (int) ip2.getPixelValue(i + 1, j);
                    p[7] = (int) ip2.getPixelValue(i + 1, j + 1);

                    int pixcoul = 0;

                    for (int l = 0; l < 8; l++) nontab[l] = 0;

                    int cpt = 0;

                    // look for different colors
                    for (int l = 0; l < 8; l++) {
                      if (p[l] != 0 && appart(p[l], nontab, 8) == 1) {
                        nontab[cpt] = p[l];
                        cpt++;
                      }
                    }

                    for (int mm = 0; mm < cpt; mm++) {
                      p1 = 0;
                      p2 = 0;
                      p3 = 0;
                      p4 = 0;
                      p5 = 0;
                      p6 = 0;
                      p7 = 0;
                      p8 = 0;

                      if (p[0] != 0 && p[0] == nontab[mm]) {
                        pixcoul = nontab[mm];
                        p1 = 1;
                      }

                      if (p[1] != 0 && p[1] == nontab[mm]) {
                        pixcoul = nontab[mm];
                        p2 = 4;
                      }

                      if (p[2] != 0 && p[2] == nontab[mm]) {
                        pixcoul = nontab[mm];
                        p3 = 2;
                      }

                      if (p[3] != 0 && p[3] == nontab[mm]) {
                        pixcoul = nontab[mm];
                        p4 = 8;
                      }

                      if (p[4] != 0 && p[4] == nontab[mm]) {
                        pixcoul = nontab[mm];
                        p5 = 16;
                      }

                      if (p[5] != 0 && p[5] == nontab[mm]) {
                        pixcoul = nontab[mm];
                        p6 = 64;
                      }

                      if (p[6] != 0 && p[6] == nontab[mm]) {
                        pixcoul = nontab[mm];
                        p7 = 32;
                      }

                      if (p[7] != 0 && p[7] == nontab[mm]) {
                        pixcoul = nontab[mm];
                        p8 = 128;
                      }

                      ptot = (p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8);

                      if (pixcoul != 0) {
                        surf[k][(int) (pixcoul - 1)] += tri[(int) (ptot)];
                        // surf[k][(int)(pixcoul-2)]+=tri[(int)(ptot)];
                      }
                    }
                  }
                }
              }
            }
          };
    }
    startAndJoin(threads);
    for (int i = 0; i < dimZ; i++) {
      for (int j = 0; j < nb; j++) {
        s2[j] += surf[i][j];
      }
    }
  }