/** * Constructor * * @param image The intensity image to be labeled * @param scale the minimum distance between maxima of objects. Less technically, this should be * the diameter of the smallest object. * @param sigma1 the standard deviation for the larger smoothing. The difference between sigma1 * and sigma2 should be roughly the width of the desired edge in the DoG image. A larger * difference will obscure small, faint edges. * @param sigma2 the standard deviation for the smaller smoothing. This should be on the order of * the largest insignificant feature in the image. * @param names - an iterator that generates names of type L for the labels. The iterator will * waste the last name taken on the background label. You can use * AllConnectedComponents.getIntegerNames() as your name generator if you don't care about * names. */ public GradientWatershed( Image<T> input, double[] scale, double[] sigma1, double[] sigma2, Iterator<L> names) { this.input = input; this.scale = scale; this.sigma1 = sigma1; this.sigma2 = sigma2; structuringElement = AllConnectedComponents.getStructuringElement(input.getNumDimensions()); this.names = names; labelingFactory = new ImageFactory<LabelingType<L>>(new LabelingType<L>(), input.getContainerFactory()); }
protected ImageFactory<FloatType> getFloatFactory() { if (floatFactory == null) { floatFactory = new ImageFactory<FloatType>(new FloatType(), input.getContainerFactory()); } return floatFactory; }
@Override public boolean process() { floatImage = null; if (output == null) { output = new Labeling<L>(labelingFactory, input.getDimensions(), null); } else { /* * Initialize the output to all background */ LocalizableCursor<LabelingType<L>> c = output.createLocalizableCursor(); List<L> background = c.getType().intern(new ArrayList<L>()); for (LabelingType<L> t : c) { t.setLabeling(background); } c.close(); } /* * Get the smoothed image. */ Image<FloatType> kernel = FourierConvolution.createGaussianKernel(input.getContainerFactory(), scale); FourierConvolution<FloatType, FloatType> convolution = new FourierConvolution<FloatType, FloatType>(getFloatImage(), kernel); if (!convolution.process()) return false; Image<FloatType> smoothed = convolution.getResult(); /* * Find the local maxima and label them individually. */ PickImagePeaks<FloatType> peakPicker = new PickImagePeaks<FloatType>(smoothed); peakPicker.setSuppression(scale); peakPicker.process(); Labeling<L> seeds = output.createNewLabeling(); LocalizableByDimCursor<LabelingType<L>> lc = seeds.createLocalizableByDimCursor(); LocalizableByDimCursor<FloatType> imageCursor = smoothed.createLocalizableByDimCursor(); int[] dimensions = input.getDimensions(); for (int[] peak : peakPicker.getPeakList()) { if (!filterPeak(imageCursor, peak, dimensions, false)) continue; lc.setPosition(peak); lc.getType().setLabel(names.next()); } imageCursor.close(); /* * Find the local minima and label them all the same. */ List<L> background = lc.getType().intern(names.next()); Converter<FloatType, FloatType> invert = new Converter<FloatType, FloatType>() { @Override public void convert(FloatType input, FloatType output) { output.setReal(-input.getRealFloat()); } }; ImageConverter<FloatType, FloatType> invSmoothed = new ImageConverter<FloatType, FloatType>(smoothed, smoothed, invert); invSmoothed.process(); peakPicker = new PickImagePeaks<FloatType>(smoothed); peakPicker.setSuppression(scale); peakPicker.process(); imageCursor = smoothed.createLocalizableByDimCursor(); for (int[] peak : peakPicker.getPeakList()) { if (!filterPeak(imageCursor, peak, dimensions, true)) continue; lc.setPosition(peak); lc.getType().setLabeling(background); } lc.close(); imageCursor.close(); smoothed = null; invSmoothed = null; Image<FloatType> gradientImage = getGradientImage(); if (gradientImage == null) return false; /* * Run the seeded watershed on the image. */ Watershed.seededWatershed(gradientImage, seeds, structuringElement, output); return true; }