/**
  * 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;
  }