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}