    001/*-
    002 *******************************************************************************
    003 * Copyright (c) 2011, 2016 Diamond Light Source Ltd.
    004 * All rights reserved. This program and the accompanying materials
    005 * are made available under the terms of the Eclipse Public License v1.0
    006 * which accompanies this distribution, and is available at
    007 * http://www.eclipse.org/legal/epl-v10.html
    008 *
    009 * Contributors:
    010 *    Peter Chang - initial API and implementation and/or initial documentation
    011 *******************************************************************************/
    012
    013package org.eclipse.january.dataset;
    014
    015import java.util.Arrays;
    016import java.util.Collection;
    017import java.util.Iterator;
    018import java.util.List;
    019
    020/**
    021 * Statistics of data set lists. Used for image processing.
    022 */
    023public class CollectionStats {
    024
    025        private static interface StatFunction {
    026                double evaluate(Dataset set);
    027        }
    028
    029        /**
    030         * Used to get a mean image from a set of images for instance.
    031         *
    032         * @param sets datasets
    033         * @return mean dataset of the same shape as those passed in
    034         * @throws Exception when datasets have different shapes
    035         */
    036        public static Dataset mean(final List<IDataset> sets) throws Exception {
    037
    038                return process(sets, new StatFunction() {
    039                        @Override
    040                        public double evaluate(Dataset set) {
    041                                return (Double)set.mean();
    042                        }
    043                });
    044        }
    045
    046        /**
    047         * Used to get a median image from a set of images for instance.
    048         *
    049         * @param sets datasets
    050         * @return median dataset of the same shape as those passed in
    051         * @throws Exception when datasets have different shapes
    052         */
    053        public static Dataset median(final List<IDataset> sets) throws Exception {
    054
    055                return process(sets, new StatFunction() {
    056                        @Override
    057                        public double evaluate(Dataset set) {
    058                                return (Double)Stats.median(set);
    059                        }
    060                });
    061        }
    062
    063        /**
    064         * Used to get a median image from a set of images for instance.
    065         *
    066         * @param sets datasets
    067         * @return median data set of the same shape as those passed in.
    068         * @throws Exception when datasets have different shapes
    069         */
    070        private static Dataset process(final List<IDataset> sets, final StatFunction function) throws Exception {
    071
    072                int[] shape = assertShapes(sets);
    073                final DoubleDataset result = DatasetFactory.zeros(DoubleDataset.class, shape);
    074                final double[] rData = result.getData();
    075                final IndexIterator iter = new PositionIterator(shape);
    076                final int[] pos = iter.getPos();
    077
    078                final int len = sets.size();
    079                final DoubleDataset pixel = DatasetFactory.zeros(DoubleDataset.class, len);
    080                final double[] pData = pixel.getData();
    081                for (int i = 0; iter.hasNext(); i++) {
    082                        for (int ipix = 0; ipix < len; ipix++) {
    083                                pData[ipix] = sets.get(ipix).getDouble(pos);
    084                        }
    085                        pixel.setDirty();
    086                        rData[i] = function.evaluate(pixel);
    087                }
    088
    089                return result;
    090        }
    091
    092        private static int[] assertShapes(final Collection<IDataset> sets) throws Exception {
    093
    094                if (sets.size()<2) throw new IllegalArgumentException("You must take the median of at least two sets!");
    095
    096                final Iterator<IDataset> it = sets.iterator();
    097                final int[] shape = it.next().getShape();
    098                while (it.hasNext()) {
    099                        IDataset d = it.next();
    100                        final int[] nextShape = d.getShape();
    101                        if (!Arrays.equals(shape, nextShape)) throw new IllegalArgumentException("All data sets should be the same shape!");
    102                }
    103                return shape;
    104        }
    105}