001    /*
002     * Histogram1DCreator
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.ArrayHistogram1D;
011    import net.sourceforge.jiu.color.data.Histogram1D;
012    import net.sourceforge.jiu.data.IntegerImage;
013    import net.sourceforge.jiu.ops.Operation;
014    import net.sourceforge.jiu.ops.MissingParameterException;
015    import net.sourceforge.jiu.ops.WrongParameterException;
016    
017    /**
018     * This class creates one-dimensional histograms for images with integer samples.
019     * Only {@link net.sourceforge.jiu.data.IntegerImage} objects are supported.
020     * <p>
021     * Existing histogram objects can be given to this operation to be reused.
022     * Give an existing {@link net.sourceforge.jiu.color.data.Histogram1D} object to this operation via 
023     * {@link #setHistogram(Histogram1D)}.
024     * <p>
025     * The histogram can be created for any channel of an IntegerImage.
026     * The first channel (index 0) is the default channel.
027     * Use {@link #setImage(IntegerImage, int)} to specify another one.
028     * <p>
029     * <em>Note: Before JIU 0.10.0 there was a single HistogramCreator class.</em>
030     * <h3>Usage example</h3>
031     * Creates a histogram for the third channel of an image.
032     * <pre>
033     * Histogram1DCreator hc = new Histogram1DCreator();
034     * hc.setImage(image, 2);
035     * hc.process();
036     * Histogram1D hist = hc.getHistogram();
037     * </pre>
038     * @author Marco Schmidt
039     * @since 0.10.0
040     */
041    public class Histogram1DCreator extends Operation
042    {
043            private Histogram1D hist;
044            private int channelIndex;
045            private IntegerImage image;
046    
047            private void createHistogramIfNecessary()
048            {
049                    if (hist == null)
050                    {
051                            hist = new ArrayHistogram1D(image.getMaxSample(0) + 1);
052                    }
053            }
054    
055            /**
056             * Returns the histogram used in this operation.
057             * @return histogram object, newly-created or reused one
058             * @see #setHistogram
059             */
060            public Histogram1D getHistogram()
061            {
062                    return hist;
063            }
064    
065            public void process() throws
066                    MissingParameterException,
067                    WrongParameterException
068            {
069                    if (image == null)
070                    {
071                            throw new MissingParameterException("Image parameter missing.");
072                    }
073                    createHistogramIfNecessary();
074                    if (hist.getMaxValue() < image.getMaxSample(channelIndex))
075                    {
076                            throw new WrongParameterException("Histogram does not have enough entries.");
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(image.getSample(channelIndex, x, y));
086                            }
087                            setProgress(y, HEIGHT);
088                    }
089            }
090    
091            /**
092             * Sets a histogram object to be used for this operation.
093             * Within {@link #process} it will be checked if this histogram is large enough
094             * for the image.
095             * @see #getHistogram
096             */
097            public void setHistogram(Histogram1D histogram)
098            {
099                    hist = histogram;
100            }
101    
102            /**
103             * Set the image for which the histogram is to be initialized.
104             * The first channel (index 0) is used by default.
105             * @param newImage image object to be used
106             * @see #setImage(IntegerImage, int)
107             */
108            public void setImage(IntegerImage newImage)
109            {
110                    setImage(newImage, 0);
111            }
112    
113            /**
114             * Set the image and the channel index for which the histogram is to be initialized.
115             * @param newImage image object to be used
116             * @param imageChannelIndex must not be negative and must be smaller than newImage.getNumChannels()
117             * @see #setImage(IntegerImage)
118             */
119            public void setImage(IntegerImage newImage, int imageChannelIndex)
120            {
121                    if (newImage == null)
122                    {
123                            throw new IllegalArgumentException("Image argument must be non-null.");
124                    }
125                    if (imageChannelIndex < 0 || imageChannelIndex >= newImage.getNumChannels())
126                    {
127                            throw new IllegalArgumentException("Invalid channel for given image.");
128                    }
129                    image = newImage;
130                    channelIndex = imageChannelIndex;
131            }
132    }