001    /*
002     * RGBColorList
003     *
004     * Copyright (c) 2001, 2002, 2003 Marco Schmidt.
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.color.quantization;
009    
010    import net.sourceforge.jiu.color.data.Histogram3D;
011    import net.sourceforge.jiu.data.RGBIndex;
012    import net.sourceforge.jiu.util.ComparatorInterface;
013    import net.sourceforge.jiu.util.Sort;
014    
015    /**
016     * Holds an array of {@link RGBColor} objects.
017     * @author Marco Schmidt
018     */
019    public class RGBColorList implements RGBIndex
020    {
021            private RGBColor[] list;
022            private final int numEntries;
023    
024            /**
025             * Creates a color list with room for a fixed number of entries.
026             * @param numberOfEntries the number of entries in the new list (must be larger than zero)
027             * @throws IllegalArgumentException if the argument is smaller than one
028             */
029            private RGBColorList(final int NUM_ENTRIES)
030            {
031                    if (NUM_ENTRIES < 1)
032                    {
033                            throw new IllegalArgumentException("RGBColorList must have at least one entry; got " + NUM_ENTRIES);
034                    }
035                    numEntries = NUM_ENTRIES;
036                    list = new RGBColor[NUM_ENTRIES];
037            }
038    
039            /**
040             * Creates a new list and initializes it with the argument histogram.
041             * All values from the histogram with a counter larger than zero will
042             * be added to the list (which will include all colors that appear at least
043             * once in the image on which the histogram was created).
044             * @param hist the histogram from which the list will be initialized
045             * @throws IllegalArgumentException thrown if no histogram entry has a non-zero counter
046             */
047            public RGBColorList(Histogram3D hist)
048            {
049                    this(hist.getNumUsedEntries());
050                    int i = 0;
051                    final int MAX_RED = hist.getMaxValue(INDEX_RED);
052                    final int MAX_GREEN = hist.getMaxValue(INDEX_GREEN);
053                    final int MAX_BLUE = hist.getMaxValue(INDEX_BLUE);
054                    for (int r = 0; r <= MAX_RED; r++)
055                    {
056                            for (int g = 0; g <= MAX_GREEN; g++)
057                            {
058                                    for (int b = 0; b <= MAX_BLUE; b++)
059                                    {
060                                            int counter = hist.getEntry(r, g, b);
061                                            if (counter > 0)
062                                            {
063                                                    list[i++] = new RGBColor(r, g, b, counter);
064                                            }
065                                    }
066                            }
067                    }
068            }
069    
070            /**
071             * In a given interval of the list this method searches for the color axis 
072             * that has the largest distribution of values.
073             * Returns a pair of int values;
074             * the first value is the component (0, 1 or 2),
075             * the second value is the difference between the minimum and maximum value found in the list.
076             * Only checks colors from index i1 to i2 of the list.
077             */
078            public int[] findExtrema(int i1, int i2)
079            {
080                    if (i1 < 0 || i1 >= numEntries || i2 < 0 || i2 >= numEntries || i1 > i2)
081                    {
082                            return null;
083                    }
084                    int[] max = new int[3];
085                    int[] min = new int[3];
086                    RGBColor c = list[i1];
087                    for (int i = 0; i < 3; i++)
088                    {
089                            min[i] = max[i] = c.getSample(i);
090                    }
091                    int i = i1 + 1;
092                    while (i < i2)
093                    {
094                            c = list[i++];
095                            for (int j = 0; j < 3; j++)
096                            {
097                                    int cSample = c.getSample(j);
098                                    if (cSample < min[j])
099                                    {
100                                            min[j] = cSample;
101                                    }
102                                    else
103                                    {
104                                            if (cSample > max[j])
105                                            {
106                                                    max[j] = cSample;
107                                            }
108                                    }
109                            }
110                    }
111                    // first value: sample index (0 - 2); second value: difference
112                    int[] result = new int[2];
113                    result[0] = result[1] = -1;
114                    for (i = 0; i < 3; i++)
115                    {
116                            int newDiff = max[i] - min[i];
117                            if (newDiff > result[1])
118                            {
119                                    result[0] = i;
120                                    result[1] = newDiff;
121                            }
122                    }
123                    return result;
124            }
125    
126            /**
127             * Returns an {@link RGBColor} object from this list, given by its zero-based
128             * index value.
129             * @param index zero-based index into the list; must be smaller than {@link #getNumEntries()}
130             * @return the color object
131             */
132            public RGBColor getColor(int index)
133            {
134                    return list[index];
135            }
136    
137            /**
138             * Returns the number of color objects in this list.
139             * @return number of colors in the list
140             */
141            public int getNumEntries()
142            {
143                    return list.length;
144            }
145    
146            /**
147             * Sorts an interval of the array of colors by one of the three components (RGB).
148             * @param index1 the index of the first element in the interval
149             * @param index2 the index of the last element in the interval
150             * @param axis the color component by which the interval is to be sorted, {@link #INDEX_RED}, {@link #INDEX_GREEN} or {@link #INDEX_BLUE}
151             */
152            public void sortByAxis(int index1, int index2, int axis) 
153            {
154                    Sort.sort(list, index1, index2, new RGBColorComparator(axis));
155            }
156    
157            /**
158             * Sorts an interval of the array of colors by their counters.
159             * @param index1 the index of the first element in the interval
160             * @param index2 the index of the last element in the interval
161             */
162            public void sortByCounter(int index1, int index2) 
163            {
164                    Sort.sort(list, index1, index2, new ComparatorInterface()
165                    {
166                            public int compare(Object obj1, Object obj2)
167                            {
168                                    RGBColor col1 = (RGBColor)obj1;
169                                    RGBColor col2 = (RGBColor)obj2;
170                                    return col1.getCounter() - col2.getCounter();
171                            }
172                    });
173            }
174    }