001/* Change the contrast of an image.
002 @Copyright (c) 1998-2014 The Regents of the University of California.
003 All rights reserved.
004
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the
008 above copyright notice and the following two paragraphs appear in all
009 copies of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION 2
025 COPYRIGHTENDKEY
026 */
027package ptolemy.domains.sdf.lib.vq;
028
029import ptolemy.actor.lib.Transformer;
030import ptolemy.data.IntMatrixToken;
031import ptolemy.data.type.BaseType;
032import ptolemy.kernel.CompositeEntity;
033import ptolemy.kernel.util.IllegalActionException;
034import ptolemy.kernel.util.NameDuplicationException;
035import ptolemy.kernel.util.Workspace;
036
037///////////////////////////////////////////////////////////////////
038//// ImageContrast
039
040/**
041 Change the contrast of an image.
042
043 <p>If the input image has a lot of pixels with the same or similar color,
044 This actor uses gray scale equalization to redistribute the value of each
045 pixel between 0 and 255.
046
047 @author Michael Leung, Steve Neuendorffer
048 @version $Id$
049 @since Ptolemy II 0.2
050 @Pt.ProposedRating Red (mikele)
051 @Pt.AcceptedRating Red (cxh)
052 */
053public class ImageContrast extends Transformer {
054    /** Construct an actor with the given container and name.
055     *  @param container The container.
056     *  @param name The name of this actor.
057     *  @exception IllegalActionException If the actor cannot be contained
058     *   by the proposed container.
059     *  @exception NameDuplicationException If the container already has an
060     *   actor with this name.
061     */
062    public ImageContrast(CompositeEntity container, String name)
063            throws IllegalActionException, NameDuplicationException {
064        super(container, name);
065
066        output.setTypeEquals(BaseType.INT_MATRIX);
067        input.setTypeEquals(BaseType.INT_MATRIX);
068    }
069
070    ///////////////////////////////////////////////////////////////////
071    ////                         public methods                    ////
072
073    /** Clone the actor into the specified workspace.
074     *  @param workspace The workspace for the new object.
075     *  @return A new actor.
076     *  @exception CloneNotSupportedException If a derived class contains
077     *   an attribute that cannot be cloned.
078     */
079    @Override
080    public Object clone(Workspace workspace) throws CloneNotSupportedException {
081        ImageContrast newObject = (ImageContrast) super.clone(workspace);
082        newObject.colorHistogram = new int[256];
083        return newObject;
084    }
085
086    /** Fire the actor.
087     *  Consume one image on the input port.
088     *
089     *  Summary:
090     *  Contrast the image so that
091     *  an more evenly color distributed image can be obtained.
092     *  Assume that color is bounded from 0 to 255 inclusively.
093     *  @exception IllegalActionException If image color is out-of-bound.
094     *
095     *  Algorithm:
096     *  Construct a color histogram for the input image.
097     *  Construct a cdf for the color histogram.
098     *  Using Gray Scale Equalization, re-map each image pixel color.
099     *
100     *  Send the new image out the output port.
101     */
102    @Override
103    public void fire() throws IllegalActionException {
104        super.fire();
105        int i;
106        int j;
107        int[][] frame;
108        int frameElement;
109
110        IntMatrixToken message = (IntMatrixToken) input.get(0);
111        frame = message.intMatrix();
112
113        // Construct a color distribution histogram for the input image:
114        // Assuming the color bound for the input 0 and 255. If color detected
115        // that has color either bigger than 255 OR small than 0, then throw an
116        // illegal action exception.
117        for (i = 0; i < 256; i++) {
118            colorHistogram[i] = 0;
119        }
120
121        int pixels = frame.length * frame[0].length;
122
123        for (i = 0; i < frame.length; i++) {
124            for (j = 0; j < frame[i].length; j++) {
125                frameElement = frame[i][j];
126
127                if (frameElement < 0 || frameElement > 255) {
128                    throw new IllegalActionException(
129                            "ImageContrast:" + "input image pixel contains at"
130                                    + j + "," + i + "with value" + frameElement
131                                    + "that is out of bounds."
132                                    + " Not between 0 and 255.");
133                }
134
135                colorHistogram[frameElement]++;
136            }
137        }
138
139        //Construct the cdf of the color distribution histogram
140        //colorHistogram[0] = colorHistogram[0]
141        for (i = 1; i < 256; i++) {
142            colorHistogram[i] = colorHistogram[i - 1] + colorHistogram[i];
143        }
144
145        // Search each pixel in the image and re-map it to a new
146        // color number to make a new relatively even color distribution
147        // image.
148        int distributionConstant = pixels / 255;
149
150        for (i = 0; i < frame.length; i++) {
151            for (j = 0; j < frame[i].length; j++) {
152                frameElement = frame[i][j];
153                frame[i][j] = colorHistogram[frameElement]
154                        / distributionConstant;
155            }
156        }
157
158        message = new IntMatrixToken(frame);
159        output.send(0, message);
160    }
161
162    ///////////////////////////////////////////////////////////////////
163    ////                         private variables                 ////
164    private int[] colorHistogram = new int[256];
165}