/**
   * @param datasets input 2D dataset
   * @return one 2D dataset
   */
  @Override
  public List<Dataset> value(IDataset... datasets) {
    if (datasets.length == 0) return null;

    List<Dataset> result = new ArrayList<Dataset>();

    for (IDataset ids : datasets) {
      Dataset ds = DatasetUtils.convertToDataset(ids);
      // check if input is 2D
      int[] s = ds.getShape();
      if (s.length != 2) return null;

      // find extent of projected dataset
      int[] pos = new int[2];
      int[] start = pshape.clone();
      int[] stop = new int[2];

      qToPixel(qspace.qFromPixelPosition(0, 0), pos);
      adjustBoundingBox(start, stop, pos);
      qToPixel(qspace.qFromPixelPosition(s[0], 0), pos);
      adjustBoundingBox(start, stop, pos);
      qToPixel(qspace.qFromPixelPosition(0, s[1]), pos);
      adjustBoundingBox(start, stop, pos);
      qToPixel(qspace.qFromPixelPosition(s[0], s[1]), pos);
      adjustBoundingBox(start, stop, pos);
      stop[0]++;
      stop[1]++;

      // iterate over bounding box in project dataset
      //     find image point
      //     calculate interpolated value
      //     store running average
      // (could have done this using a slice iterator)
      Vector3d qy = new Vector3d();
      Vector3d q = new Vector3d();
      Vector3d t = new Vector3d();
      double delta, value;
      int i = 0, n;
      for (int y = start[0]; y < stop[0]; y++) {
        qy.scale((y + roff) * cdel, col);
        for (int x = start[1]; x < stop[1]; x++) {
          q.scaleAdd((x + coff) * rdel, row, qy);
          qspace.pixelPosition(q, t);
          n = (int) (count.getElementLongAbs(i) + 1);
          value = image.getElementDoubleAbs(i);
          delta = Maths.interpolate(ds, t.y, t.x) - value;
          image.setObjectAbs(i, value + (delta / n));
          count.setObjectAbs(i, n);
          i++;
        }
      }

      result.add(image);
      result.add(count);
    }
    return result;
  }
  @Override
  protected OperationData process(IDataset input, IMonitor monitor) {

    RectangularROI box = model.getBox();

    Dataset in1 =
        BoxSlicerRodScanUtils.rOIBox(input, monitor, box.getIntLengths(), box.getIntPoint());

    if (g2 == null) g2 = new Polynomial2D(model.getFitPower());
    if ((int) Math.pow(model.getFitPower() + 1, 2) != g2.getNoOfParameters())
      g2 = new Polynomial2D(model.getFitPower());

    Dataset[] fittingBackground =
        BoxSlicerRodScanUtils.LeftRightTopBottomBoxes(
            input, monitor, box.getIntLengths(), box.getIntPoint(), model.getBoundaryBox());

    Dataset offset = DatasetFactory.ones(fittingBackground[2].getShape(), Dataset.FLOAT64);

    Dataset intermediateFitTest = Maths.add(offset, fittingBackground[2]);
    Dataset matrix =
        LinearLeastSquaresServicesForSXRD.polynomial2DLinearLeastSquaresMatrixGenerator(
            model.getFitPower(), fittingBackground[0], fittingBackground[1]);

    DoubleDataset test = (DoubleDataset) LinearAlgebra.solveSVD(matrix, intermediateFitTest);
    double[] params = test.getData();

    DoubleDataset in1Background =
        g2.getOutputValues0(
            params, box.getIntLengths(), model.getBoundaryBox(), model.getFitPower());

    IndexIterator it = in1Background.getIterator();

    while (it.hasNext()) {
      double v = in1Background.getElementDoubleAbs(it.index);
      if (v < 0) in1Background.setObjectAbs(it.index, 0);
    }

    Dataset pBackgroundSubtracted = Maths.subtract(in1, in1Background, null);

    pBackgroundSubtracted.setName("pBackgroundSubtracted");

    IndexIterator it1 = pBackgroundSubtracted.getIterator();

    while (it1.hasNext()) {
      double q = pBackgroundSubtracted.getElementDoubleAbs(it1.index);
      if (q < 0) pBackgroundSubtracted.setObjectAbs(it1.index, 0);
    }

    Dataset output = DatasetUtils.cast(pBackgroundSubtracted, Dataset.FLOAT64);

    output.setName("Region of Interest, polynomial background removed");

    return new OperationData(output);
  }