/*
  * This test is illustrative of an issue in IJ1 where the internal stack gets
  * deleted in certain cases. If you setProcessor() on an ImagePlus with a
  * stack of 1 slice the stack gets deleted. A subsequent call to getStack()
  * will hatch a new one using the pixels of the current ImageProcessor.
  * Basically to avoid problems the legacy layer should never call
  * setProcessor() or if it does it should do a getStack() rather than cache
  * calls to previous getStack() calls.
  */
 @Test
 public void testStackKiller() {
   final ImageStack stack = new ImageStack(2, 2);
   final byte[] slice = new byte[] {1, 2, 3, 4};
   stack.addSlice("one slice", slice);
   final ImagePlus imp = new ImagePlus("fred", stack);
   assertEquals(stack, imp.getStack());
   final byte[] slice2 = new byte[] {5, 6, 7, 8};
   final ByteProcessor proc = new ByteProcessor(2, 2, slice2, null);
   imp.setProcessor(proc);
   final ImageStack secondStack = imp.getStack();
   assertNotSame(stack, secondStack);
   assertEquals(slice, stack.getPixels(1));
   assertEquals(slice2, secondStack.getPixels(1));
 }
Exemple #2
0
  /** Performs actual projection using specified method. */
  public void doProjection() {
    if (imp == null) return;
    sliceCount = 0;
    if (method < AVG_METHOD || method > MEDIAN_METHOD) method = AVG_METHOD;
    for (int slice = startSlice; slice <= stopSlice; slice += increment) sliceCount++;
    if (method == MEDIAN_METHOD) {
      projImage = doMedianProjection();
      return;
    }

    // Create new float processor for projected pixels.
    FloatProcessor fp = new FloatProcessor(imp.getWidth(), imp.getHeight());
    ImageStack stack = imp.getStack();
    RayFunction rayFunc = getRayFunction(method, fp);
    if (IJ.debugMode == true) {
      IJ.log("\nProjecting stack from: " + startSlice + " to: " + stopSlice);
    }

    // Determine type of input image. Explicit determination of
    // processor type is required for subsequent pixel
    // manipulation.  This approach is more efficient than the
    // more general use of ImageProcessor's getPixelValue and
    // putPixel methods.
    int ptype;
    if (stack.getProcessor(1) instanceof ByteProcessor) ptype = BYTE_TYPE;
    else if (stack.getProcessor(1) instanceof ShortProcessor) ptype = SHORT_TYPE;
    else if (stack.getProcessor(1) instanceof FloatProcessor) ptype = FLOAT_TYPE;
    else {
      IJ.error("Z Project", "Non-RGB stack required");
      return;
    }

    // Do the projection.
    for (int n = startSlice; n <= stopSlice; n += increment) {
      IJ.showStatus("ZProjection " + color + ": " + n + "/" + stopSlice);
      IJ.showProgress(n - startSlice, stopSlice - startSlice);
      projectSlice(stack.getPixels(n), rayFunc, ptype);
    }

    // Finish up projection.
    if (method == SUM_METHOD) {
      fp.resetMinAndMax();
      projImage = new ImagePlus(makeTitle(), fp);
    } else if (method == SD_METHOD) {
      rayFunc.postProcess();
      fp.resetMinAndMax();
      projImage = new ImagePlus(makeTitle(), fp);
    } else {
      rayFunc.postProcess();
      projImage = makeOutputImage(imp, fp, ptype);
    }

    if (projImage == null) IJ.error("Z Project", "Error computing projection.");
  }
  private byte getPixel(
      final ImageStack image,
      final int x,
      final int y,
      final int z,
      final int w,
      final int h,
      final int d) {
    if (x >= 0 && x < w && y >= 0 && y < h && z >= 0 && z < d)
      return ((byte[]) image.getPixels(z + 1))[x + y * w];

    return (byte) 255;
  } /* end getPixel */
  private ImagePlus findSurfaceVoxels(final ImagePlus imp) {
    final int w = imp.getWidth();
    final int h = imp.getHeight();
    final int d = imp.getImageStackSize();
    final ImageStack stack = imp.getImageStack();
    final ImageStack surfaceStack = new ImageStack(w, h, d);

    for (int z = 0; z < d; z++) {
      IJ.showStatus("Finding surface voxels");
      final byte[] pixels = (byte[]) stack.getPixels(z + 1);
      surfaceStack.setPixels(pixels.clone(), z + 1);
      final ImageProcessor surfaceIP = surfaceStack.getProcessor(z + 1);
      for (int y = 0; y < h; y++) {
        checkNeighbours:
        for (int x = 0; x < w; x++) {
          if (getPixel(stack, x, y, z, w, h, d) == (byte) 0) continue;
          for (int nz = -1; nz < 2; nz++) {
            final int znz = z + nz;
            for (int ny = -1; ny < 2; ny++) {
              final int yny = y + ny;
              for (int nx = -1; nx < 2; nx++) {
                final int xnx = x + nx;
                final byte pixel = getPixel(stack, xnx, yny, znz, w, h, d);
                if (pixel == (byte) 0) continue checkNeighbours;
              }
            }
          }
          // we checked all the neighbours for a 0
          // but didn't find one, so this is not a surface voxel
          surfaceIP.set(x, y, (byte) 1);
        }
      }
    }
    // turn all the 1's into 0's
    final int wh = w * h;
    for (int z = 0; z < d; z++) {
      IJ.showStatus("Finding surface voxels");
      final ImageProcessor ip = surfaceStack.getProcessor(z + 1);
      for (int i = 0; i < wh; i++) {
        if (ip.get(i) == (byte) 1) ip.set(i, (byte) 0);
      }
    }

    final ImagePlus surfaceImp = new ImagePlus("Surface");
    surfaceImp.setStack(surfaceStack);
    surfaceImp.setCalibration(imp.getCalibration());
    return surfaceImp;
  }
