    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
    033         * @return mean data set of the same shape as those passed in.
    034         * @throws Exception
    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
    050         * @return median data set of the same shape as those passed in.
    051         * @throws Exception
    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
    067         * @return median data set of the same shape as those passed in.
    068         * @throws Exception
    069         */
    070        private static Dataset process(final List<IDataset> sets,
    071                                                       final StatFunction   function) throws Exception {
    072
    073                int[] shape = assertShapes(sets);
    074                final DoubleDataset result = DatasetFactory.zeros(DoubleDataset.class, shape);
    075        final double[] rData = result.getData();
    076        final IndexIterator iter = new PositionIterator(shape);
    077        final int[] pos = iter.getPos();
    078
    079        final int len = sets.size();
    080                final DoubleDataset pixel = DatasetFactory.zeros(DoubleDataset.class, len);
    081                final double[] pData = pixel.getData();
    082        for (int i = 0; iter.hasNext(); i++) {
    083                        for (int ipix = 0; ipix < len; ipix++) {
    084                                pData[ipix] = sets.get(ipix).getDouble(pos);
    085                        }
    086                        pixel.setDirty();
    087                        rData[i] = function.evaluate(pixel);
    088                }
    089
    090        return result;
    091        }
    092
    093        private static int[] assertShapes(final Collection<IDataset> sets) throws Exception{
    094
    095                if (sets.size()<2) throw new Exception("You must take the median of at least two sets!");
    096
    097                final Iterator<IDataset> it = sets.iterator();
    098                final int[] shape = it.next().getShape();
    099                while (it.hasNext()) {
    100                        IDataset d = it.next();
    101                        final int[] nextShape = d.getShape();
    102                        if (!Arrays.equals(shape, nextShape)) throw new Exception("All data sets should be the same shape!");
    103                }
    104                return shape;
    105        }
    106}