/* * Makes sure calculation of IJ1 channels is correctly invertible */ @Test public void testRasterization() { final long[][] dimsList = {{1, 1, 1}, {1, 2, 3}, {2, 3, 4}, {5, 4, 3}, {4, 2, 7}}; final AxisType[] axes = {Axes.CHANNEL, SCIFIOAxes.SPECTRA, SCIFIOAxes.FREQUENCY}; for (long[] dims : dimsList) { // setup long numChannels = 1; for (long dim : dims) numChannels *= dim; // test from long index back to long index for (long channel = 0; channel < numChannels; channel++) { long[] channelPositions = new long[dims.length]; LegacyUtils.fillChannelIndices(dims, axes, channel, channelPositions); long ij1Pos = LegacyUtils.calcIJ1ChannelPos(dims, axes, channelPositions); assertEquals(channel, ij1Pos); } // test from long[] index back to long[] index long[] channelPositions1 = new long[dims.length]; long[] channelPositions2 = new long[dims.length]; Extents extents = new Extents(dims); Position pos = extents.createPosition(); while (pos.hasNext()) { pos.fwd(); pos.localize(channelPositions1); long ij1Channel = LegacyUtils.calcIJ1ChannelPos(dims, axes, channelPositions1); LegacyUtils.fillChannelIndices(dims, axes, ij1Channel, channelPositions2); for (int i = 0; i < channelPositions1.length; i++) assertEquals(channelPositions1[i], channelPositions2[i]); } } }
/** * Makes a color {@link Dataset} from an {@link ImagePlus}. Color Datasets have isRgbMerged() * true, channels == 3, and bitsperPixel == 8. Does not populate the data of the returned Dataset. * That is left to other utility methods. Does not set metadata of Dataset. Throws exceptions if * input ImagePlus is not single channel RGB. */ private Dataset makeColorDataset(final ImagePlus imp, final AxisType[] preferredOrder) { final int x = imp.getWidth(); final int y = imp.getHeight(); final int c = imp.getNChannels(); final int z = imp.getNSlices(); final int t = imp.getNFrames(); if (imp.getType() != ImagePlus.COLOR_RGB) { throw new IllegalArgumentException("can't make a color Dataset from a nonRGB ImagePlus"); } if (c != 1) { throw new IllegalArgumentException( "can't make a color Dataset from a multichannel ColorProcessor stack"); } final int[] inputDims = new int[] {x, y, 3, z, t}; final AxisType[] axes = LegacyUtils.orderedAxes(preferredOrder, inputDims); final long[] dims = LegacyUtils.orderedDims(axes, inputDims); final String name = imp.getTitle(); final int bitsPerPixel = 8; final boolean signed = false; final boolean floating = false; final boolean virtual = imp.getStack().isVirtual(); final Dataset ds = datasetService.create(dims, name, axes, bitsPerPixel, signed, floating, virtual); ds.setRGBMerged(true); DatasetUtils.initColorTables(ds); return ds; }
/** * Makes a color {@link ImagePlus} from a color {@link Dataset}. The ImagePlus will have the same * X, Y, Z, & T dimensions. C will be 1. The data values and metadata are not assigned. Throws an * exception if the dataset is not color compatible. */ private ImagePlus makeColorImagePlus(final Dataset ds) { if (!LegacyUtils.isColorCompatible(ds)) { throw new IllegalArgumentException("Dataset is not color compatible"); } final int[] dimIndices = new int[5]; final int[] dimValues = new int[5]; LegacyUtils.getImagePlusDims(ds, dimIndices, dimValues); final int w = dimValues[0]; final int h = dimValues[1]; final int c = dimValues[2] / 3; final int z = dimValues[3]; final int t = dimValues[4]; final ImageStack stack = new ImageStack(w, h, c * z * t); for (int i = 0; i < c * z * t; i++) stack.setPixels(new int[w * h], i + 1); final ImagePlus imp = new ImagePlus(ds.getName(), stack); imp.setDimensions(c, z, t); return imp; }
/** * Assigns the data values of a {@link Dataset} from a paired {@link ImagePlus}. Assumes the * Dataset and ImagePlus have compatible dimensions and that the data planes are not directly * mapped. Gets values via {@link ImageProcessor}::getf(). In cases where there is a narrowing of * data into modern ImageJ types the data is range clamped. Does not change the Dataset's * metadata. */ @Override public void updateDataset(final Dataset ds, final ImagePlus imp) { final RealType<?> type = ds.getType(); final double typeMin = type.getMinValue(); final double typeMax = type.getMaxValue(); final boolean signed16BitData = type instanceof ShortType; final RandomAccess<? extends RealType<?>> accessor = ds.getImgPlus().randomAccess(); final long[] dims = ds.getDims(); final AxisType[] axes = ds.getAxes(); final int xIndex = ds.getAxisIndex(Axes.X); final int yIndex = ds.getAxisIndex(Axes.Y); final int zIndex = ds.getAxisIndex(Axes.Z); final int tIndex = ds.getAxisIndex(Axes.TIME); final int xSize = imp.getWidth(); final int ySize = imp.getHeight(); final int zSize = imp.getNSlices(); final int tSize = imp.getNFrames(); final int cSize = imp.getNChannels(); final ImageStack stack = imp.getStack(); int planeNum = 1; final long[] pos = new long[dims.length]; for (int t = 0; t < tSize; t++) { if (tIndex >= 0) pos[tIndex] = t; for (int z = 0; z < zSize; z++) { if (zIndex >= 0) pos[zIndex] = z; for (int c = 0; c < cSize; c++) { LegacyUtils.fillChannelIndices(dims, axes, c, pos); final ImageProcessor proc = stack.getProcessor(planeNum++); for (int x = 0; x < xSize; x++) { if (xIndex >= 0) pos[xIndex] = x; for (int y = 0; y < ySize; y++) { if (yIndex >= 0) pos[yIndex] = y; accessor.setPosition(pos); double value = proc.getf(x, y); if (signed16BitData) value -= 32768.0; if (value < typeMin) value = typeMin; else if (value > typeMax) value = typeMax; accessor.get().setReal(value); } } } } } ds.update(); }
/** * Creates a {@link ImageDisplay} from an {@link ImagePlus}. Shares planes of data when possible. */ @Override public ImageDisplay createDisplay(final ImagePlus imp) { return createDisplay(imp, LegacyUtils.getPreferredAxisOrder()); }