cn.edu.tsinghua.gui.HistogramDemo.java Source code

Java tutorial

Introduction

Here is the source code for cn.edu.tsinghua.gui.HistogramDemo.java

Source

package cn.edu.tsinghua.gui;
/*
 * @(#)HistogramDemo.java   1.17 01/03/19 13:54:26
 *
 * Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */

/*
 * Disparaging my ass.  This was so riddled with errors it needed to be completely rewritten.
 * Now it works as it should. 20130130. Nicholas Clinton.
 */

import java.io.File;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.FlowLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.image.renderable.ParameterBlock;
import java.awt.image.DataBuffer;
import java.awt.event.*;
import java.awt.Color;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.border.EtchedBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.*;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.Histogram;
import javax.media.jai.LookupTableJAI;
import javax.media.jai.RenderedOp;

import org.apache.commons.math.MathException;
import org.apache.commons.math.distribution.NormalDistributionImpl;

/**
 * Rewritten to handle multi-band input and correct implementation of probability distributions.
 * @author nclinton
 *
 */
public class HistogramDemo extends JPanel implements ActionListener {

    private PlanarImage source = null;
    private PlanarImage target = null;
    private Panner panner;
    private JButton reset;
    private JButton equal;
    private JButton norm;
    private JButton piece;
    private ImageDisplay canvas;
    private XYPlot graph;

    /**
     * Initialize display.
     * @author Sun Microsystems
     * @param filename is the image filename
     */
    public HistogramDemo(String filename) {
        File f = new File(filename);

        if (f.exists() && f.canRead()) {
            source = JAI.create("fileload", filename);
        } else {
            return;
        }

        canvas = new ImageDisplay(source);
        canvas.setLayout(new FlowLayout(FlowLayout.RIGHT, 2, 2));

        panner = new Panner(canvas, source, 128);
        panner.setBackground(Color.red);
        panner.setBorder(new EtchedBorder());
        canvas.add(panner);

        Font font = new Font("SansSerif", Font.BOLD, 12);
        JLabel title = new JLabel(" Histogram");
        title.setFont(font);
        title.setLocation(0, 32);

        setOpaque(true);
        setLayout(new BorderLayout());
        setBackground(Color.white);

        graph = new XYPlot();
        graph.setBackground(Color.black);
        graph.setBorder(new LineBorder(new Color(0, 0, 255), 1));

        Colorbar cbar = new Colorbar();
        cbar.setBackground(Color.black);
        cbar.setPreferredSize(new Dimension(256, 25));
        cbar.setBorder(new LineBorder(new Color(255, 0, 255), 2));

        JPanel hist_panel = new JPanel();
        hist_panel.setLayout(new BorderLayout());
        hist_panel.setBackground(Color.white);
        hist_panel.add(graph, BorderLayout.CENTER);
        hist_panel.add(cbar, BorderLayout.SOUTH);

        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(2, 1, 5, 5));
        panel.setBackground(Color.white);
        panel.add(canvas);
        panel.add(hist_panel);

        JPanel controlPanel = new JPanel();
        controlPanel.setLayout(new FlowLayout());

        reset = new JButton("Reset");
        equal = new JButton("Uniform");
        norm = new JButton("Gaussian");
        piece = new JButton("Piecewise");

        reset.addActionListener(this);
        equal.addActionListener(this);
        norm.addActionListener(this);
        piece.addActionListener(this);

        controlPanel.add(reset);
        controlPanel.add(equal);
        controlPanel.add(norm);
        controlPanel.add(piece);

        add(title, BorderLayout.NORTH);
        add(panel, BorderLayout.CENTER);
        add(controlPanel, BorderLayout.SOUTH);

