/** * Test whether the {@code containing} interval completely contains the {@code contained} * interval. * * <p>TODO: move to {@link Intervals} * * @param containing * @param contained * @return */ public static final boolean contains(final Interval containing, final Interval contained) { assert containing.numDimensions() == contained.numDimensions(); final int n = containing.numDimensions(); for (int d = 0; d < n; ++d) { if (containing.min(d) > contained.min(d) || containing.max(d) < contained.max(d)) return false; } return true; }
/** * Computes a Gaussian convolution with the precision of the type provided on an infinite {@link * RandomAccessible} * * @param sigma - the sigma for the convolution * @param img - the img {@link RandomAccessible} (infinite -> Views.extend( ... ) ) * @param interval - the interval which should be convolved * @param output - the output {@link RandomAccessible} (img and output can be the same) * @param origin - the origin in the output where the result should be placed * @param imgFactory - the {@link ImgFactory} for T which is needed for temporary imgs */ @SuppressWarnings("rawtypes") public static <T extends NumericType<T>> void inNumericType( final double[] sigma, final RandomAccessible<T> img, final Interval interval, final RandomAccessible<T> output, final Localizable origin, final ImgFactory<T> imgFactory) { // find out if it is a NativeType, therefore we get the first value // defined by the // interval in the img - we also need it in this case for the // convolution final long[] tmpCoordinate = new long[img.numDimensions()]; interval.min(tmpCoordinate); final RandomAccess<T> tmp = img.randomAccess(); tmp.setPosition(tmpCoordinate); if (NativeType.class.isInstance(tmp.get())) { // we have to call it in an extra method because we cannot cast to // (NumericType<T> & NativeType<T>) computeInNativeType( sigma, (RandomAccessible) img, interval, (RandomAccessible) output, origin, (ImgFactory) imgFactory, tmp.get()); } else { final GaussGeneral<T> gauss = new GaussGeneral<T>(sigma, img, interval, output, origin, imgFactory, tmp.get()); gauss.call(); } }
/** * Computes a Gaussian convolution with double precision on an infinite {@link RandomAccessible} * * @param sigma - the sigma for the convolution * @param img - the img {@link RandomAccessible} (infinite -> Views.extend( ... ) ) * @param interval - the interval which should be convolved * @param output - the output {@link RandomAccessible} (img and output can be the same) * @param origin - the origin in the output where the result should be placed * @param imgFactory - the {@link ImgFactory} for {@link DoubleType} which is needed for temporary * imgs */ public static <T extends RealType<T>> void inDouble( final double[] sigma, final RandomAccessible<T> img, final Interval interval, final RandomAccessible<T> output, final Localizable origin, final ImgFactory<DoubleType> imgFactory) { // find out if it is a DoubleType, therefore we get the first value // defined by the // interval in the img final long[] tmpCoordinate = new long[img.numDimensions()]; interval.min(tmpCoordinate); final RandomAccess<T> tmp = img.randomAccess(); tmp.setPosition(tmpCoordinate); if (DoubleType.class.isInstance(tmp.get())) { @SuppressWarnings({"rawtypes", "unchecked"}) final RandomAccessible<DoubleType> rIn = (RandomAccessible) img; @SuppressWarnings({"rawtypes", "unchecked"}) final RandomAccessible<DoubleType> rOut = (RandomAccessible) output; new GaussDouble(sigma, rIn, interval, rOut, origin, imgFactory).call(); } else { final RandomAccessible<DoubleType> rIn = new WriteConvertedRandomAccessible<T, DoubleType>( img, new RealDoubleSamplerConverter<T>()); final RandomAccessible<DoubleType> rOut = new WriteConvertedRandomAccessible<T, DoubleType>( output, new RealDoubleSamplerConverter<T>()); new GaussDouble(sigma, rIn, interval, rOut, origin, imgFactory).call(); } }
public static String printInterval(final Interval interval) { String out = "(Interval empty)"; if (interval == null || interval.numDimensions() == 0) return out; out = "[" + interval.min(0); for (int i = 1; i < interval.numDimensions(); i++) out += ", " + interval.min(i); out += "] -> [" + interval.max(0); for (int i = 1; i < interval.numDimensions(); i++) out += ", " + interval.max(i); out += "], dimensions (" + interval.dimension(0); for (int i = 1; i < interval.numDimensions(); i++) out += ", " + interval.dimension(i); out += ")"; return out; }
/** * Create a long[] with the min coordinates of an {@link Interval}. * * <p>Keep in mind that creating arrays wildly is not good practice and consider using the * interval directly. * * @param interval * @return dimensions of the interval as a new long[] */ public static final long[] intervalMin(final Interval interval) { final long[] min = new long[interval.numDimensions()]; interval.min(min); return min; }
/** * Get a "good" initial viewer transform. The viewer transform is chosen such that for the first * source, * * <ul> * <li>the XY plane is aligned with the screen plane, * <li>the <em>z = dim_z / 2</em> slice is shown, * <li>centered and scaled such that the full <em>dim_x</em> by <em>dim_y</em> is visible. * </ul> * * @param viewerWidth width of the viewer display * @param viewerHeight height of the viewer display * @param state the {@link ViewerState} containing at least one source. * @return proposed initial viewer transform. */ public static AffineTransform3D initTransform( final int viewerWidth, final int viewerHeight, final boolean zoomedIn, final ViewerState state) { final int cX = viewerWidth / 2; final int cY = viewerHeight / 2; final Source<?> source = state.getSources().get(state.getCurrentSource()).getSpimSource(); final int timepoint = state.getCurrentTimepoint(); if (!source.isPresent(timepoint)) return new AffineTransform3D(); final AffineTransform3D sourceTransform = new AffineTransform3D(); source.getSourceTransform(timepoint, 0, sourceTransform); final Interval sourceInterval = source.getSource(timepoint, 0); final double sX0 = sourceInterval.min(0); final double sX1 = sourceInterval.max(0); final double sY0 = sourceInterval.min(1); final double sY1 = sourceInterval.max(1); final double sZ0 = sourceInterval.min(2); final double sZ1 = sourceInterval.max(2); final double sX = (sX0 + sX1 + 1) / 2; final double sY = (sY0 + sY1 + 1) / 2; final double sZ = (sZ0 + sZ1 + 1) / 2; final double[][] m = new double[3][4]; // rotation final double[] qSource = new double[4]; final double[] qViewer = new double[4]; Affine3DHelpers.extractApproximateRotationAffine(sourceTransform, qSource, 2); LinAlgHelpers.quaternionInvert(qSource, qViewer); LinAlgHelpers.quaternionToR(qViewer, m); // translation final double[] centerSource = new double[] {sX, sY, sZ}; final double[] centerGlobal = new double[3]; final double[] translation = new double[3]; sourceTransform.apply(centerSource, centerGlobal); LinAlgHelpers.quaternionApply(qViewer, centerGlobal, translation); LinAlgHelpers.scale(translation, -1, translation); LinAlgHelpers.setCol(3, translation, m); final AffineTransform3D viewerTransform = new AffineTransform3D(); viewerTransform.set(m); // scale final double[] pSource = new double[] {sX1 + 0.5, sY1 + 0.5, sZ}; final double[] pGlobal = new double[3]; final double[] pScreen = new double[3]; sourceTransform.apply(pSource, pGlobal); viewerTransform.apply(pGlobal, pScreen); final double scaleX = cX / pScreen[0]; final double scaleY = cY / pScreen[1]; final double scale; if (zoomedIn) scale = Math.max(scaleX, scaleY); else scale = Math.min(scaleX, scaleY); viewerTransform.scale(scale); // window center offset viewerTransform.set(viewerTransform.get(0, 3) + cX, 0, 3); viewerTransform.set(viewerTransform.get(1, 3) + cY, 1, 3); return viewerTransform; }