/* * Copyright 2005, 2009 Cosmin Basca. * e-mail: cosmin.basca@gmail.com * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * Please see COPYING for the complete licence. */ package robo.vision.util; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.renderable.ParameterBlock; import java.io.File; import javax.media.jai.Histogram; import javax.media.jai.JAI; import javax.media.jai.LookupTableJAI; import javax.media.jai.PlanarImage; import javax.media.jai.RenderedOp; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.border.EtchedBorder; import javax.swing.border.LineBorder; import robo.vision.widgets.Colorbar; import robo.vision.widgets.ImageDisplay; import robo.vision.widgets.Panner; import robo.vision.widgets.XYPlot; public class HistogramAnalyzerPanel extends JPanel implements ActionListener { /** * */ private static final long serialVersionUID = 8133888877427171860L; 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; public HistogramAnalyzerPanel(PlanarImage src) { this.source = src; this.init(); } public HistogramAnalyzerPanel(String filename) { File f = new File(filename); if ( f.exists() && f.canRead() ) { source = JAI.create("fileload", filename); } else { return; } this.init(); } private void init() { 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("Equalize"); norm = new JButton("Normalize"); 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) ); } public int[] getHistogram(PlanarImage image) { // set up the histogram int[] bins = { 256 }; double[] low = { 0.0D }; double[] high = { 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; } // one way to do this (old style) // this could also be done with matchcdf public PlanarImage equalize() { int sum = 0; byte[] cumulative = new byte[256]; int array[] = getHistogram(source); float scale = 255.0F / (float) (source.getWidth() * source.getHeight()); for ( int i = 0; i < 256; i++ ) { sum += array[i]; cumulative[i] = (byte)((sum * scale) + .5F); } LookupTableJAI lookup = new LookupTableJAI(cumulative); ParameterBlock pb = new ParameterBlock(); pb.addSource(source); pb.add(lookup); return JAI.create("lookup", pb, null); } // for a single band public PlanarImage normalize() { double[] mean = new double[] { 128.0 }; double[] stDev = new double[] { 34.0 }; float[][] CDFnorm = new float[1][]; CDFnorm[0] = new float[256]; double mu = mean[0]; double twoSigmaSquared = 2.0*stDev[0]*stDev[0]; CDFnorm[0][0] = (float)Math.exp(-mu*mu/twoSigmaSquared); for ( int i = 1; i < 256; i++ ) { double deviation = i - mu; CDFnorm[0][i] = CDFnorm[0][i-1] + (float)Math.exp(-deviation*deviation/twoSigmaSquared); } double CDFnormLast = CDFnorm[0][255]; for ( int i = 0; i < 256; i++ ) { CDFnorm[0][i] /= CDFnormLast; } 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); } public PlanarImage piecewise() { float[][][] bp = new float[1][2][]; bp[0][0] = new float[] { 0.0F, 32.0F, 64.0F, 255.0F }; bp[0][1] = new float[] { 0.0F, 128.0F, 112.0F, 255.0F }; return JAI.create("piecewise", source, bp); } 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( getHistogram(target) ); } }