        // original histogram (remains unmodified)
        // graph.plot( getHistogram(source) );
        graph.plot(getMultiHistogram(source));
    }

    /**
     * Old one.
     * @param image
     * @return
     */
    public int[] getHistogram(PlanarImage image) {
        // set up the histogram
        int[] bins = { 256, 256, 256 };
        double[] low = { 0.0D, 0.0D, 0.0D };
        double[] high = { 256.0D, 256.0D, 256.0D };

        ParameterBlock pb = new ParameterBlock();
        pb.addSource(image);
        pb.add(null);
        pb.add(1);
        pb.add(1);
        pb.add(bins);
        pb.add(low);
        pb.add(high);

        RenderedOp op = JAI.create("histogram", pb, null);
        Histogram histogram = (Histogram) op.getProperty("histogram");

        // get histogram contents
        int[] local_array = new int[histogram.getNumBins(0)];
        for (int i = 0; i < histogram.getNumBins(0); i++) {
            local_array[i] = histogram.getBinSize(0, i);
        }

        return local_array;
    }

    /**
     * New one.  Assumes an 8-bit image.
     * @param image
     * @return
     */
    public int[][] getMultiHistogram(PlanarImage image) {
        // set up the histogram
        int[] bins = { 256, 256, 256 };
        double[] low = { 0.0D, 0.0D, 0.0D };
        double[] high = { 256.0D, 256.0D, 256.0D };

        ParameterBlock pb = new ParameterBlock();
        pb.addSource(image);
        pb.add(null);
        pb.add(1);
        pb.add(1);
        pb.add(bins);
        pb.add(low);
        pb.add(high);

        RenderedOp op = JAI.create("histogram", pb, null);
        Histogram histogram = (Histogram) op.getProperty("histogram");

        // get histogram contents
        int[][] local_array = new int[source.getNumBands()][histogram.getNumBins(0)];
        for (int b = 0; b < source.getNumBands(); b++) {
            for (int i = 0; i < histogram.getNumBins(b); i++) {
                local_array[b][i] = histogram.getBinSize(b, i);
                //System.out.print(local_array[b][i] + " ");
            }
            //System.out.println();
        }
        return local_array;
    }

    /**
     * Adjust to a Uniform distribution CDF.
     * @return the stretched image.
     */
    public PlanarImage equalize() {
        // From JAI programming guide
        int numBands = source.getNumBands();
        int binCount = 256;
        // Create an equalization CDF.
        float[][] CDFeq = new float[numBands][];
        for (int b = 0; b < numBands; b++) {
            CDFeq[b] = new float[binCount];
            for (int i = 0; i < binCount; i++) {
                CDFeq[b][i] = (float) (i + 1) / (float) binCount;
            }
        }
        int[] bins = { 256 };
        double[] low = { 0.0D };
        double[] high = { 256.0D };

        ParameterBlock pb = new ParameterBlock();
        pb.addSource(source);
        pb.add(null);
        pb.add(1);
        pb.add(1);
        pb.add(bins);
        pb.add(low);
        pb.add(high);

        RenderedOp fmt = JAI.create("histogram", pb, null);
        // Create a histogram-equalized image.
        return JAI.create("matchcdf", fmt, CDFeq);
    }

    /**
     * Adjust to a normal distribution CDF, mean=128, SD=64.
     * @return the stretched image.
     */
    public PlanarImage normalize() {
        int numBands = source.getNumBands();
        int binCount = 256;
        float[][] CDFnorm = new float[numBands][binCount];
        NormalDistributionImpl norm = new NormalDistributionImpl(128.0, 64.0);
        for (int b = 0; b < numBands; b++) {
            for (int i = 0; i < binCount - 1; i++) {
                try {
                    CDFnorm[b][i] = (float) norm.cumulativeProbability(i);
                } catch (MathException e) {
                    e.printStackTrace();
                }
            }
            // the cumulative probability must equal one
            CDFnorm[b][binCount - 1] = 1;
        }

        int[] bins = { 256 };
        double[] low = { 0.0D };
        double[] high = { 256.0D };

        ParameterBlock pb = new ParameterBlock();
        pb.addSource(source);
        pb.add(null);
        pb.add(1);
        pb.add(1);
        pb.add(bins);
        pb.add(low);
        pb.add(high);

        RenderedOp fmt = JAI.create("histogram", pb, null);
        return JAI.create("matchcdf", fmt, CDFnorm);
    }

    /**
     * From Sun.  Piecewise linear mapping.
     * @return
     */
    public PlanarImage piecewise() {

        // Create a piecewise-mapped image emphasizing low values.
        int numBands = source.getNumBands();
        float[][][] bp = new float[numBands][2][];
        for (int b = 0; b < numBands; b++) {
            bp[b][0] = new float[] { 0.0F, 32.0F, 64.0F, 255.0F };
            bp[b][1] = new float[] { 0.0F, 64.0F, 112.0F, 255.0F };
        }

        return JAI.create("piecewise", source, bp);
    }

    /**
     * Handle button clicks.
     */
    public void actionPerformed(ActionEvent e) {
        JButton b = (JButton) e.getSource();

        if (b == reset) {
            target = source;
        } else if (b == equal) {
            target = equalize();
        } else if (b == norm) {
            target = normalize();
        } else if (b == piece) {
            target = piecewise();
        }

        canvas.set(target);
        graph.plot(getMultiHistogram(target));
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private void createAndShowGUI() {
        JFrame frame = new JFrame("Java Advanced Imaging (JAI) Widget");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(this);
        frame.pack();
        frame.setVisible(true);
    }

    /**
     * 
     * @param args is the file path of an image
     */
    public static void main(String[] args) {
        final HistogramDemo histo = new HistogramDemo(args[0]);
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                histo.createAndShowGUI();
            }
        });
    }
}