Lookup tables provide a very flexible approach to transforming
the colors of an image. One can use a lookup table filter, for example,
to create a negative of the source image.
The LookupOp
filter uses an instance of LookupTable
(or, actually, one of its two subclasses) to map source pixels to
destination pixels according to the source pixel component values.
(Note that this filter can not be used with indexed color model
images.)
So, for example, the 8 bits of the red component for an RGB pixel
would need a table of up to 256 elements, each holding a value for
the corresponding red component in the destination pixel. You can
provide one table used by all three components or separate tables
for each. (Four table for ARGB pixels.)
There are two subclasses of the abstract LookupTable.
The ByteLookupTable
and the ShortLookupTable
essentially offer the same features except for the type of arrays.
Each offers a constructor for creating a single table for all color
components and a constructor for creating multiple tables, one for
each color component.
The following table shows how to can create a table that selects
only colors above a given threshold:
short[] threshold = new short[256];
for (int i = threshold_level; i < 256; i++)
threshold[i] = (short) i;
LookupTable threshold_table = new ShortLookupTable
(0, threshold);
LookupOp threshold_op = new LookupOp (threshold_table,
null);
fDstImage = threshold_op.filter (fSrcImage,
null);
The program LookupTableApplet
shown below demonstrates the above technique. The threshold_op
filter is applied to the source image with
a user selected threshold level.
LookupTableApplet
Resources: saturn.jpg,
saturnVoyager.jpg
|
import
javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import javax.swing.event.*;
/** Demonstrate using a lookup table to provide a threshold
filter.**/
public class LookupTableApplet extends JApplet
implements
ChangeListener {
BufferedImage fSrcImage, fDstImage;
ImageIcon fDstIcon;
JLabel fThresLabel;
JSlider fThresSlider;
/**
* Build the interface with the source and
filter output image
* displayed side by side.
**/
public void init () {
setLayout (new BorderLayout ());
fSrcImage = getBufImage ("saturnVoyager.jpg");
if (fSrcImage == null) {
System.out.println
("Error in reading image file!");
return;
}
JPanel control_panel = new JPanel();
control_panel.add (fThresLabel =
new
JLabel ("Threshold 100 ",SwingConstants.RIGHT) );
control_panel.add (fThresSlider =
new
JSlider (Adjustable.HORIZONTAL, 0, 255, 100));
fThresSlider.addChangeListener (this);
// Filter image with an initial value
for threshold
thresholdFilter (100);
// Use ImageIcon objects to hold the
two images
ImageIcon src_icon = new ImageIcon
(fSrcImage);
fDstIcon = new ImageIcon (fDstImage);
// Put the icons on labels
JLabel src_display = new JLabel (src_icon);
JLabel dst_display = new JLabel (fDstIcon);
// And then display the labels on
the scroll panes
JScrollPane src_pane = new JScrollPane
(src_display);
JScrollPane dst_pane = new JScrollPane
(dst_display);
// Use a JSplitPane to show the source
and destination
// images side by side.
JSplitPane split_pane =
new JSplitPane (JSplitPane.HORIZONTAL_SPLIT,
true, src_pane, dst_pane);
split_pane.setResizeWeight (0.5);
split_pane.setContinuousLayout (true);
// Add the DrawingPanel to the contentPane.
add (split_pane, BorderLayout.CENTER);
add (control_panel, BorderLayout.SOUTH);
} // init
/**
* This class implements ChangeListener
for the
* slider. So the ChangeEvents come
here when the
* slider is moved.
**/
public void stateChanged (ChangeEvent evt) {
// Use the labels to show the numerical
values of the
// scroll bar settings.
fThresLabel.setText ("Threshold "
+
Integer.toHexString (fThresSlider.getValue ()));
// Get the values from the slider
and set a new threshold
thresholdFilter (fThresSlider.getValue
());
// Reset the destination images with
the modified version.
fDstIcon.setImage(fDstImage);
// Repaint to show the modified image.
repaint ();
} // stateChanged
/** Create the filter to execute a threshold setting
on the
* color component values.
**/
void thresholdFilter (int threshold_level) {
short[] threshold = new short[256];
for (int i = threshold_level; i <
256; i++)
threshold[i] = (short)
i;
LookupTable threshold_table = new
ShortLookupTable (0, threshold);
LookupOp threshold_op = new LookupOp
(threshold_table, null);
fDstImage = threshold_op.filter (fSrcImage,
null);
} // thresholdFilter
/**
* Download the image file and convert
to a
* BufferedImage object.
*/
BufferedImage getBufImage (String image_name){
// Get the image
Image img = getImage (getCodeBase(),
image_name);
// and use a MediaTracker to load
it before converting it to
// a BufferedImage.
try {
MediaTracker tracker =
new MediaTracker (this);
tracker.addImage (img,0);
tracker.waitForID (0);
} catch (InterruptedException e) {
return null; }
int width = img.getWidth (this);
int height= img.getHeight (this);
BufferedImage buffered_image =
new BufferedImage (width,
height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = buffered_image.createGraphics
();
g2.drawImage (img,0 ,0, null);
return buffered_image;
} // getBufImage
} // class LookupTableApplet
|
You can invert the colors of the source image by creating an array
of size 256 and filling the first element with the value 256 and
then decreasing by one in each element until reaching 0 in the last
element.
If we wanted to apply the above threshold filter to only
the red component and leave the other color components unchanged,
we need to create a two dimensional array to hold the threshold
array plus an identity array that leaves the other components unchanged.
short[] identity = new short[256];
for (int i = 0; i < 256; i++) identity[i] = (short)
i;
short[][] red_threshold = {threshold, identity, identity};
LookupTable red_threshold_table = new ShortLookupTable
(0, red_threshold);
LookupOp red_threshold_op = new LookupOp (red_threshold_table,
null);
BufferedImage dest_image = red_threshold_op.filter (source_image,
null);
The following program LookupTableOneColorApplet
is the same as the above applet except that the red_threshold_op
filter is used on the source image.
LookupTableOneColorApplet
Resources: saturn.jpg,
saturnVoyager.jpg
|
import
javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import javax.swing.event.*;
/**
* Demonstrate using a lookup table to provide
a threshold filter
* on a single color component.
**/
public class LookupTableOneColorApplet extends JApplet
implements
ChangeListener {
BufferedImage fSrcImage, fDstImage;
ImageIcon fDstIcon;
JLabel fThresLabel;
JSlider fThresSlider;
/**
* Build the interface with the source
and filter output image
* displayed side by side.
**/
public void init () {
... Same as LookupTableApplet
...
/** Create the filter to execute a threshold
setting on the
* color component values.
**/
void thresholdFilter (int threshold_level) {
short[] threshold = new short[256];
for (int i = threshold_level; i
< 256; i++)
threshold[i] = (short)
i;
short[]
identity = new short[256];
for (int i = 0; i < 256; i++) identity[i]
= (short) i;
short[][] red_threshold = {threshold,
identity, identity};
LookupTable red_threshold_table
=
new ShortLookupTable (0,
red_threshold);
LookupOp red_threshold_op = new
LookupOp (red_threshold_table, null);
fDstImage
= red_threshold_op.filter (fSrcImage,
null);
} // thresholdFilter
...
Same as LookupTableApplet ...
} // class LookupTableOneColorApplet
|
There are obviously many such lookup table transforms you can create.
Note that in-place filtering (i.e. destination image can be the
same as the source image) can be done with the LookupOp
filter.
References & Web Resources
Latest update: March 8, 2006
|