| 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 |