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}