@Override
  public void map() {
    for (int d = 2; d < position.length; ++d) min[d] = max[d] = position[d];

    min[0] = target.min(0);
    min[1] = target.min(1);
    max[0] = target.max(0);
    max[1] = target.max(1);
    final FinalInterval sourceInterval = new FinalInterval(min, max);

    final long cr = -target.dimension(0);

    final RandomAccess<B> targetRandomAccess = target.randomAccess(target);
    final RandomAccess<A> sourceRandomAccess = source.randomAccess(sourceInterval);

    for (sourceRandomAccess.setPosition(min),
            targetRandomAccess.setPosition(min[0], 0),
            targetRandomAccess.setPosition(min[1], 1);
        targetRandomAccess.getLongPosition(1) <= max[1];
        sourceRandomAccess.move(cr, 0), targetRandomAccess.move(cr, 0), sourceRandomAccess.fwd(1),
            targetRandomAccess.fwd(1)) {
      for (;
          targetRandomAccess.getLongPosition(0) <= max[0];
          sourceRandomAccess.fwd(0), targetRandomAccess.fwd(0))
        converter.convert(sourceRandomAccess.get(), targetRandomAccess.get());
    }
  }
  private static void adjustForOSEM(
      final HashMap<ViewId, RandomAccessibleInterval<FloatType>> weights,
      final WeightType weightType,
      final double osemspeedup) {
    if (osemspeedup == 1.0) return;

    if (weightType == WeightType.PRECOMPUTED_WEIGHTS
        || weightType == WeightType.WEIGHTS_ONLY
        || weightType == WeightType.LOAD_WEIGHTS) {
      for (final RandomAccessibleInterval<FloatType> w : weights.values()) {
        for (final FloatType f : Views.iterable(w))
          f.set(
              Math.min(
                  1, f.get() * (float) osemspeedup)); // individual contribution never higher than 1
      }
    } else if (weightType == WeightType.NO_WEIGHTS) {
      for (final RandomAccessibleInterval<FloatType> w : weights.values()) {
        final RandomAccess<FloatType> r = w.randomAccess();
        final long[] min = new long[w.numDimensions()];
        w.min(min);
        r.setPosition(min);
        r.get()
            .set(
                Math.min(
                    1,
                    r.get().get()
                        * (float) osemspeedup)); // individual contribution never higher than 1
      }
    } else if (weightType == WeightType.VIRTUAL_WEIGHTS) {
      for (final RandomAccessibleInterval<FloatType> w : weights.values())
        ((NormalizingRandomAccessibleInterval<FloatType>) w).setOSEMspeedup(osemspeedup);
    } else {
      throw new RuntimeException(
          "Weight Type: "
              + weightType.name()
              + " not supported in ProcessForDeconvolution.adjustForOSEM()");
    }
  }
  /**
   * TODO
   *
   * @param cumulativeMinCutoff
   * @param cumulativeMaxCutoff
   * @param state
   * @param setupAssignments
   */
  public static void initBrightness(
      final double cumulativeMinCutoff,
      final double cumulativeMaxCutoff,
      final ViewerState state,
      final SetupAssignments setupAssignments) {
    final Source<?> source = state.getSources().get(state.getCurrentSource()).getSpimSource();
    final int timepoint = state.getCurrentTimepoint();
    if (!source.isPresent(timepoint)) return;
    if (!UnsignedShortType.class.isInstance(source.getType())) return;
    @SuppressWarnings("unchecked")
    final RandomAccessibleInterval<UnsignedShortType> img =
        (RandomAccessibleInterval<UnsignedShortType>)
            source.getSource(timepoint, source.getNumMipmapLevels() - 1);
    final long z = (img.min(2) + img.max(2) + 1) / 2;

    final int numBins = 6535;
    final Histogram1d<UnsignedShortType> histogram =
        new Histogram1d<UnsignedShortType>(
            Views.iterable(Views.hyperSlice(img, 2, z)),
            new Real1dBinMapper<UnsignedShortType>(0, 65535, numBins, false));
    final DiscreteFrequencyDistribution dfd = histogram.dfd();
    final long[] bin = new long[] {0};
    double cumulative = 0;
    int i = 0;
    for (; i < numBins && cumulative < cumulativeMinCutoff; ++i) {
      bin[0] = i;
      cumulative += dfd.relativeFrequency(bin);
    }
    final int min = i * 65535 / numBins;
    for (; i < numBins && cumulative < cumulativeMaxCutoff; ++i) {
      bin[0] = i;
      cumulative += dfd.relativeFrequency(bin);
    }
    final int max = i * 65535 / numBins;
    final MinMaxGroup minmax = setupAssignments.getMinMaxGroups().get(0);
    minmax.getMinBoundedValue().setCurrentValue(min);
    minmax.getMaxBoundedValue().setCurrentValue(max);
  }