/* JAI-Ext - OpenSource Java Advanced Image Extensions Library * http://www.geo-solutions.it/ * Copyright 2014 GeoSolutions * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package it.geosolutions.jaiext.stats; import it.geosolutions.jaiext.range.Range; import it.geosolutions.jaiext.range.RangeFactory; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * This subclass of {@link Statistics} is used for calculating the median of an image. This operation is performed by saving alist of all the pixel * values. When the result is requested, the list is sorted and then the middle value is taken. If the list size is even, then the mean of the 2 * middle values. */ public class Median extends Statistics { /** List of the image pixels */ private List<Double> listData; /** Range of the accepted values */ private final Range interval; Median(double minBound, double maxBound) { // If the array bounds are infinite, the minimum and maximum values are taken if (minBound == Double.NEGATIVE_INFINITY) { minBound = -Double.MAX_VALUE; } if (maxBound == Double.POSITIVE_INFINITY) { maxBound = Double.MAX_VALUE; } // Setting of the parameters this.interval = RangeFactory.create(minBound, true, maxBound, false, false); this.listData = Collections.synchronizedList(new ArrayList<Double>()); this.type = StatsType.MEDIAN; } @Override public void addSample(double sample) { samples++; if (interval.contains(sample)) { listData.add(sample); } } @Override protected void accumulateStats(Statistics stats) { throw new UnsupportedOperationException("Median statistics cannot be accumulated"); } @Override public Object getResult() { // Sorting of the data Collections.sort(listData); // Calculation of the list size int listSize = listData.size(); if (listSize == 0) { // If no value is saved, then the Double.NaN is returned return Double.NaN; } else if (listSize == 1) { // If the size is one, then the value is returned return listData.get(0); } else { // If the middle value is 1 it is returned // else an average of the 2 middle value is returned int halfSize = listSize / 2; double halfValue = listData.get(halfSize); if (listData.size() % 2 == 1) { return halfValue; } else { return (halfValue + listData.get(halfSize + 1)) / 2; } } } @Override public Long getNumSamples() { return Long.valueOf(samples); } @Override protected void clearStats() { // The list is cleared by creating a new empty list listData = Collections.synchronizedList(new ArrayList<Double>()); } }