Hello everybody,
In the following code, I’m trying to apply image processing operations performed in createOps() method but it doesn’t work !! Any help to know why it didn't work ?!
And here is the code:
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());
}
}
}
And here is the classes I used :
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;
}
}
}