Exemple #5
0
  /**
   * Saito-Toriwaki algorithm for Euclidian Distance Transformation. Direct application of Algorithm
   * 1. Bob Dougherty 8/8/2006
   *
   * <ul>
   *   <li>Version S1A: lower memory usage.
   *   <li>Version S1A.1 A fixed indexing bug for 666-bin data set
   *   <li>Version S1A.2 Aug. 9, 2006. Changed noResult value.
   *   <li>Version S1B Aug. 9, 2006. Faster.
   *   <li>Version S1B.1 Sept. 6, 2006. Changed comments.
   *   <li>Version S1C Oct. 1, 2006. Option for inverse case. <br>
   *       Fixed inverse behavior in y and z directions.
   *   <li>Version D July 30, 2007. Multithread processing for step 2.
   * </ul>
   *
   * <p>This version assumes the input stack is already in memory, 8-bit, and outputs to a new
   * 32-bit stack. Versions that are more stingy with memory may be forthcoming.
   *
   * @param imp 8-bit (binary) ImagePlus
   */
  private float[][] geometryToDistanceMap(ImagePlus imp, boolean inv) {
    final int w = imp.getWidth();
    final int h = imp.getHeight();
    final int d = imp.getStackSize();
    int nThreads = Runtime.getRuntime().availableProcessors();

    // Create references to input data
    ImageStack stack = imp.getStack();
    byte[][] data = new byte[d][];
    for (int k = 0; k < d; k++) data[k] = (byte[]) stack.getPixels(k + 1);

    // Create 32 bit floating point stack for output, s. Will also use it
    // for g in Transformation 1.
    float[][] s = new float[d][];
    for (int k = 0; k < d; k++) {
      ImageProcessor ipk = new FloatProcessor(w, h);
      s[k] = (float[]) ipk.getPixels();
    }
    float[] sk;
    // Transformation 1. Use s to store g.
    IJ.showStatus("EDT transformation 1/3");
    Step1Thread[] s1t = new Step1Thread[nThreads];
    for (int thread = 0; thread < nThreads; thread++) {
      s1t[thread] = new Step1Thread(thread, nThreads, w, h, d, inv, s, data);
      s1t[thread].start();
    }
    try {
      for (int thread = 0; thread < nThreads; thread++) {
        s1t[thread].join();
      }
    } catch (InterruptedException ie) {
      IJ.error("A thread was interrupted in step 1 .");
    }
    // Transformation 2. g (in s) -> h (in s)
    IJ.showStatus("EDT transformation 2/3");
    Step2Thread[] s2t = new Step2Thread[nThreads];
    for (int thread = 0; thread < nThreads; thread++) {
      s2t[thread] = new Step2Thread(thread, nThreads, w, h, d, s);
      s2t[thread].start();
    }
    try {
      for (int thread = 0; thread < nThreads; thread++) {
        s2t[thread].join();
      }
    } catch (InterruptedException ie) {
      IJ.error("A thread was interrupted in step 2 .");
    }
    // Transformation 3. h (in s) -> s
    IJ.showStatus("EDT transformation 3/3");
    Step3Thread[] s3t = new Step3Thread[nThreads];
    for (int thread = 0; thread < nThreads; thread++) {
      s3t[thread] = new Step3Thread(thread, nThreads, w, h, d, inv, s, data);
      s3t[thread].start();
    }
    try {
      for (int thread = 0; thread < nThreads; thread++) {
        s3t[thread].join();
      }
    } catch (InterruptedException ie) {
      IJ.error("A thread was interrupted in step 3 .");
    }
    // Find the largest distance for scaling
    // Also fill in the background values.
    float distMax = 0;
    final int wh = w * h;
    float dist;
    for (int k = 0; k < d; k++) {
      sk = s[k];
      for (int ind = 0; ind < wh; ind++) {
        if (((data[k][ind] & 255) < 128) ^ inv) {
          sk[ind] = 0;
        } else {
          dist = (float) Math.sqrt(sk[ind]);
          sk[ind] = dist;
          distMax = (dist > distMax) ? dist : distMax;
        }
      }
    }
    IJ.showProgress(1.0);
    IJ.showStatus("Done");
    return s;
  }
  public void Calc_5Fr(ImagePlus imp1, ImagePlus imp2) {
    if (imp1.getType() != imp2.getType()) {
      error();
      return;
    }
    if (imp1.getType() == 0) { // getType returns 0 for 8-bit, 1 for 16-bit
      bitDepth = "8-bit";
      Prefs.set("ps.bitDepth", bitDepth);
    } else {
      bitDepth = "16-bit";
      Prefs.set("ps.bitDepth", bitDepth);
    }
    int width = imp1.getWidth();
    int height = imp1.getHeight();
    if (width != imp2.getWidth() || height != imp2.getHeight()) {
      error();
      return;
    }

    ImageStack stack1 = imp1.getStack();
    //		if (bgStackTitle != "NoBg") ImageStack stack2 = imp2.getStack();
    ImageStack stack2 = imp2.getStack();

    ImageProcessor ip = imp1.getProcessor();
    int dimension = width * height;
    byte[] pixB;
    short[] pixS;
    float[][] pixF = new float[5][dimension];
    float[][] pixFBg = new float[5][dimension];

    float a;
    float b;
    float den;
    float aSmp;
    float bSmp;
    float denSmp;
    float aBg;
    float bBg;
    float denBg;
    float retF;
    float azimF;

    byte[] retB = new byte[dimension];
    short[] retS = new short[dimension];
    byte[] azimB = new byte[dimension];
    short[] azimS = new short[dimension];
    // Derived Variables:
    float swingAngle = 2f * (float) Math.PI * swing;
    float tanSwingAngleDiv2 = (float) Math.tan(swingAngle / 2.f);
    float tanSwingAngleDiv2DivSqrt2 = (float) (Math.tan(swingAngle / 2.f) / Math.sqrt(2));
    float wavelengthDiv2Pi = wavelength / (2f * (float) Math.PI);

    // get the pixels of each slice in the stack and convert to float
    for (int i = 0; i < 5; i++) {
      if (bitDepth == "8-bit") {
        pixB = (byte[]) stack1.getPixels(i + 3);
        for (int j = 0; j < dimension; j++) pixF[i][j] = 0xff & pixB[j];
        if (bgStackTitle != "NoBg") {
          pixB = (byte[]) stack2.getPixels(i + 3);
          for (int j = 0; j < dimension; j++) pixFBg[i][j] = 0xff & pixB[j];
        }
      } else {
        pixS = (short[]) stack1.getPixels(i + 3);
        for (int j = 0; j < dimension; j++) pixF[i][j] = (float) pixS[j];
        if (bgStackTitle != "NoBg") {
          pixS = (short[]) stack2.getPixels(i + 3);
          for (int j = 0; j < dimension; j++) pixFBg[i][j] = (float) pixS[j];
        }
      }
    }

    // Algorithm
    // terms a and b
    for (int j = 0; j < dimension; j++) {
      denSmp = (pixF[1][j] + pixF[2][j] + pixF[3][j] + pixF[4][j] - 4 * pixF[0][j]) / 2;
      denBg = denSmp;
      a = (pixF[4][j] - pixF[1][j]);
      aSmp = a;
      aBg = a;
      b = (pixF[2][j] - pixF[3][j]);
      bSmp = b;
      bBg = b;
      if (bgStackTitle != "NoBg") {
        denBg = (pixFBg[1][j] + pixFBg[2][j] + pixFBg[3][j] + pixFBg[4][j] - 4 * pixFBg[0][j]) / 2;
        aBg = pixFBg[4][j] - pixFBg[1][j];
        bBg = pixFBg[2][j] - pixFBg[3][j];
      }
      // Special case of sample retardance half wave, denSmp = 0
      if (denSmp == 0) {
        retF = (float) wavelength / 4;
        azimF =
            (float) (a == 0 & b == 0 ? 0 : (azimRef + 90 + 90 * Math.atan2(a, b) / Math.PI) % 180);
      } else {
        // Retardance, the background correction can be improved by separately considering sample
        // retardance values larger than a quarter wave
        if (bgStackTitle != "NoBg") {
          a = aSmp / denSmp - aBg / denBg;
          b = bSmp / denSmp - bBg / denBg;
        } else {
          a = aSmp / denSmp;
          b = bSmp / denSmp;
        }
        retF = (float) Math.atan(tanSwingAngleDiv2 * Math.sqrt(a * a + b * b));
        if (denSmp < 0) retF = (float) Math.PI - retF;
        retF = retF * wavelengthDiv2Pi; // convert to nm
        if (retF > retCeiling) retF = retCeiling;

        // Orientation
        if ((bgStackTitle == "NoBg") || ((bgStackTitle != "NoBg") && (Math.abs(denSmp) < 1))) {
          a = aSmp;
          b = bSmp;
        }
        azimF =
            (float) (a == 0 & b == 0 ? 0 : (azimRef + 90 + 90 * Math.atan2(a, b) / Math.PI) % 180);
      }
      if (bitDepth == "8-bit") retB[j] = (byte) (((int) (255 * retF / retCeiling)) & 0xff);
      else retS[j] = (short) (4095 * retF / retCeiling);
      if (mirror == "Yes") azimF = 180 - azimF;
      if (bitDepth == "8-bit") azimB[j] = (byte) (((int) azimF) & 0xff);
      else azimS[j] = (short) (azimF * 10f);
    }
    // show the resulting images in slice 1 and 2
    imp1.setSlice(3);
    if (bitDepth == "8-bit") {
      stack1.setPixels(retB, 1);
      stack1.setPixels(azimB, 2);
    } else {
      stack1.setPixels(retS, 1);
      stack1.setPixels(azimS, 2);
    }
    imp1.setSlice(1);
    IJ.selectWindow(imp1.getTitle());

    Prefs.set("ps.sampleStackTitle", sampleStackTitle);
    Prefs.set("ps.bgStackTitle", bgStackTitle);
    Prefs.set("ps.mirror", mirror);
    Prefs.set("ps.wavelength", wavelength);
    Prefs.set("ps.swing", swing);
    Prefs.set("ps.retCeiling", retCeiling);
    Prefs.set("ps.azimRef", azimRef);
    Prefs.savePreferences();
  }