public void reconstructOffline(ImagePlus imagePlus) throws Exception { ImagePlusDataSink sink = new ImagePlusDataSink(); configure(); init(); for (int i = 0; i < imagePlus.getStackSize(); i++) { backproject(ImageUtil.wrapImageProcessor(imagePlus.getStack().getProcessor(i + 1)), i); } waitForResult(); if (Configuration.getGlobalConfiguration().getUseHounsfieldScaling()) applyHounsfieldScaling(); int[] size = projectionVolume.getSize(); System.out.println(size[0] + " " + size[1] + " " + size[2]); for (int k = 0; k < projectionVolume.getSize()[2]; k++) { FloatProcessor fl = new FloatProcessor(projectionVolume.getSize()[0], projectionVolume.getSize()[1]); for (int j = 0; j < projectionVolume.getSize()[1]; j++) { for (int i = 0; i < projectionVolume.getSize()[0]; i++) { fl.putPixelValue(i, j, projectionVolume.getAtIndex(i, j, k)); } } sink.process(projectionVolume.getSubGrid(k), k); } sink.close(); ImagePlus revan = ImageUtil.wrapGrid3D(sink.getResult(), "Reconstruction of " + imagePlus.getTitle()); revan.setTitle(imagePlus.getTitle() + " reconstructed"); revan.show(); reset(); }
/** Refine segmentation with ADD/SUB regions of interests */ private synchronized void refine() { if (controlPanel.status != ControlJPanel.SEGMENTATED_STATUS) return; if (controlPanel.addJRadioButton.isSelected()) addRoi = imp.getRoi(); else subRoi = imp.getRoi(); if (null != addRoi) { final float alpha = controlPanel.addThreshold.getValue() / 100.0f; final Shape shape = ShapeRoiHelper.getShape(new ShapeRoi(addRoi)); final AffineTransform trans = new AffineTransform(); trans.translate(addRoi.getBounds().getX(), addRoi.getBounds().getY()); final Area area = new Area(shape); area.transform(trans); siox.subpixelRefine(area, SioxSegmentator.ADD_EDGE, alpha, (float[]) confMatrix.getPixels()); } if (null != subRoi) { final float alpha = controlPanel.subThreshold.getValue() / 100.0f; final Shape shape = ShapeRoiHelper.getShape(new ShapeRoi(subRoi)); final AffineTransform trans = new AffineTransform(); trans.translate(subRoi.getBounds().getX(), subRoi.getBounds().getY()); final Area area = new Area(shape); area.transform(trans); siox.subpixelRefine(area, SioxSegmentator.SUB_EDGE, alpha, (float[]) confMatrix.getPixels()); } updateResult(); }
private void raytrace(double energyEV, int numRays) { Grid2D grid = new Grid2D(600, 500); FloatProcessor imp; imp = new FloatProcessor(grid.getWidth(), grid.getHeight()); imp.setPixels(grid.getBuffer()); // SimpleVector startPosition = new SimpleVector(40,grid.getHeight()/2/scale, 0); SimpleVector startPosition = new SimpleVector(0, 0, 0); for (int i = 0; i < numRays; ++i) { followRay(startPosition.clone(), new SimpleVector(1, 0, 0), energyEV, imp, 0, 0); } imp.drawString( grid.getWidth() / scale + "cm", grid.getWidth() / 2 - 20, grid.getHeight() - 10, Color.WHITE); grid.show("Energy: " + energyEV + "eV, Material: " + material.getName()); System.out.println( "Rejection sampling: average misses per draw: " + (float) sumMisses / (float) numDraws); numDraws = 0; sumMisses = 0; }
int[] smooth(int[] a, int n) { FloatProcessor fp = new FloatProcessor(n, 1); for (int i = 0; i < n; i++) fp.putPixelValue(i, 0, a[i]); GaussianBlur gb = new GaussianBlur(); gb.blur1Direction(fp, 2.0, 0.01, true, 0); for (int i = 0; i < n; i++) a[i] = (int) Math.round(fp.getPixelValue(i, 0)); return a; }
float[] smooth(float[] a, int n) { FloatProcessor fp = new FloatProcessor(n, 1); for (int i = 0; i < n; i++) fp.setf(i, 0, a[i]); GaussianBlur gb = new GaussianBlur(); gb.blur1Direction(fp, 2.0, 0.01, true, 0); for (int i = 0; i < n; i++) a[i] = fp.getf(i, 0); return a; }
protected static final FloatProcessor scaleByte(final ByteProcessor bp) { final FloatProcessor fp = new FloatProcessor(bp.getWidth(), bp.getHeight()); final byte[] bytes = (byte[]) bp.getPixels(); final float[] floats = (float[]) fp.getPixels(); for (int i = 0; i < bytes.length; ++i) floats[i] = (bytes[i] & 0xff) / 255.0f; return fp; }
public static double[] getPixels(ImagePlus imp, int[] slices, int[] frames, int[] channels) { ImagePlus subImp = AccessImage.getSubHyperStack(imp, slices, frames, channels); ImageStack imageStack = subImp.getImageStack(); double[] pixels = new double[subImp.getWidth() * subImp.getHeight() * imageStack.getSize()]; for (int i = 0; i < imageStack.getSize(); i++) { switch (subImp.getType()) { case ImagePlus.GRAY8: ByteProcessor byteProcessor = (ByteProcessor) imageStack.getProcessor(i + 1); for (int iX = 0; iX < subImp.getWidth(); iX++) { for (int iY = 0; iY < subImp.getHeight(); iY++) { pixels[i * subImp.getWidth() * subImp.getHeight() + iY * subImp.getWidth() + iX] = (double) byteProcessor.getPixelValue(iX, iY); } } break; case ImagePlus.GRAY16: ShortProcessor shortProcessor = (ShortProcessor) imageStack.getProcessor(i + 1); for (int iX = 0; iX < subImp.getWidth(); iX++) { for (int iY = 0; iY < subImp.getHeight(); iY++) { pixels[i * subImp.getWidth() * subImp.getHeight() + iY * subImp.getWidth() + iX] = (double) shortProcessor.getPixelValue(iX, iY); } } break; case ImagePlus.GRAY32: FloatProcessor floatProcessor = (FloatProcessor) imageStack.getProcessor(i + 1); for (int iX = 0; iX < subImp.getWidth(); iX++) { for (int iY = 0; iY < subImp.getHeight(); iY++) { pixels[i * subImp.getWidth() * subImp.getHeight() + iY * subImp.getWidth() + iX] = (double) floatProcessor.getPixelValue(iX, iY); } } break; case ImagePlus.COLOR_RGB: ColorProcessor colorProcessor = (ColorProcessor) imageStack.getProcessor(i + 1); int nX = subImp.getWidth(); int nY = subImp.getHeight(); byte[] red = new byte[nX * nY]; byte[] green = new byte[nX * nY]; byte[] blue = new byte[nX * nY]; colorProcessor.getRGB(red, green, blue); int r, g, b; for (int j = 0; j < nX * nY; j++) { r = red[j] << 16; g = green[j] << 8; b = blue[j] << 0; pixels[i * nX * nY + j] = (double) (r + g + b); } break; } } return (pixels); }
/** * Creates a new FloatProcessor using the specified FloatProcessor. Set 'cm' to null to use the * default grayscale LUT. */ public SerializableFloatProcessor(FloatProcessor floatProcessor) { floatProcessor = (FloatProcessor) floatProcessor.duplicate(); this.width = floatProcessor.getWidth(); this.height = floatProcessor.getHeight(); this.pixels = (float[]) floatProcessor.getPixels(); this.cm = floatProcessor.getColorModel(); resetRoi(); if (pixels != null) findMinAndMax(); }
/** 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."); }
/** * Retrieve float data of 32 bits images * * @param imp : image to analyze * @return float array with data for each pixel */ public static float[] getFloatData(ImagePlus imp) { float[] imagefloat = null; for (int i = 0; i < imp.getStackSize(); i++) { FloatProcessor fp = (FloatProcessor) imp.getImageStack().getProcessor(i + 1).duplicate(); if (i == 0) imagefloat = (float[]) fp.getPixels(); else imagefloat = (float[]) ArrayUtils.addAll(imagefloat, (float[]) fp.getPixels()); System.out.println("slice : " + (i + 1) + "/" + imp.getStackSize()); } return imagefloat; }
/** * Convert VectorProcessor to an array of {@link FloatProcessor}'s. * * @return this VectorProcessor represented as an array of {@link FloatProcessor}'s * @see #toFloatStack() */ public FloatProcessor[] toFloatProcessors() { final FloatProcessor[] r = new FloatProcessor[numberOfValues]; for (int i = 0; i < numberOfValues; ++i) { final FloatProcessor fp = new FloatProcessor(width, height); final float[] values = (float[]) fp.getPixels(); for (int j = 0; j < values.length; j++) { values[j] = pixels[j][i]; } r[i] = fp; } return r; }
@Override public boolean run(JEXEntry optionalEntry) { if (imageData == null || !imageData.getTypeName().getType().equals(JEXData.IMAGE)) { return false; } // Run the function TreeMap<DimensionMap, String> images = ImageReader.readObjectToImagePathTable(imageData); TreeMap<DimensionMap, String> outputMap = new TreeMap<DimensionMap, String>(); int count = 0; int total = images.size(); for (DimensionMap dim : images.keySet()) { if (this.isCanceled()) { return false; } String path = images.get(dim); // File f = new File(path); // get the image ImagePlus im = new ImagePlus(path); ij.process.ImageProcessor imProc = im.getProcessor(); if (imProc == null) continue; FloatProcessor imp = (FloatProcessor) im.getProcessor().convertToFloat(); // should be a float processor int newWidth = (int) (imp.getWidth() * scale); imp.setInterpolationMethod(ImageProcessor.BILINEAR); imp = (FloatProcessor) imp.resize(newWidth); ImagePlus toSave = FunctionUtility.makeImageToSave(imp, "false", bitDepth); String finalPath = JEXWriter.saveImage(toSave); outputMap.put(dim.copy(), finalPath); Logs.log("Finished processing " + count + " of " + total + ".", 1, this); count++; // Status bar int percentage = (int) (100 * ((double) count / (double) images.size())); JEXStatics.statusBar.setProgressPercentage(percentage); } // Set the outputs output = ImageWriter.makeImageStackFromPaths("temp", outputMap); output.setDataObjectInfo("Stack binned using binning function"); // Return status return true; }
/** * Creates the Euclidian Distance Map of a (binary) byte image. * * @param ip The input image, not modified; must be a ByteProcessor. * @param backgroundValue Pixels in the input with this value are interpreted as background. Note: * for pixel value 255, write either -1 or (byte)255. * @param edgesAreBackground Whether out-of-image pixels are considered background * @return The EDM, containing the distances to the nearest background pixel. Returns null if the * thread is interrupted. */ public FloatProcessor makeFloatEDM( ImageProcessor ip, int backgroundValue, boolean edgesAreBackground) { int width = ip.getWidth(); int height = ip.getHeight(); FloatProcessor fp = new FloatProcessor(width, height); byte[] bPixels = (byte[]) ip.getPixels(); float[] fPixels = (float[]) fp.getPixels(); final int progressInterval = 100; int nProgressUpdates = height / progressInterval; // how often the progress bar is updated when passing once through y // range double progressAddendum = (nProgressUpdates > 0) ? 0.5 / nProgressUpdates : 0; for (int i = 0; i < width * height; i++) if (bPixels[i] != backgroundValue) fPixels[i] = Float.MAX_VALUE; int[][] pointBufs = new int[2][width]; // two buffers for two passes; low short contains x, high short y int yDist = Integer.MAX_VALUE; // this value is used only if edges are not background // pass 1 & 2: increasing y for (int x = 0; x < width; x++) { pointBufs[0][x] = NO_POINT; pointBufs[1][x] = NO_POINT; } for (int y = 0; y < height; y++) { if (edgesAreBackground) yDist = y + 1; // distance to nearest background point (along y) edmLine(bPixels, fPixels, pointBufs, width, y * width, y, backgroundValue, yDist); if (y % progressInterval == 0) { if (Thread.currentThread().isInterrupted()) return null; addProgress(progressAddendum); } } // pass 3 & 4: decreasing y for (int x = 0; x < width; x++) { pointBufs[0][x] = NO_POINT; pointBufs[1][x] = NO_POINT; } for (int y = height - 1; y >= 0; y--) { if (edgesAreBackground) yDist = height - y; edmLine(bPixels, fPixels, pointBufs, width, y * width, y, backgroundValue, yDist); if (y % progressInterval == 0) { if (Thread.currentThread().isInterrupted()) return null; addProgress(progressAddendum); } } fp.sqrt(); return fp; } // public FloatProcessor makeFloatEDM
void SMLblur1Direction( final FloatProcessor ippp, final double sigma, final double accuracy, final boolean xDirection, final int extraLines) { final float[] pixels = (float[]) ippp.getPixels(); final int width = ippp.getWidth(); final int height = ippp.getHeight(); final int length = xDirection ? width : height; // number of points per line (line can be a row or column) final int pointInc = xDirection ? 1 : width; // increment of the pixels array index to the next poin a line final int lineInc = xDirection ? width : 1; // increment of the pixels array index to the next line final int lineFromA = 0 - extraLines; // the first line to process final int lineFrom; if (lineFromA < 0) lineFrom = 0; else lineFrom = lineFromA; final int lineToA = (xDirection ? height : width) + extraLines; // the last line+1 to process final int lineTo; if (lineToA > (xDirection ? height : width)) lineTo = (xDirection ? height : width); else lineTo = lineToA; final int writeFrom = 0; // first point of a line that needs to be written final int writeTo = xDirection ? width : height; final float[][] gaussKernel = lowpassGauss.makeGaussianKernel(sigma, accuracy, length); final int kRadius = gaussKernel[0].length; // Gaussian kernel radius after upscaling final int readFrom = (writeFrom - kRadius < 0) ? 0 : writeFrom - kRadius; // not including broadening by downscale&upscale final int readTo = (writeTo + kRadius > length) ? length : writeTo + kRadius; final int newLength = length; final float[] cache1 = new float[newLength]; // holds data before convolution (after downscaling, if any) int pixel0 = 0; for (int line = lineFrom; line < lineTo; line++, pixel0 += lineInc) { int p = pixel0 + readFrom * pointInc; for (int i = readFrom; i < readTo; i++, p += pointInc) cache1[i] = pixels[p]; SMLconvolveLine( cache1, pixels, gaussKernel, readFrom, readTo, writeFrom, writeTo, pixel0, pointInc); } return; }
/** Generate output image whose type is same as input image. */ private ImagePlus makeOutputImage(ImagePlus imp, FloatProcessor fp, int ptype) { int width = imp.getWidth(); int height = imp.getHeight(); float[] pixels = (float[]) fp.getPixels(); ImageProcessor oip = null; // Create output image consistent w/ type of input image. int size = pixels.length; switch (ptype) { case BYTE_TYPE: oip = imp.getProcessor().createProcessor(width, height); byte[] pixels8 = (byte[]) oip.getPixels(); for (int i = 0; i < size; i++) pixels8[i] = (byte) pixels[i]; break; case SHORT_TYPE: oip = imp.getProcessor().createProcessor(width, height); short[] pixels16 = (short[]) oip.getPixels(); for (int i = 0; i < size; i++) pixels16[i] = (short) pixels[i]; break; case FLOAT_TYPE: oip = new FloatProcessor(width, height, pixels, null); break; } // Adjust for display. // Calling this on non-ByteProcessors ensures image // processor is set up to correctly display image. oip.resetMinAndMax(); // Create new image plus object. Don't use // ImagePlus.createImagePlus here because there may be // attributes of input image that are not appropriate for // projection. return new ImagePlus(makeTitle(), oip); }
// set values in floatEdm to zero if pixel in mask equals 'resetOnThis' private void resetMasked(FloatProcessor floatEdm, ImageProcessor mask, int resetOnThis) { int width = mask.getWidth(); int height = mask.getHeight(); byte[] mPixels = (byte[]) mask.getPixels(); float[] fPixels = (float[]) floatEdm.getPixels(); for (int i = 0; i < width * height; i++) if (mPixels[i] == resetOnThis) fPixels[i] = 0; }
public StandardDeviation(FloatProcessor fp, int num) { result = (float[]) fp.getPixels(); len = result.length; this.num = num; sum = new double[len]; sum2 = new double[len]; }
/** Produce a binary image based on the current confidence matrix */ private void createBinaryMask() { if (null != confMatrix) { final ByteProcessor result = (ByteProcessor) confMatrix.convertToByte(false); result.multiply(255); // Set background color based on the Process > Binary > Options if (!Prefs.blackBackground) result.invert(); new ImagePlus("Mask", result).show(); } }
// overwrite ip with floatEdm converted to bytes private void byteFromFloat(ImageProcessor ip, FloatProcessor floatEdm) { int width = ip.getWidth(); int height = ip.getHeight(); byte[] bPixels = (byte[]) ip.getPixels(); float[] fPixels = (float[]) floatEdm.getPixels(); for (int i = 0; i < width * height; i++) { float v = fPixels[i]; bPixels[i] = v < 255f ? (byte) (v + 0.5) : (byte) 255; } }
protected void copyProjectionViews() throws Exception { FloatProcessor currentProjection; for (int ip = 0; ip < nImages; ip++) { try { Grid2D projection = inputQueue.get(ip); currentProjection = new FloatProcessor( projection.getWidth(), projection.getHeight(), projection.getBuffer(), null); for (int iu = 0; iu <= maxU; iu++) { for (int iv = 0; iv <= maxV; iv++) { // there may be a problem projectionViews.setAtIndex(ip, iu, iv, currentProjection.getf(iu, iv)); } } } catch (Exception e) { System.out.println("An error occured during copying projection views " + ip); } } }
public static ImagePlus asImagePlus( String title, double[] data, int width, int height, int nSlices, int nFrames, int nChannels) { ImageStack imageStack = new ImageStack(width, height); FloatProcessor ip = null; for (int i = 0; i < nSlices * nFrames * nChannels; i++) { ip = new FloatProcessor(width, height); for (int iX = 0; iX < width; iX++) { for (int iY = 0; iY < height; iY++) { ip.putPixelValue(iX, iY, data[i * height * width + iY * width + iX]); } } imageStack.addSlice(ip); } ImagePlus resImp = new ImagePlus(title, imageStack); resImp.setOpenAsHyperStack(true); resImp.setDimensions(nChannels, nSlices, nFrames); return resImp; }
/** Update the result overlay with the current matrix of confidence */ private void updateResult() { imp.killRoi(); roiOverlay.setRoi(null); ImageProcessor cp = confMatrix.convertToRGB(); cp.multiply(1.0 / 255.0); cp.copyBits(ip, 0, 0, Blitter.MULTIPLY); resultOverlay.setImage(cp); imp.changes = true; imp.updateAndDraw(); }
private void followRay( SimpleVector pos, SimpleVector dir, double energyEV, FloatProcessor imp, int scatterCount, double totalDistance) { if (energyEV <= 1 || scatterCount > 20000) { System.out.println("energy low, times scattered: " + scatterCount); return; } // follow ray until next interaction point SimpleVector oldPos = pos.clone(); double dist = sampler.getDistanceUntilNextInteractionCm(material, energyEV); pos.add(dir.multipliedBy(dist)); pathlengths.add(dist); // draw the entire path // imp.drawLine((int)(scale*oldPos.getElement(0)), (int)(scale*oldPos.getElement(1)), // (int)(scale*pos.getElement(0)), (int)(scale*pos.getElement(1))); // draw interaction points only imp.drawDot((int) (scale * pos.getElement(0)), (int) (scale * pos.getElement(1))); // choose compton or photoelectric effect double photo = material.getAttenuation(energyEV / 1000, AttenuationType.PHOTOELECTRIC_ABSORPTION); double compton = material.getAttenuation(energyEV / 1000, AttenuationType.INCOHERENT_ATTENUATION); if (sampler.random() * (photo + compton) <= photo) { // photoelectric absorption energyEV = 0; // System.out.println("absorbed after " + scatterCount + " collisions"); xs.add(pos.getElement(0)); ys.add(pos.getElement(1)); zs.add(pos.getElement(2)); return; } else { // compton scattering energyEV = sampler.sampleComptonScattering(energyEV, dir); // send new ray followRay(pos, dir, energyEV, imp, scatterCount + 1, totalDistance + dist); } }
/** * Calculates a 16-bit grayscale Euclidean Distance Map for a binary 8-bit image. Each foreground * (nonzero) pixel in the binary image is assigned a value equal to its distance from the nearest * background (zero) pixel, multiplied by EDM.ONE. For compatibility with previous versions of * ImageJ only. */ public ShortProcessor make16bitEDM(ImageProcessor ip) { FloatProcessor floatEdm = makeFloatEDM(ip, 0, false); floatEdm.setMinAndMax(0, 65535. / ONE); return (ShortProcessor) floatEdm.convertToShort(true); }
public static ImagePlus subtract(ImagePlus a, ImagePlus b) { boolean silent = (IJ.getInstance() == null); int nX = a.getWidth(); int nY = a.getHeight(); int nSlices = a.getNSlices(); int nFrames = a.getNFrames(); int nChannels = a.getNChannels(); if ((nX != b.getWidth()) || (nY != b.getHeight()) || (nSlices != b.getNSlices()) || (nFrames != b.getNFrames()) || (nChannels != b.getNChannels())) { if (silent) { System.out.println("Subtract: image dimensions do not match, return nothing."); } else { IJ.showMessage("Subtract: image dimensions do not match, return nothing."); } } ImageStack resIms = new ImageStack(nX, nY); FloatProcessor fp; ImageProcessor ip1, ip2; int total = nSlices * nFrames * nChannels; double prog = 0; if (silent) { System.out.println("SUBSTRACTING BACKGROUND"); } else { IJ.showStatus("SUBSTRACTING BACKGROUND"); } for (int i = 0; i < nChannels; i++) { for (int j = 0; j < nFrames; j++) { for (int k = 0; k < nSlices; k++) { if (silent) { FNTDprogress.updateProgress(prog / total); } else { IJ.showProgress(prog / total); } prog++; a.setPosition(i + 1, k + 1, j + 1); b.setPosition(i + 1, k + 1, j + 1); ip1 = a.getProcessor(); ip2 = b.getProcessor(); fp = new FloatProcessor(nX, nY); for (int m = 0; m < nX; m++) { for (int n = 0; n < nY; n++) { fp.putPixelValue(m, n, ip1.getPixelValue(m, n) - ip2.getPixelValue(m, n)); } } resIms.addSlice(fp); } } } FNTDprogress.updateProgress(1); System.out.println(""); ImagePlus resImp = new ImagePlus("Result of" + a.getTitle() + "-" + b.getTitle(), resIms); if (resIms.getSize() > 1) { resImp = HyperStackConverter.toHyperStack( resImp, nChannels, nSlices, nFrames, "xyztc", "grayscale"); } return (resImp); }
@Override public Grid2D applyToolToImage(Grid2D imageProcessor) { FloatProcessor imp = new FloatProcessor(imageProcessor.getWidth(), imageProcessor.getHeight()); imp.setPixels(imageProcessor.getBuffer()); if (!initBead) initializeBead(); ImageProcessor imp1 = imp.duplicate(); // original double[][] beadMean3D = config.getBeadMeanPosition3D(); // [beadNo][x,y,z] double[] uv = new double[1]; SimpleMatrix pMatrix = config.getGeometry().getProjectionMatrix(imageIndex).computeP(); // [projection #][bead #][u, v, state[0: initial, 1: registered, 2: updated by hough searching]] double[][][] beadPosition2D = config.getBeadPosition2D(); int noBeadRegistered = 0; double[][] xy1 = new double[WeightBearingBeadPositionBuilder.beadNo][2]; // original double[][] xy2 = new double[WeightBearingBeadPositionBuilder.beadNo] [2]; // warped (mapped to the mean), control points, reference double[][] xy1_hat = new double[WeightBearingBeadPositionBuilder.beadNo][2]; // original double[][] xy2_hat = new double[WeightBearingBeadPositionBuilder.beadNo][2]; // original // double distanceReferenceToCurrentBead = 0; for (int i = WeightBearingBeadPositionBuilder.currentBeadNo; i >= 0; i--) { if (beadMean3D[i][0] != 0 || beadMean3D[i][1] != 0 || beadMean3D[i][2] != 0) { // assume bead 3d is registered. uv = compute2DCoordinates(beadMean3D[i], pMatrix); // find bead location if registered by txt: state 1 if (beadPosition2D[imageIndex][i][2] == 1) { noBeadRegistered++; if (isDisplay) { imp1.setValue(2); imp1.drawLine( (int) Math.round(beadPosition2D[imageIndex][i][0] - 10), (int) Math.round(beadPosition2D[imageIndex][i][1] - 10), (int) Math.round(beadPosition2D[imageIndex][i][0] + 10), (int) Math.round(beadPosition2D[imageIndex][i][1] + 10)); imp1.drawLine( (int) Math.round(beadPosition2D[imageIndex][i][0] - 10), (int) Math.round(beadPosition2D[imageIndex][i][1] + 10), (int) Math.round(beadPosition2D[imageIndex][i][0] + 10), (int) Math.round(beadPosition2D[imageIndex][i][1] - 10)); imp1.drawString( "Bead " + i + " (state:" + (int) beadPosition2D[imageIndex][i][2] + ")", (int) beadPosition2D[imageIndex][i][0], (int) beadPosition2D[imageIndex][i][1] - 10); } xy1[noBeadRegistered - 1][0] = beadPosition2D[imageIndex][i][0]; xy1[noBeadRegistered - 1][1] = beadPosition2D[imageIndex][i][1]; xy2[noBeadRegistered - 1][0] = uv[0]; xy2[noBeadRegistered - 1][1] = uv[1]; } else if (imageIndex != 0 && imageIndex != config.getGeometry().getNumProjectionMatrices() - 1) { if (beadPosition2D[imageIndex - 1][i][2] == 1 && beadPosition2D[imageIndex + 1][i][2] == 1) { noBeadRegistered++; double xMean = (beadPosition2D[imageIndex - 1][i][0] + beadPosition2D[imageIndex - 1][i][0]) / 2; double yMean = (beadPosition2D[imageIndex + 1][i][1] + beadPosition2D[imageIndex + 1][i][1]) / 2; if (isDisplay) { imp1.setValue(2); imp1.drawLine( (int) Math.round(xMean - 10), (int) Math.round(yMean - 10), (int) Math.round(xMean + 10), (int) Math.round(yMean + 10)); imp1.drawLine( (int) Math.round(xMean - 10), (int) Math.round(yMean + 10), (int) Math.round(xMean + 10), (int) Math.round(yMean - 10)); imp1.drawString("Bead " + i + " (state:" + "M)", (int) xMean, (int) yMean - 10); } xy1[noBeadRegistered - 1][0] = xMean; xy1[noBeadRegistered - 1][1] = yMean; xy2[noBeadRegistered - 1][0] = uv[0]; xy2[noBeadRegistered - 1][1] = uv[1]; } } // mean projected bead // imp1.drawLine((int) Math.round(uv[0]-10), (int) Math.round(uv[1]), (int) // Math.round(uv[0]+10), (int) Math.round(uv[1])); // imp1.drawLine((int) Math.round(uv[0]), (int) Math.round(uv[1]-10), (int) // Math.round(uv[0]), (int) Math.round(uv[1]+10)); } } if (isDisplay) { for (int x = 0; x < config.getGeometry().getDetectorWidth(); x += 50) imp1.drawLine(x, 0, x, config.getGeometry().getDetectorHeight()); for (int y = 0; y < config.getGeometry().getDetectorHeight(); y += 50) imp1.drawLine(0, y, config.getGeometry().getDetectorWidth(), y); } if (isCornerIncluded) { xy1[noBeadRegistered + 0][0] = 0; xy1[noBeadRegistered + 0][1] = 0; xy2[noBeadRegistered + 0][0] = 0; xy2[noBeadRegistered + 0][1] = 0; xy1[noBeadRegistered + 1][0] = 0; xy1[noBeadRegistered + 1][1] = config.getGeometry().getDetectorHeight(); xy2[noBeadRegistered + 1][0] = 0; xy2[noBeadRegistered + 1][1] = config.getGeometry().getDetectorHeight(); xy1[noBeadRegistered + 2][0] = config.getGeometry().getDetectorWidth(); xy1[noBeadRegistered + 2][1] = 0; xy2[noBeadRegistered + 2][0] = config.getGeometry().getDetectorWidth(); xy2[noBeadRegistered + 2][1] = 0; xy1[noBeadRegistered + 3][0] = config.getGeometry().getDetectorWidth(); xy1[noBeadRegistered + 3][1] = config.getGeometry().getDetectorHeight(); xy2[noBeadRegistered + 3][0] = config.getGeometry().getDetectorWidth(); xy2[noBeadRegistered + 3][1] = config.getGeometry().getDetectorHeight(); noBeadRegistered = noBeadRegistered + 4; } boolean fScaling = true; double minX = Double.MAX_VALUE; double maxX = 0; double minY = Double.MAX_VALUE; double maxY = 0; double c = 0; if (fScaling) { // ----- scaling to reduce condition # of A matrix for (int i = 0; i < noBeadRegistered; i++) { minX = Math.min(minX, xy1[i][0]); maxX = Math.max(maxX, xy1[i][0]); minY = Math.min(minY, xy1[i][1]); maxY = Math.max(maxY, xy1[i][1]); } c = Math.max(maxX - minX, maxY - minY); for (int i = 0; i < noBeadRegistered; i++) { xy1_hat[i][0] = (xy1[i][0] - minX) / c; xy1_hat[i][1] = (xy1[i][1] - minY) / c; xy2_hat[i][0] = (xy2[i][0] - minX) / c; xy2_hat[i][1] = (xy2[i][1] - minY) / c; } } else { xy1_hat = xy1; xy2_hat = xy2; } ImageProcessor imp2 = imp1.duplicate(); // warped /* * A*x = b * Matrix A = (n + 3) * (n + 3); * n (noBeadRegistered + 4): # of control points + 4 corner points (assume corner points are static) */ int n = noBeadRegistered + 3; SimpleMatrix A = new SimpleMatrix(n, n); SimpleVector x_x = new SimpleVector(n); SimpleVector x_y = new SimpleVector(n); SimpleVector b_x = new SimpleVector(n); SimpleVector b_y = new SimpleVector(n); double rij = 0; double valA = 0; double valb_x = 0; double valb_y = 0; // Matrix L formation // alpha: mean of distances between control points' xy-projections) is a constant only present // on the diagonal of K // lambda: TPS smoothing regularization coefficient double alpha = 0.0; double lambda = 1.6; // 1.6 for (int i = 0; i < noBeadRegistered; i++) { // i= # of row for (int j = i; j < noBeadRegistered; j++) { // j= # of column alpha += Math.sqrt( Math.pow(xy2_hat[i][0] - xy2_hat[j][0], 2) + Math.pow(xy2_hat[i][1] - xy2_hat[j][1], 2)); } } alpha = alpha / Math.pow(noBeadRegistered, 2); for (int i = 0; i < n; i++) { // i= # of row for (int j = i; j < n; j++) { // j= # of column if (i < 3 && j < 3) valA = 0; else if (i >= 3 && j >= 3 && i == j) { valA = Math.pow(alpha, 2) * lambda; // valA = lambda; if (imageIndex < 10) System.out.println("Regularization = " + valA + ", lambda= " + lambda); } else if (i == 0 && j >= 0) valA = 1; else if (i == 1 && j >= 3) valA = xy1_hat[j - 3][0]; else if (i == 2 && j >= 3) valA = xy1_hat[j - 3][1]; else { rij = Math.pow(xy1_hat[j - 3][0] - xy1_hat[i - 3][0], 2) + Math.pow(xy1_hat[j - 3][1] - xy1_hat[i - 3][1], 2); if (rij == 0) valA = 0; else valA = rij * Math.log(rij); } A.setElementValue(i, j, valA); A.setElementValue(j, i, valA); } if (i < 3) { valb_x = 0; valb_y = 0; } else { // valb_x = xy2_hat[i-3][0]-xy1_hat[i-3][0]; // valb_y = xy2_hat[i-3][1]-xy1_hat[i-3][1]; valb_x = xy2[i - 3][0] - xy1[i - 3][0]; valb_y = xy2[i - 3][1] - xy1[i - 3][1]; // if (imageIndex > 150 && imageIndex < 170) // System.out.println("Idx" + imageIndex + ",Elevation" + (i-3) + ": " + valb_x + "---" // + valb_y); } b_x.setElementValue(i, valb_x); b_y.setElementValue(i, valb_y); } // System.out.println("A condition number=" + A.conditionNumber(MatrixNormType.MAT_NORM_L1)); // System.out.println("A condition number=" + A.conditionNumber(MatrixNormType.MAT_NORM_LINF)); x_x = Solvers.solveLinearSysytemOfEquations(A, b_x); x_y = Solvers.solveLinearSysytemOfEquations(A, b_y); if (fScaling) { // ----- pixel space coefficients a, b scaling back double tmpA0 = x_x.getElement(0) - x_x.getElement(1) * (minX / c) - x_x.getElement(2) * (minY / c); for (int j = 0; j < noBeadRegistered; j++) { tmpA0 -= Math.log(c) * 2 * x_x.getElement(j + 3) * (Math.pow(xy1_hat[j][0], 2) + Math.pow(xy1_hat[j][1], 2)); } x_x.setElementValue(0, tmpA0); tmpA0 = x_y.getElement(0) - x_y.getElement(1) * (minX / c) - x_y.getElement(2) * (minY / c); for (int j = 0; j < noBeadRegistered; j++) { tmpA0 -= Math.log(c) * 2 * x_y.getElement(j + 3) * (Math.pow(xy1_hat[j][0], 2) + Math.pow(xy1_hat[j][1], 2)); } x_y.setElementValue(0, tmpA0); x_x.setElementValue(1, x_x.getElement(1) / c); x_y.setElementValue(1, x_y.getElement(1) / c); x_x.setElementValue(2, x_x.getElement(2) / c); x_y.setElementValue(2, x_y.getElement(2) / c); for (int i = 3; i < n; i++) { x_x.setElementValue(i, x_x.getElement(i) / Math.pow(c, 2)); x_y.setElementValue(i, x_y.getElement(i) / Math.pow(c, 2)); } // ----- pixel space coefficients a, b scaling back end } double devU = 0; double devV = 0; // Do warping // if (imageIndex == 0) { for (int y = 0; y < config.getGeometry().getDetectorHeight(); y++) { // for (int y=252; y<253; y++) { for (int x = 0; x < config.getGeometry().getDetectorWidth(); x++) { // for (int x=606; x<607; x++) { devU = x_x.getElement(0) + x_x.getElement(1) * x + x_x.getElement(2) * y; devV = x_y.getElement(0) + x_y.getElement(1) * x + x_y.getElement(2) * y; for (int i = 0; i < noBeadRegistered; i++) { rij = Math.pow(xy1[i][0] - x, 2) + Math.pow(xy1[i][1] - y, 2); if (rij > 0) { devU += x_x.getElement(i + 3) * rij * Math.log(rij); devV += x_y.getElement(i + 3) * rij * Math.log(rij); } } // devU = 0; // devV = 0; imp2.setf(x, y, (float) imp1.getInterpolatedValue(x - devU, y - devV)); // System.out.println("x, y=" + x + ", " + y + "\t" + devU + ", " + devV); // maxDevU = Math.max(maxDevU, devU); // maxDevV = Math.max(maxDevV, devV); } } // Error estimate after transformation // for (int i=0; i<= WeightBearingBeadPositionBuilder.currentBeadNo; i++){ // // if (beadMean3D[i][0] != 0 || beadMean3D[i][1] != 0 || beadMean3D[i][2] != 0){ // assume // bead 3d is registered. // // // find bead location if registered by txt: state 1 // if (beadPosition2D[imageIndex][i][2] == 1){ // // // Projected Reference // uv = compute2DCoordinates(beadMean3D[i], pMatrix); // double x = uv[0]; // double y = uv[1]; // // bead detected position in 2d // // Transform to 2D coordinates, time variant position // //beadPosition2D[imageIndex][i][0]; // //beadPosition2D[imageIndex][i][1]; // // devU = x_x.getElement(0) + x_x.getElement(1)*x + x_x.getElement(2)*y; // devV = x_y.getElement(0) + x_y.getElement(1)*x + x_y.getElement(2)*y; // for (int j=0; j<noBeadRegistered; j++){ // rij = Math.pow(xy1[j][0]-x, 2) + Math.pow(xy1[j][1]-y, 2); // if (rij > 0) { // devU += x_x.getElement(j+3)*rij*Math.log(rij); // devV += x_y.getElement(j+3)*rij*Math.log(rij); // } // } // // distanceReferenceToCurrentBead += // Math.sqrt(Math.pow(uv[0]-(beadPosition2D[imageIndex][i][0]+devU), // 2)+Math.pow(uv[1]-(beadPosition2D[imageIndex][i][1]+devV), 2)); // // } // } // } // System.out.println("Euclidean distance\t" + imageIndex + "\t" + // distanceReferenceToCurrentBead/noBeadRegistered); // } if (isDisplay) { for (int i = WeightBearingBeadPositionBuilder.currentBeadNo; i >= 0; i--) { if (beadMean3D[i][0] != 0 || beadMean3D[i][1] != 0 || beadMean3D[i][2] != 0) { // assume bead 3d is registered. uv = compute2DCoordinates(beadMean3D[i], pMatrix); imp2.setValue(2); // mean projected bead imp2.drawLine( (int) Math.round(uv[0] - 10), (int) Math.round(uv[1]), (int) Math.round(uv[0] + 10), (int) Math.round(uv[1])); imp2.drawLine( (int) Math.round(uv[0]), (int) Math.round(uv[1] - 10), (int) Math.round(uv[0]), (int) Math.round(uv[1] + 10)); } } } Grid2D result = new Grid2D((float[]) imp2.getPixels(), imp2.getWidth(), imp2.getHeight()); return result; }
/** * Create ImagePlusExtended object from primary array (byte, short ....) * * @param title : title of the image * @param object : array * @param showImage : display image if true * @return ImagePlusExtended */ public static ImagePlusExtended createImage(String title, Object object, boolean showImage) { ImagePlusExtended imp = null; int i = 0; if (object instanceof byte[][]) { byte[][] is = (byte[][]) object; int height = is.length; int width = is[0].length; ByteProcessor byteprocessor = new ByteProcessor(width, height); byte[] bp = (byte[]) byteprocessor.getPixels(); int h = 0; while (h < height) { int w = 0; while (w < width) { bp[i] = is[h][w]; w++; i++; } i = ++h * width; } imp = new ImagePlusExtended(title, byteprocessor); } else if (object instanceof short[][]) { short[][] is = (short[][]) object; int height = is.length; int width = is[0].length; ShortProcessor shortprocessor = new ShortProcessor(width, height); short[] sp = (short[]) shortprocessor.getPixels(); int h = 0; while (h < height) { int w = 0; while (w < width) { sp[i] = is[h][w]; w++; i++; } i = ++h * width; } imp = new ImagePlusExtended(title, shortprocessor); } else if (object instanceof int[][]) { int[][] is = (int[][]) object; int height = is.length; int width = is[0].length; ShortProcessor shortprocessor = new ShortProcessor(width, height); short[] sp = (short[]) shortprocessor.getPixels(); int h = 0; while (h < height) { int w = 0; while (w < width) { sp[i] = (short) is[h][w]; w++; i++; } i = ++h * width; } imp = new ImagePlusExtended(title, shortprocessor); } else if (object instanceof float[][]) { float[][] fs = (float[][]) object; int height = fs.length; int width = fs[0].length; FloatProcessor floatprocessor = new FloatProcessor(width, height); float[] fp = (float[]) floatprocessor.getPixels(); int h = 0; while (h < height) { int w = 0; while (w < width) { fp[i] = fs[h][w]; w++; i++; } i = ++h * width; } floatprocessor.resetMinAndMax(); imp = new ImagePlusExtended(title, floatprocessor); } else if (object instanceof double[][]) { double[][] ds = (double[][]) object; int height = ds.length; int width = ds[0].length; FloatProcessor floatprocessor = new FloatProcessor(width, height); float[] fp = (float[]) floatprocessor.getPixels(); int h = 0; while (h < height) { int w = 0; while (w < width) { fp[i] = (float) ds[h][w]; w++; i++; } i = ++h * width; } floatprocessor.resetMinAndMax(); imp = new ImagePlusExtended(title, floatprocessor); } else if (object instanceof byte[][][]) { byte[][][] is = (byte[][][]) object; int height = is.length; int width = is[0].length; int stackSize = is[0][0].length; ImageStack imagestack = new ImageStack(width, height); for (int sz = 0; sz < stackSize; sz++) { ByteProcessor byteprocessor = new ByteProcessor(width, height); byte[] bp = (byte[]) byteprocessor.getPixels(); i = 0; int h = 0; while (h < height) { int w = 0; while (w < width) { bp[i] = is[h][w][sz]; w++; i++; } i = ++h * width; } imagestack.addSlice("", byteprocessor); } imp = new ImagePlusExtended(title, imagestack); } else if (object instanceof short[][][]) { short[][][] is = (short[][][]) object; int height = is.length; int width = is[0].length; int stackSize = is[0][0].length; ImageStack imagestack = new ImageStack(width, height); for (int sz = 0; sz < stackSize; sz++) { ShortProcessor shortprocessor = new ShortProcessor(width, height); short[] sp = (short[]) shortprocessor.getPixels(); i = 0; int h = 0; while (h < height) { int w = 0; while (w < width) { sp[i] = is[h][w][sz]; w++; i++; } i = ++h * width; } imagestack.addSlice("", shortprocessor); } imp = new ImagePlusExtended(title, imagestack); } else if (object instanceof int[][][]) { int[][][] is = (int[][][]) object; int height = is.length; int width = is[0].length; int stackSize = is[0][0].length; ImageStack imagestack = new ImageStack(width, height); for (int sz = 0; sz < stackSize; sz++) { ShortProcessor shortprocessor = new ShortProcessor(width, height); short[] sp = (short[]) shortprocessor.getPixels(); i = 0; int h = 0; while (h < height) { int w = 0; while (w < width) { sp[i] = (short) is[h][w][sz]; w++; i++; } i = ++h * width; } if (sz == 0) shortprocessor.resetMinAndMax(); imagestack.addSlice("", shortprocessor); } imp = new ImagePlusExtended(title, imagestack); } else if (object instanceof float[][][]) { float[][][] fs = (float[][][]) object; int height = fs.length; int width = fs[0].length; int stackSize = fs[0][0].length; ImageStack imagestack = new ImageStack(width, height); for (int sz = 0; sz < stackSize; sz++) { FloatProcessor floatprocessor = new FloatProcessor(width, height); float[] fp = (float[]) floatprocessor.getPixels(); i = 0; int h = 0; while (h < height) { int w = 0; while (w < width) { fp[i] = fs[h][w][sz]; w++; i++; } i = ++h * width; } if (sz == 0) floatprocessor.resetMinAndMax(); imagestack.addSlice("", floatprocessor); } imp = new ImagePlusExtended(title, imagestack); } else if (object instanceof double[][][]) { double[][][] ds = (double[][][]) object; int height = ds.length; int width = ds[0].length; int stackSize = ds[0][0].length; ImageStack imagestack = new ImageStack(width, height); for (int sz = 0; sz < stackSize; sz++) { FloatProcessor floatprocessor = new FloatProcessor(width, height); float[] fp = (float[]) floatprocessor.getPixels(); i = 0; int h = 0; while (h < height) { int w = 0; while (w < width) { fp[i] = (float) ds[h][w][sz]; w++; i++; } i = ++h * width; } if (sz == 0) floatprocessor.resetMinAndMax(); imagestack.addSlice("", floatprocessor); } imp = new ImagePlusExtended(title, imagestack); } else { System.out.println("MIJ Error message: Unknow type of images or volumes."); return null; } if (showImage) { imp.show(); imp.updateAndDraw(); } return imp; }
/** * Returns saturation corrected version of the input image. A simple, one-parametric * exponential-saturation function with characteristic saturation rate is used (see Greilich et * al., 2013; Klimpki et al., 2016) * * @param img Input image * @param dwell_time Pixel dwell time, unit has to match saturation_rate * @param saturation_rate Characteristic saturation rate, unit has to match dwell_time * @return */ public static ImagePlus saturationCorrection( ImagePlus img, double dwell_time, double saturation_rate) { boolean silent = (IJ.getInstance() == null); int nX = img.getWidth(); int nY = img.getHeight(); int nSlices = img.getNSlices(); int nFrames = img.getNFrames(); int nChannels = img.getNChannels(); ImageStack resIms = new ImageStack(nX, nY); FloatProcessor fp; ImageProcessor ip1; int total = nSlices * nFrames * nChannels; double prog = 0; if (silent) { System.out.println("SATURATION CORRECTION"); } else { IJ.showStatus("SATURATION CORRECTION"); } for (int i = 0; i < nChannels; i++) { for (int j = 0; j < nFrames; j++) { for (int k = 0; k < nSlices; k++) { if (silent) { FNTDprogress.updateProgress(prog / total); } else { IJ.showProgress(prog / total); } prog++; img.setPosition(i + 1, k + 1, j + 1); ip1 = img.getProcessor(); fp = new FloatProcessor(nX, nY); double count_rate; for (int m = 0; m < nX; m++) { for (int n = 0; n < nY; n++) { count_rate = ip1.getPixelValue(m, n); count_rate = 1.0 - count_rate / (dwell_time * saturation_rate); count_rate = -1.0 * saturation_rate * dwell_time * log(count_rate); fp.putPixelValue(m, n, count_rate); } } resIms.addSlice(fp); } } } FNTDprogress.updateProgress(1); System.out.println(""); ImagePlus resImp = new ImagePlus(img.getTitle() + " (sat. corrected)", resIms); if (resIms.getSize() > 1) { resImp = HyperStackConverter.toHyperStack( resImp, nChannels, nSlices, nFrames, "xyztc", "grayscale"); } return (resImp); }
/** * Computes the geodesic distance function for each pixel in mask, using the given mask. Mask and * marker should be ImageProcessor the same size and containing float values. The function returns * a new Float processor the same size as the input, with values greater or equal to zero. */ @Override public FloatProcessor geodesicDistanceMap(ImageProcessor marker, ImageProcessor mask) { // size of image width = mask.getWidth(); height = mask.getHeight(); // update mask this.maskProc = mask; // create new empty image, and fill it with black FloatProcessor result = new FloatProcessor(width, height); result.setValue(0); result.fill(); // initialize empty image with either 0 (foreground) or Inf (background) array = result.getFloatArray(); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { int val = marker.get(i, j) & 0x00ff; array[i][j] = val == 0 ? backgroundValue : 0; } } int iter = 0; do { modif = false; // forward iteration IJ.showStatus("Forward iteration " + iter); forwardIteration(); // backward iteration IJ.showStatus("Backward iteration " + iter); backwardIteration(); // Iterate while pixels have been modified iter++; } while (modif); // Normalize values by the first weight if (this.normalizeMap) { for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { array[i][j] /= this.weights[0]; } } } // Compute max value within the mask float maxVal = 0; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { if (maskProc.getPixel(i, j) != 0) maxVal = Math.max(maxVal, array[i][j]); } } // update and return resulting Image processor result.setFloatArray(array); result.setMinAndMax(0, maxVal); // Forces the display to non-inverted LUT if (result.isInvertedLut()) result.invertLut(); return result; }
/** * Returns image in units of adjusted count-rate (Klimpki et al., 2016), i.e. compensated for * laser power and dwell time. If requested, non-linearities in laser-power compensation are * considered. * * @param img Input image * @param dwell_time Pixel dwell time, unit will match rate (i.e. us --> MHz) * @param laser_power Percentage laser power, * @param laser_exponent Exponent of laser-power compensation non-linearity, referred to 10% * percentage laser power. Equals 0.0 for perfect linearity * @return */ public static ImagePlus getAdjustedCountrateImage( ImagePlus img, double dwell_time, double laser_power, double laser_exponent) { boolean silent = (IJ.getInstance() == null); int nX = img.getWidth(); int nY = img.getHeight(); int nSlices = img.getNSlices(); int nFrames = img.getNFrames(); int nChannels = img.getNChannels(); ImageStack resIms = new ImageStack(nX, nY); FloatProcessor fp; ImageProcessor ip1; int total = nSlices * nFrames * nChannels; double prog = 0; if (silent) { System.out.println("DWELL-TIME/LASER-POWER COMPENSATION"); } else { IJ.showStatus("DWELL-TIME/LASER-POWER COMPENSATION"); } for (int i = 0; i < nChannels; i++) { for (int j = 0; j < nFrames; j++) { for (int k = 0; k < nSlices; k++) { if (silent) { FNTDprogress.updateProgress(prog / total); } else { IJ.showProgress(prog / total); } prog++; img.setPosition(i + 1, k + 1, j + 1); ip1 = img.getProcessor(); fp = new FloatProcessor(nX, nY); double laser_factor = Math.pow(laser_power / 0.10, laser_exponent); for (int m = 0; m < nX; m++) { for (int n = 0; n < nY; n++) { fp.putPixelValue( m, n, ip1.getPixelValue(m, n) * laser_factor / (laser_power * dwell_time)); } } resIms.addSlice(fp); } } } FNTDprogress.updateProgress(1); System.out.println(""); ImagePlus resImp = new ImagePlus(img.getTitle() + " (adj. count-rate)", resIms); if (resIms.getSize() > 1) { resImp = HyperStackConverter.toHyperStack( resImp, nChannels, nSlices, nFrames, "xyztc", "grayscale"); } return (resImp); }