001    /*
002     * Histogram3DCreator
003     *
004     * Copyright (c) 2002 Marco Schmidt.
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.color.analysis;
009    
010    import net.sourceforge.jiu.color.data.Histogram3D;
011    import net.sourceforge.jiu.color.data.NaiveHistogram3D;
012    import net.sourceforge.jiu.color.data.OnDemandHistogram3D;
013    import net.sourceforge.jiu.data.IntegerImage;
014    import net.sourceforge.jiu.ops.Operation;
015    import net.sourceforge.jiu.ops.MissingParameterException;
016    import net.sourceforge.jiu.ops.WrongParameterException;
017    
018    /**
019     * This class creates three-dimensional histograms for images with integer samples.
020     * Only {@link net.sourceforge.jiu.data.IntegerImage} is supported.
021     * Existing histogram objects can be given to this operation to be reused.
022     * <p>
023     * <em>Note: Before JIU 0.10.0 there was a single HistogramCreator class.</em>
024     * @author Marco Schmidt
025     * @since 0.10.0
026     */
027    public class Histogram3DCreator extends Operation
028    {
029            private Histogram3D hist;
030            private IntegerImage image;
031            private int index1;
032            private int index2;
033            private int index3;
034            private boolean naive;
035    
036            private void createHistogramIfNecessary()
037            {
038                    if (hist == null)
039                    {
040                            if (naive)
041                            {
042                                    hist = new NaiveHistogram3D(image.getMaxSample(index1) + 1, 
043                                            image.getMaxSample(index2) + 1, 
044                                            image.getMaxSample(index3) + 1);
045                            }
046                            else
047                            {
048                                    hist = new OnDemandHistogram3D(image.getMaxSample(index1) + 1, 
049                                            image.getMaxSample(index2) + 1, 
050                                            image.getMaxSample(index3) + 1);
051                            }
052                    }
053            }
054    
055            /**
056             * Returns the histogram initialized in this operation.
057             */
058            public Histogram3D getHistogram()
059            {
060                    return hist;
061            }
062    
063            public void process() throws
064                    MissingParameterException,
065                    WrongParameterException
066            {
067                    if (image == null)
068                    {
069                            throw new MissingParameterException("Image parameter missing.");
070                    }
071                    createHistogramIfNecessary();
072                    if (hist.getMaxValue(0) < image.getMaxSample(index1) ||
073                        hist.getMaxValue(1) < image.getMaxSample(index2) ||
074                        hist.getMaxValue(2) < image.getMaxSample(index3))
075                    {
076                            throw new WrongParameterException("Histogram is not large enough for image (hist max value / image max samples).");
077                    }
078                    hist.clear();
079                    final int WIDTH = image.getWidth();
080                    final int HEIGHT = image.getHeight();
081                    for (int y = 0; y < HEIGHT; y++)
082                    {
083                            for (int x = 0; x < WIDTH; x++)
084                            {
085                                    hist.increaseEntry(
086                                            image.getSample(index1, x, y),
087                                            image.getSample(index2, x, y), 
088                                            image.getSample(index3, x, y));
089                            }
090                            setProgress(y, HEIGHT);
091                    }
092            }
093    
094            /**
095             * Sets the histogram object to be reused for this operation.
096             * If this method is not called, a new histogram will be created.
097             * @param histogram the histogram object to be used in this operation
098             */
099            public void setHistogram3D(Histogram3D histogram)
100            {
101                    hist = histogram;
102            }
103    
104            /**
105             * The image for which a histogram will be initialized.
106             * Simply calls {@link #setImage(IntegerImage, int, int, int)} 
107             * with 0, 1 and 2 as parameters.
108             * @param newImage the image for the histogram initialization
109             */
110            public void setImage(IntegerImage newImage)
111            {
112                    setImage(newImage, 0, 1, 2);
113            }
114    
115            /**
116             * The image for which a histogram will be initialized.
117             * Simply calls {@link #setImage(IntegerImage, int, int, int)} 
118             * with 0, 1 and 2 as parameters.
119             * @param newImage
120             */
121            public void setImage(IntegerImage newImage, int channelIndex1, int channelIndex2, int channelIndex3)
122            {
123                    if (newImage == null)
124                    {
125                            throw new IllegalArgumentException("Image argument must not be null.");
126                    }
127                    
128                    if (channelIndex1 < 0 || channelIndex1 >= newImage.getNumChannels() ||
129                        channelIndex2 < 0 || channelIndex2 >= newImage.getNumChannels() ||
130                        channelIndex3 < 0 || channelIndex3 >= newImage.getNumChannels())
131                    {
132                            throw new IllegalArgumentException("The three index arguments must be >= 0 and < the number of channels.");
133                    }
134                    if (channelIndex1 == channelIndex2 || channelIndex2 == channelIndex3 || channelIndex1 == channelIndex3)
135                    {
136                            throw new IllegalArgumentException("The three index arguments must be different from each other.");
137                    }
138                    image = newImage;
139                    index1 = channelIndex1;
140                    index2 = channelIndex2;
141                    index3 = channelIndex3;
142            }
143    }