/* 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.zonal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import javax.media.jai.ROI; import it.geosolutions.jaiext.range.Range; import it.geosolutions.jaiext.stats.Statistics; import it.geosolutions.jaiext.stats.Statistics.StatsType; import it.geosolutions.jaiext.stats.StatsFactory; /** * This class is used for storing the statistics associated to a specific geometry. All the statistics are organized inside Map objects. The * "statsContainer" object contains a number of items, each one for every band. Every item object contains the statistics array for every Class, if the * classifier is present, or only for the Class 0 if not. The statistics object are created at the initialization time if the classifier is not * present, otherwise they are created when a new Class is founded. */ public class ZoneGeometry { /** Boolean indicating if the classifier is present */ private final boolean classification; /** Map containing all the statistics for every band and for every Class */ private final Map<Integer, Map<Integer, Map<Range, Statistics[]>>> statsContainer; /** Array indicating which statistics must be calculated */ private final StatsType[] stats; /** Array indicating the minimum bounds for each band */ private double[] minBounds; /** Array indicating the maximum bounds for each band */ private double[] maxBounds; /** Array indicating the number of bins for each band */ private int[] numbins; /** Geometry associated to the selected zone*/ private final ROI roi; private List<Range> ranges; ZoneGeometry(ROI roi, List<Range> ranges, int[] bands, StatsType[] stats, boolean classification, double[] minBounds, double[] maxBounds, int[] numbins) { // Setting of the parameters this.classification = classification; this.stats = stats; this.minBounds = minBounds; this.maxBounds = maxBounds; this.numbins = numbins; this.roi = roi; this.ranges = ranges; // creation of the new map associated with this ZoneGeometry instance statsContainer = new TreeMap<Integer, Map<Integer, Map<Range, Statistics[]>>>(); // Cicle on all the selected bands for creating the band inner map elements for (int i : bands) { Map<Integer, Map<Range, Statistics[]>> mapClass = new TreeMap<Integer, Map<Range, Statistics[]>>(); // If the classifier is not present, the statistics objects are created at the ZoneGeometry // instantiation if (!classification) { Map<Range, Statistics[]> mapRange = new HashMap<Range, Statistics[]>(); for(Range inputRange : ranges){ Statistics[] statistics = new Statistics[stats.length]; for (int st = 0; st < stats.length; st++) { int statId = stats[st].getStatsId(); if (statId <= 6) { statistics[st] = StatsFactory.createSimpleStatisticsObjectFromInt(statId); } else { statistics[st] = StatsFactory.createComplexStatisticsObjectFromInt(statId, minBounds[i], maxBounds[i], numbins[i]); } } mapRange.put(inputRange, statistics); } mapClass.put(0, mapRange); } statsContainer.put(i, mapClass); } } public synchronized void add(double sample, int band, int classId, Range dataRange) { // Selection of the map associated with the band indicated by the index Map<Integer, Map<Range, Statistics[]>> mapClass = statsContainer.get(band); // Selection of the Map associated with the zone indicated by the index // (always 0 if the classifier is not present) Map<Range, Statistics[]> mapRange = mapClass.get(classId); // if the classifier is present and a new Class is founded, then a new statistics object is created if (classification && mapRange == null) { mapRange = new HashMap<Range, Statistics[]>(); Statistics[] statistics = new Statistics[stats.length]; for (int st = 0; st < stats.length; st++) { int statId = stats[st].getStatsId(); if (statId <= 6) { statistics[st] = StatsFactory.createSimpleStatisticsObjectFromInt(statId); } else { statistics[st] = StatsFactory.createComplexStatisticsObjectFromInt(statId, minBounds[band], maxBounds[band], numbins[band]); } } // The updated statistics are inserted in the related containers mapRange.put(dataRange, statistics); // Insertion of the MapRange if not present mapClass.put(classId, mapRange); }else{ // Selection of the Statistics[] statistics = mapRange.get(dataRange); // Update of the statistics for (int st = 0; st < stats.length; st++) { statistics[st].addSample(sample); } } } /** * Utility method for having the Statistics of a specific band inside a specific zone class and a specific Range */ public Statistics[] getStatsPerBandPerClassPerRange(int band, int classId, Range range) { Statistics[] statistics = statsContainer.get(band).get(classId).get(range); return statistics; } /** * Utility method for having the Statistics of a specific band if no classifier is used */ public Statistics[] getStatsPerBandNoClassifier(int band, Range range) { Statistics[] statistics = statsContainer.get(band).get(0).get(range); return statistics; } /** * Utility method for having the Statistics of a specific band if no classifier and no Range are used */ public Statistics[] getStatsPerBandNoClassifierNoRange(int band) { Range fullRange = statsContainer.get(band).get(0).keySet().iterator().next(); Statistics[] statistics = statsContainer.get(band).get(0).get(fullRange); return statistics; } /** * Utility method for having the Statistics of a specific band if classifier is used but no range is present */ public Statistics[] getStatsPerBandNoRange(int band, int classId) { Statistics[] statistics = statsContainer.get(band).get(classId).get(ranges.get(0)); return statistics; } /** * Utility method for having all the zone-class statistics for a selected band. */ public Map<Integer, Map<Range, Statistics[]>> getStatsPerBand(int band) { Map<Integer, Map<Range, Statistics[]>> resultAllClass = statsContainer.get(band); return resultAllClass; } /** * Utility method for having all the zone-class statistics for a selected band. */ public Map<Range, Statistics[]> getStatsPerBandPerClass(int band, int classId) { Map<Range, Statistics[]> resultPerClass = statsContainer.get(band).get(classId); return resultPerClass; } /** * Utility method indicating the number of classes */ public int getNumClass() { Map<Integer, Map<Range, Statistics[]>> resultAllClass = statsContainer.get(0); return resultAllClass.size(); } public List<Range> getRanges(){ return ranges; } /** * Utility method indicating the index of all the classes */ public Set<Integer> getClasses() { Map<Integer, Map<Range, Statistics[]>> resultAllClass = statsContainer.get(0); Set<Integer> classes = resultAllClass.keySet(); TreeSet<Integer> orderedSet = new TreeSet<Integer>(classes); return java.util.Collections.unmodifiableSet(orderedSet); } /** * Utility method for having all ZoneGeometry statistics. */ public Map<Integer, Map<Integer, Map<Range, Statistics[]>>> getTotalStats() { return new TreeMap<Integer, Map<Integer, Map<Range, Statistics[]>>>(statsContainer); } /** * Utility method for finding the zone associated geometry. */ public ROI getROI(){ return roi; } /** Simple method for clearing all the image statistics */ public void clear() { statsContainer.clear(); } static class StatsPerRange{ private Statistics[] stats; private List<Range> rangeList; StatsPerRange() { rangeList = new ArrayList<Range>(); } public Statistics[] getStats() { return stats; } public void setStats(Statistics[] stats) { this.stats = stats; } public List<Range> getRangeList() { return rangeList; } public void addRange(Range r){ rangeList.add(r); } public void addRanges(List<Range> list){ rangeList=list; } } }