import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import java.io.*;
import javax.imageio.ImageIO;
import java.util.*;
import java.awt.event.*;
import java.awt.image.*;
/*******************************************/
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ByteLookupTable;
import java.awt.image.ColorConvertOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.awt.image.LookupOp;
import java.awt.image.RescaleOp;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
/************************************************/
class HistogramViewer extends javax.swing.JFrame {
HistogramEqualizer histoEqual = new HistogramEqualizer();
private File imageFile; // The image selected in the selectFileDialog
BufferedImage image;
private ImageComponent imageComponent = new ImageComponent();
private HistogramComponent histogramComponent = new HistogramComponent();
private javax.swing.JButton loadFileButton;
private javax.swing.JFrame selectFileDialog;
private javax.swing.JFileChooser selector;
private java.awt.Container histogramContainer = new Container();
private java.awt.Container imageContainer = new Container();
private java.awt.Container buttonContainer = new Container();
private final int WINDOW_WIDTH = 590;
private final int WINDOW_HEIGHT = 400;
public static void main(String[] args) {
new HistogramViewer().show();
}
/*************************************************************************/
/**
* A Hashtable member variable holds the image processing
* operations, keyed by their names.
**/
private Hashtable mOps;
/**
* The createOps() method creates the image processing
* operations discussed in the column.
**/
void createOps() {
// Create a brand new Hashtable to hold the operations.
mOps = new Hashtable();
// Blurring
float ninth = 1.0f / 9.0f;
float[] blurKernel = {
ninth, ninth, ninth,
ninth, ninth, ninth,
ninth, ninth, ninth,
};
mOps.put("Blur", new ConvolveOp(
new Kernel(3, 3, blurKernel)));
// Edge detection
float[] edgeKernel = {
0.0f, -1.0f, 0.0f,
-1.0f, 4.0f, -1.0f,
0.0f, -1.0f, 0.0f
};
mOps.put("Edge detector", new ConvolveOp(
new Kernel(3, 3, edgeKernel)));
// Sharpening
float[] sharpKernel = {
0.0f, -1.0f, 0.0f,
-1.0f, 5.0f, -1.0f,
0.0f, -1.0f, 0.0f
};
mOps.put("Sharpen", new ConvolveOp(
new Kernel(3, 3, sharpKernel),
ConvolveOp.EDGE_NO_OP, null));
// Lookup table operations: posterizing and inversion.
short[] posterize = new short[256];
short[] invert = new short[256];
short[] straight = new short[256];
byte[] thresholdTable = new byte[256];
for (int i = 0; i < 256; i++) {
posterize = (short)(i - (i % 32));
invert = (short)(255 - i);
straight = (short)i;
thresholdTable = (byte) ((i < 128) ? 0 : 255);
}
// mOps.put("Posterize", new LookupOp(new ShortLookupTable(0, posterize),null));
mOps.put("GrayScale", new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null));
// mOps.put("Invert", new LookupOp(new ShortLookupTable(0, invert), null));
short[][] blueInvert = new short[][] { straight, straight, invert };
// mOps.put("Invert blue", new LookupOp(new ShortLookupTable(0, blueInvert), null));
// Thresholding
// mOps.put("Threshold 192", createThresholdOp(192, 0, 255));
// mOps.put("Threshold 128", createThresholdOp(128, 0, 255));
//mOps.put("Threshold 64", createThresholdOp(64, 0, 255));
mOps.put("Threshold ", new LookupOp(new ByteLookupTable(0, thresholdTable), null));
}
/**
* createThresholdOp() uses a LookupOp to simulate a
* thresholding operation.
**/
private BufferedImageOp createThresholdOp(int threshold,
int minimum, int maximum) {
short[] thresholdArray = new short[256];
for (int i = 0; i < 256; i++) {
if (i < threshold)
thresholdArray = (short)minimum;
else
thresholdArray = (short)maximum;
}
return new LookupOp(new ShortLookupTable(0, thresholdArray), null);
}
/*************************************************************************/
/** Init the components in the frame */
public HistogramViewer() {
createOps();
Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
Container contentPane = getContentPane();
Rectangle bounds = new Rectangle((screenSize.width - WINDOW_WIDTH)/2,
(screenSize.height - WINDOW_WIDTH)/2,
WINDOW_WIDTH, WINDOW_HEIGHT);
contentPane.setLayout(new java.awt.BorderLayout());
setBounds(bounds);
// initialize file selection dialog stuff
selectFileDialog = new javax.swing.JFrame();
selector = new javax.swing.JFileChooser();
loadFileButton = new javax.swing.JButton();
selector.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
selectorActionPerformed(evt);
}
});
selectFileDialog.getContentPane().add(selector, java.awt.BorderLayout.CENTER);
selectFileDialog.setBounds(bounds);
// set app to die if main window is closed
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent evt) { System.exit(0); }
});
// setup histogram graphs container
histogramContainer.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER));
histogramContainer.add(histogramComponent, null);
contentPane.add(histogramContainer, java.awt.BorderLayout.NORTH);
// setup images container
imageContainer.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER));
imageContainer.add(imageComponent, null);
contentPane.add(new JScrollPane(imageContainer), java.awt.BorderLayout.CENTER);
// setup load button
loadFileButton.setText("Load");
loadFileButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
selectFileDialog.show();
}
});
buttonContainer.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER));
buttonContainer.add(loadFileButton, null);
/******************************************************/
// Create a list of operations.
final Choice processChoice = new Choice();
Enumeration e = mOps.keys();
// Add all the operation names from the Hashtable.
while (e.hasMoreElements())
processChoice.add((String)e.nextElement());
// Add an event listener. This is where the image processing
// actually occurs.
processChoice.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent ie) {
if (ie.getStateChange() != ItemEvent.SELECTED) return;
String key = processChoice.getSelectedItem();
// statusLabel.setText("Working...");
BufferedImageOp op = (BufferedImageOp)mOps.get(key);
image = op.filter(image, null);
// statusLabel.setText("");
repaint();
}
});
buttonContainer.add(processChoice, null);
/*********************************************************************/
contentPane.add(buttonContainer, java.awt.BorderLayout.SOUTH);
}
/**
* First draw the color image which has been selected, and then make a grey image
* from the orginal image, and draw the grey image.
*/
public void loadFile() throws IOException {
// load image and make greyscale version
histoEqual.loadRGBArrays(); //get RGB data from original image
histoEqual.makeGreyImage(); //make out a grey image from original image
// apply histogram-equalization
histoEqual.performEqualization();
// update the imageComponent
imageComponent.clearImages();
imageComponent.addImage(histoEqual.getInputImage());
imageComponent.addImage(histoEqual.getGreyImage());
imageComponent.addImage(histoEqual.getEqualizedImage());
imageComponent.repaint();
// update the histogramComponent
histogramComponent.setHistograms(histoEqual.getNewHistogram(),
histoEqual.getOldHistogram());
histogramComponent.repaint();
}
/**
* Button in file selector is clicked, then load the selected image.
*/
private void selectorActionPerformed(java.awt.event.ActionEvent evt) {
imageFile = selector.getSelectedFile();
try {
selectFileDialog.dispose();
image = ImageIO.read(imageFile);
histoEqual.setInputImage(image);
loadFile();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
import java.net.*;
import java.awt.image.*;
import java.awt.*;
/*
* HistogramEqualizer.java
*
* Created on 01/05/2004, 11:51pm
* The algorithm and code are based on the "imageprocessing" package of "Java Image Processing API version 1"
*/
/** This is the class of the program
* @author ouyang
*/
public class HistogramEqualizer {
private static BufferedImage inputImage; //image object of input image
private static BufferedImage newImage; //image after histogram equalization
private static BufferedImage greyImage; //grey image of input image
private short[][] red; // array of red which is extracted from the image data
private short[][] green; // array of green which is extracted from the image data
private short[][] blue; // array of blue which is extracted from the image data
private int[] inputImageData; // data array of input image
private short[][] greyImageData; // data array of the image after being greyed
private short[][] equalizedImageData; // data array after histogram equalization
private double[] oldHistogram = new double[256]; // normalized histogram of grey image
private double[] newHistogram = new double[256]; // normalized histogram of equalized image
private double[] equalizedHistogram = new double[256]; // equalized histogram of equalized image
private int rows; // image height
private int cols; // image width
/**
* Get RGB inputImageData from image and change them into
* three color arrays, red, green, and blue.
*/
public void loadRGBArrays() {
// check if we need to resize the component arrays, i.e.,
// has the size of the image changed?
if (inputImage.getHeight() != rows || inputImage.getWidth() != cols) {
rows = inputImage.getHeight();
cols = inputImage.getWidth();
red = new short[rows][cols];
green = new short[rows][cols];
blue = new short[rows][cols];
}
// get pixels as ints of the form 0xRRGGBB
inputImageData = inputImage.getRGB(0, 0, inputImage.getWidth(),
inputImage.getHeight(), null, 0,
inputImage.getWidth());
// extract red, green, and blue components from each pixel
int index;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
index = (row * cols) + col;
unpackPixel(inputImageData[index], red, green, blue, row, col);
}
}
}
/** Make out a grey image "greyImageData" from original image. */
public void makeGreyImage() {
greyImageData = new short[rows][cols];
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
// grey value is average of red, green, and blue components, i.e.,
// grey = (red + green + blue) / 3
greyImageData[row][col] = (short)(( red[row][col]
+ green[row][col]
+ blue[row][col]) / 3);
}
}
greyImage = greyToBufferedImage(greyImageData);
}
/**
* This method can convert array of short inputImageDatatype into a BufferedImage.
* After being converted into type of BufferedImage, the image can be showed on
* GUI.
* @return a object of BufferedImage which is coverted from the input grey image data array
* @param inputGreyImageData The short[][] of grey image data
*/
public BufferedImage greyToBufferedImage(short[][] inputGreyImageData) {
int[] greyBufferedImageData = new int[rows * cols];
int index;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
index = (row * cols) + col;
greyBufferedImageData[index] = packPixel(inputGreyImageData[row][col],
inputGreyImageData[row][col],
inputGreyImageData[row][col]);
}
}
BufferedImage greyImage = new BufferedImage(cols, rows, BufferedImage.TYPE_INT_RGB);
greyImage.setRGB(0, 0, cols, rows, greyBufferedImageData, 0, cols);
return greyImage;
}
// performEqualization takes the greyImageData and creates
// the old and new histograms and the new image
public void performEqualization() {
createHistograms(greyImageData, oldHistogram, equalizedHistogram);
equalizedImageData = equalizeImage(greyImageData, equalizedHistogram);
createHistograms(equalizedImageData, newHistogram, null);
newImage = greyToBufferedImage(equalizedImageData);
}
/**
* Return the image data after histogram-equalization.
* This method applies the algorithm of histogram-equalization
* on the input image data.
* @return the image data histogram-equalized
* @param inputGreyImageData input grey image data need to be histogram-equalized
* @param equalizedHistogram equalized histogram of inputGreyImageData
*/
public short[][] equalizeImage(short[][] inputGreyImageData,
double[] equalizedHistogram) {
short[][] data = new short[rows][cols];
double s = 0;
for (int y = 0; y < rows; y++) {
for (int x = 0; x < cols; x++) {
//s += normalizedHistogram[inputGreyImageData[y][x]];
data[y][x] = (short) (equalizedHistogram[inputGreyImageData[y][x]] * 255);
}
}
return data;
}
/*
* Create normalized and equalized histograms of inputGreyImageData
* @param inputGreyImageData a grey image data
* @param normalizedHistogram used to return normalized histogram
* @param equalizedHistogram used to return equalized histogram
*/
public void createHistograms(short[][] inputGreyImageData,
double[] normalizedHistogram, double[] equalizedHistogram) {
int[] histogram = new int[256];
// count the number of occurences of each color
for (int y = 0; y < rows; y++) {
for (int x = 0; x < cols; x++) {
++histogram[inputGreyImageData[y][x]];
}
}
// normalize and equalize the histogram array
double sum = 0;
for (int v = 0; v < 256; v++) {
if (normalizedHistogram != null) {
normalizedHistogram[v] = (double) histogram[v] / (cols * rows);
}
if (equalizedHistogram != null) {
sum += histogram[v];
equalizedHistogram[v] = sum / (cols * rows);
}
}
}
// packPixel takes the red, green, and blue components
// of a color and returns a 24-bit representation of the
// the color, i.e., 0xRRGGBB
// red, green, and blue are assumed to be in the range 0 - 255
private static int packPixel(int red, int green, int blue) {
return (red << 16) | (green << 8) | blue;
}
// unpackPixel does the opposite of packPixel;
// it takes a 24-bit pixel in the form 0xRRGGBB
// and pulls out the three components, storing
// them position (row, col) or the red, green,
// and blue arrays
private static void unpackPixel(int pixel, short [][] red, short [][] green, short [][] blue, int row, int col) {
red[row][col] = (short)((pixel >> 16) & 0xFF);
green[row][col] = (short)((pixel >> 8) & 0xFF);
blue[row][col] = (short)((pixel >> 0) & 0xFF);
}
//****************************//
// Various Accessor Functions //
//****************************//
public BufferedImage getInputImage() { return inputImage; }
public BufferedImage getGreyImage() { return greyImage; }
public BufferedImage getEqualizedImage() { return newImage; }
public double [] getOldHistogram() { return oldHistogram; }
public double [] getNewHistogram() { return newHistogram; }
public void setInputImage(BufferedImage image) { inputImage = image; }
}
import java.awt.*;
/**
* Component to show the original histogram and resulting histogram.
*/
class HistogramComponent extends javax.swing.JComponent {
private double[] oldHistogram; // Histogram of image before histogram-equalization
private double[] newHistogram; // Histogram of image after histogram-equalization
public HistogramComponent() {
setPreferredSize(new Dimension(590, 150));
revalidate();
}
public void setHistograms(double[] newHistogram, double[] oldHistogram) {
this.oldHistogram = oldHistogram;
this.newHistogram = newHistogram;
}
/**
* Paint the histogram-equalized image and two histograms
*/
public void paint(Graphics g) {
drawHistogram(g, "Old Histogram", 15, 5, 125, 1, oldHistogram);
drawHistogram(g, "New Histogram", 320, 5, 125, 1, newHistogram);
}
/**
* Draw the histogram picture of input histogram
*
*@param g graphics object of current frame
* x the x coordinate of histogram image to be showed
* y the x coordinate of histogram image to be showed
* height the height of the histogram image
* space the space between two lines in the histogram.
*/
public void drawHistogram(Graphics g, String title, int x, int y,
int height, int space, double[] inputHistogram) {
double max = 0;
if (inputHistogram != null) {
for (int j = 0; j < 256; j++) {
if (inputHistogram[j] > max)
max = inputHistogram[j];
}
}
// set up font
g.setFont(new Font("Arial", Font.PLAIN, 11));
FontMetrics fm = g.getFontMetrics();
int ascent = fm.getAscent();
int lineHeight = fm.getHeight();
// draw title
int titleWidth = fm.stringWidth(title);
g.setColor(Color.black);
g.drawString(title, x + (256*space - titleWidth)/2, y + ascent);
y += lineHeight;
height -= lineHeight;
// draw background
Rectangle histRect = new Rectangle(x, y, 256*space, height);
g.setColor(Color.white);
g.fillRect(histRect.x, histRect.y, histRect.width, histRect.height);
// draw bars
g.setColor(Color.darkGray);
if (inputHistogram != null) {
for (int i = 0; i < 256; i++)
g.drawLine(x + ((i + 1) * space), y + height,
x + ((i + 1) * space),
y +
height - (int) (height * inputHistogram / max));
}
// draw vertical label
String vLabel = "" + ((double) (int) (max * 1000) / 10) + "%";
g.setColor(Color.red);
g.drawString(vLabel, x + 2, y + ascent);
// draw horizontal labels
g.setColor(Color.black);
g.drawString("256", (x + (space * 256)) - 8, y + height + ascent + 2);
g.drawString("128", (x + (space * 128)) - 8, y + height + ascent + 2);
g.drawString(" 0", (x + (space * 0)) - 8, y + height + ascent + 2);
}
}
import java.awt.*;
import java.util.LinkedList;
import java.awt.image.BufferedImage;
/**
* Component to show images
*/
class ImageComponent extends javax.swing.JComponent {
private LinkedList imageList = new LinkedList();
private LinkedList rectList = new LinkedList();
private static final int PADDING = 5;
public ImageComponent() {}
public void addImage(BufferedImage image) {
if (image == null)
return;
// add image to list
imageList.add(image);
rectList.add(new Rectangle(0, 0, image.getWidth(), image.getHeight()));
// update scroll bar
resizeScroller();
}
public void clearImages() {
// clear lists
imageList.clear();
rectList.clear();
// update scroll bar
resizeScroller();
}
// assuming we're inside a scrollbar view,
// resizeScroller updates our preferred size
// and tells the view to revalidate its bars
private void resizeScroller() {
Rectangle bounds = new Rectangle(0, 0, 0, 0);
// calculate bounds of images
for (int i = 0; i < imageList.size(); ++i) {
Rectangle rect = (Rectangle)rectList.get(i);
bounds.height = Math.max(bounds.height, rect.height);
bounds.width += rect.width;
}
bounds.width += PADDING * (imageList.size() + 1);
bounds.height += 2*PADDING;
setPreferredSize(bounds.getSize());
revalidate();
}
// paint the images
public void paint(Graphics g) {
int offset = PADDING;
for (int i = 0; i < imageList.size(); ++i) {
g.drawImage((BufferedImage)imageList.get(i), offset, PADDING, null);
offset += PADDING + ((Rectangle)rectList.get(i)).width;
}
}
}