Image processor (Java)
From LiteratePrograms
Contents |
Image Processor
This is a java program that performs graphical operations on an image. These operations are:
1)Reset the image
2)Invert the image colours
3)Gamma correction
4)Applying custom filters to the image
5)Convolution
6)Blue Fade
Using a GUI, users can select any image they wish to use.
For this program to work, users should save the image below to the directory that the source code is saved in.
This is a good program to learn java with as it introduces how to produce graphical user interfaces. It also demonstrates how the extensive java API can be implemented to the programmers benefit.
Defining the class
It is essential to define a class at the beginning of a java program, listing all the library classes that the program will use and defining any initial variables or fields. The class definition is below:
<<Defining the class>>= import java.awt.*; import java.awt.image.*; import java.io.*; import javax.imageio.*; import javax.swing.*; import java.awt.event.*; import java.util.ArrayList; import javax.swing.table.DefaultTableModel; public class ImageProcessor extends JFrame { JButton select_image_button, invert_button, gamma_button, convolve_button, reset_button, slow_gamma_button, fast_gamma_button; JButton box_3x3_button, box_5x5_button, box_6x4_button, gaussian_3x3_button, high_3x3_button, select_file_button; JButton custom_filter_button, select_size_button, execute_button; JTextField gamma_value_height, width_field; JTextField[][] filter_array; JLabel info_label, height_label, width_label, gamma_label, image_icon; BufferedImage image, orig_image; JFileChooser file_chooser; JTable filter_table; Container container; JPanel control_container, menu_container, option_container, top_container, bottom_container; int height = 1, width = 1; private final String INITIAL_IMAGE_FILE = "raytrace.jpg"; class body }
<<class body>>= Constructor Event Handler Return Pointer to Array Reset Invert Slow Gamma Fast Gamma File Filters Creating Custom Filter Convolution Blue fade Main
Because this program creates a graphical user interface (GUI), it requires
alot of import statements to import and use java library
classes in its implementation. What each class does and how thier
characteristics are described below:
java.awt.*- Contains all of the classes for creating user
interfaces and for painting graphics and images.
java.awt.image- An abstract class, image is the superclass of
all classes that represent graphical images.
java.io.*- Used for system input and output through data
streams, serialization and the file system.
javax.imageio.*- Provides a pluggable architecture for working
with images stored in files and accessed across the network.
javax.swing.*- Provides a set of lightweight GUI components
that, to the maximum degree possible, work the same on all platforms.
java.awt.event.*- Provides interfaces and classes for dealing
with different types of events created by AWT components.
java.util.ArrayList- Provides access to a library class which
can store an arbitrary number of elements, with each element being another
object.
javax.swing.table.DefaultTableModel- The TableModel interface
specifies the methods the JTable will use to interrogate a tabular data
model, this library class is an implementation of TableModel which uses a
Vector of Vectors to store the cell value objects.
When naming a class it is important to name it something that identifies
what it does or how it behaves. In this case the class is called
ImageProcessor because it processes images in a certain way.
Notice the code extends JFrame. This indicates
ImageProcessor is a subclass of the library class
Jframe. Essentially, this means ImageProcessor is
a Jframe. It inherits all the methods and behaviour of
Jframe but adds some of its own functionality, which will be
explained, along with the methods that provide this functionality.
The body of the class definition is taken up by defining the various components that are used to create the GUI. These components are described below, organised in groups of thier component type.
Component Type: JButton A button component that can cause
an event to occur when the user clicks on it.
Component Names:The select_image_button allows users to
select an image of thier choice from a certain location. The
invert_button invers the values of the image. The
gamma_button allows the user to perform gamma correction on the
image. The convolve_button allows users to apply convolution to
the image.The reset_button resets the image to its original
state. The slow_gamma_button performs gamma correction at a
slow rate. The fast_gamma_button performs gamma correction at a
fast rate. The box_3x3_button allows the user to apply a 3x3
blur filter to the image. The box_5x5_button allows the user to
apply a 5x5 blur filter to the image. The box_6x4_button button
allows the user to apply a 6x4 blur filter to the image. The
gaussian_3x3_button button allows the user to apply a 3x3
gaussian blur to the image. The high_3x3_button button applies
a high pass filter to the image. The select_file_button allows
users to select a file of thier choice. The filter_button
allows users to choose a filter of thier choice. When the user wishes to use
a filter of thier choice they must select a filter size. The
select_size_button allows them to do this. Once they have
selected a filter size and input values, the execute_button
applies the filter.
Component Type: JTextField. This is a text area on the
screen that users can input values into.
Component Names:The gamma_value_height field allows users
to enter a value to be used in the gamma correction, as does
width_field. Note that the filter_array is of type
JTextField [] []. This means it is a two dimensional array. The
purpose of this is to store information that will become apparant later in
the literate program.
Component Type: JLabel. This is used to display certain
information on the GUI.
Component Names: info_label, height_label,
width_label, gamma_label, image_icon
Component Type: BufferedImage. This is used to display
images in the GUI.
Component Names: image is used to represent the image
that the operations are going to be performed on. When the reset operation
is performed orig_image is used to return the image to its
original form.
Component Type: JFileChooser. This is a box that allows
the user to select a file from a location thier computer.
Component Name: file_chooser is used when the user
wishes to select a file.
Component Type: JTable. This is a table that can be used
in the GUI.
Component Name: filter_table. This is used when the user
wishes to apply a unique filter to the image.
Component Type: Container. This is used to contain all
the components that have been specified for the GUI.
Component Name: container. When the GUI has been created
this will be used to manage thier layout.
Component Type: JPanel. This is used when a number of
components need to be grouped together.
Component Name: control_container, menu_container, option_container, top_container, bottom_container
The height and width of the filter are also
defined and initialised to 1 in the body of the class definition.
Constructor
After defining all the components and fields that are going to be used in the program we must create instances of them so they can be used. This is achieved in the constructor of the class.
<<Constructor>>= public void ImageProcessor() throws IOException { container = getContentPane(); container.setLayout(new BorderLayout()); File image_file = new File(INITIAL_IMAGE_FILE); if (image_file.exists()) { image = ImageIO.read(image_file); orig_image = ImageIO.read(image_file); image_icon = new JLabel(new ImageIcon(image)); } else { image_icon=new JLabel(new ImageIcon()); } container.add(image_icon, BorderLayout.CENTER); control_container = new JPanel(new BorderLayout()); container.add(control_container, BorderLayout.SOUTH); info_label = new JLabel("Ready"); control_container.add(info_label, BorderLayout.NORTH); menu_container = new JPanel(new GridLayout(5, 1)); control_container.add(menu_container, BorderLayout.WEST); select_image_button = new JButton("Select Image"); menu_container.add(select_image_button); invert_button = new JButton("Invert"); menu_container.add(invert_button); gamma_button = new JButton("Gamma"); menu_container.add(gamma_button); convolve_button = new JButton("Convolve"); menu_container.add(convolve_button); reset_button = new JButton("Reset"); menu_container.add(reset_button); option_container = new JPanel(new BorderLayout()); control_container.add(option_container, BorderLayout.CENTER); top_container = new JPanel(new FlowLayout()); option_container.add(top_container, BorderLayout.NORTH); gamma_value_height = new JTextField(6); gamma_label = new JLabel("Gamma Value:"); height_label = new JLabel("Height:"); slow_gamma_button = new JButton("Slow Gamma"); fast_gamma_button = new JButton("Fast Gamma"); box_3x3_button = new JButton("3x3 Box"); box_5x5_button = new JButton("5x5 Box"); box_6x4_button = new JButton("6x4 Box"); gaussian_3x3_button = new JButton("3x3 Gaussian Blur"); high_3x3_button = new JButton("3x3 High Pass"); select_file_button = new JButton("Select File"); custom_filter_button = new JButton("Custom Filter"); width_field = new JTextField(6); width_label = new JLabel("Width:"); select_size_button = new JButton("Select Size"); execute_button = new JButton("Execute"); bottom_container = new JPanel(new FlowLayout()); option_container.add(bottom_container, BorderLayout.CENTER); file_chooser = new JFileChooser("Image Processor"); GUIEventHandler handler = new GUIEventHandler(); select_image_button.addActionListener(handler); invert_button.addActionListener(handler); gamma_button.addActionListener(handler); convolve_button.addActionListener(handler); reset_button.addActionListener(handler); slow_gamma_button.addActionListener(handler); fast_gamma_button.addActionListener(handler); box_3x3_button.addActionListener(handler); box_5x5_button.addActionListener(handler); box_6x4_button.addActionListener(handler); gaussian_3x3_button.addActionListener(handler); high_3x3_button.addActionListener(handler); select_file_button.addActionListener(handler); custom_filter_button.addActionListener(handler); select_size_button.addActionListener(handler); execute_button.addActionListener(handler); pack(); setLocationRelativeTo(null); setVisible(true); top_container.setVisible(false); bottom_container.setVisible(false); }
The most vital component of the GUI is the image that will be altered with
the methods of the class. The file raytrace.jpg is passed to a
field called image_file at the start of the constructor. This
is then passed to the BufferedImage image using the
read method of the ImageIO library class. A copy
is also created using the same method. This is called
orig_image and is used when we need to reset the image.
After the image has been read the GUI needs to be set up. To begin with, the
container needs to be initialised with the
getContentPane method. The GUI also needs a layout, which is
achieved by using the setLayout method. The
BorderLayout is used for this GUI.
The first element to be put in the container is the image. This is passed as
a JLabel and is called image_icon. After the image
has been passed, it needs to be placed in the container using
the add method of the awt library class. To place
it in a
position that is desired, the BorderLayout.CENTER is used. This
tells the compiler to place the image in the centre of the
container.
To have a user friendly interface the components of the container should be
properly laid out. This can be achieved by seperating the container into
seperate containers and applying individual layouts to each of them. The
first of the seperate containers is the control_container. This
is a JPanel and has a BorderLayout. This is then
added to the container using the add method of the
awt library class. It is placed in the bottom of the
container by using the code
BorderLayout.SOUTH. The control container will hold the menu
container, option container and information field.
The GUI should also have a label that indicates its status. This is called
info_label, which is a JLabel and is set to
"Ready". The label is added to the control_container using the
add method of the Container class. It is placed at
the top of control_container using the code
BorderLayout.NORTH. It is important to say that this label is
not placed at the top of the GUI, but at the top of the bottom container.
This example indicates the importance of using more than one container to
achieve a
user friendly interface.
Another container is required for the buttons that will be used in program.
This is called the menu_container. Again, the container is a
JPanel but it adopts the GridLayout layout. The
menu_container is added to the control_container
using the add method of the awt library class. It
is
placed to the left in the control_container by the code
BorderLayout.WEST.
The buttons select_image_button, invert_button,
gamma_button, convolve_button and
reset_button are then added to the menu_container
using the add method of the awt library class.
Each
button is a JButton.
There is a need for another container that holds different options for the
user depending on what buttons have been clicked, for example, if the
custom_filter_button is clicked there needs to be an empty
filter displayed. This container is a JPanel and is called
option_container. It is added to the
control_container using the add method of the
awt library class. This container adopts the
BorderLayout and is placed in the middle of the
control_container using the CENTRE code.
Inside the option_container are two containers. The first to be
intialised is the top_container. Again, this is a
JPanel and adopts the FlowLayout layout. It is
placed in the top of the option_container with the code
BorderLayout.NORTH.
The components that could be used in the top_container,
depending on the methods that are called, are then initialised. These are
gamma_value_height and width_field which are
JTextField components. gamma_label,
width_label and height_label are initialised,
which are JLabel components. There are also a number of
JButton components that could be used. These are
slow_gamma_button, fast_gamma_button,
box_3x3_button, box_5x5_button,
box_6x4_button, gaussian_3x3_button,
high_3x3_button, select_file_button,
custom_filter_button, select_size_button and
execute_button.
Another container is required for the filter table that could be used if the
custom filter method is called. This is a JPanel and is called
bottom_container. It adopts the FlowLayout layout
and is added to the option_container and placed in the middle
of it with the code BorderLayout.CENTER.
If the user wishes to select thier own image they need to use
aJFileChooser. This is initialised in the constructor and is
called file_chooser. It must have a directory for where the
files come from, which is passsed as a parameter when it is initialised.
Note that this directory is simply where the file chooser opens. In this
case the directory is E:\\ICCT\\Semester 4\\CS-217 Computer
Graphics 1\\Assignment1\\Example\\. This directory should be changed to a more suitable directory if the program is going to be run.
For the GUI to interact with the user there needs to be event handlers.
These essentially allow the component to respond to a users action. The
event handler in this case is called handler and is a
GUIEventHandler, which is defined later in the program. This
event handler must be 'placed' behind a button so they can react to the user
clicking on them, for example. This is achieved by calling the
addActionListener method of the GUIEventHandler
and passing handler as a parameter to each button, such as
the select_image_button button, for example.
Now that all the components are created, initialised and event handlers have
been set, the GUI needs to be displayed. This is achieved by using methods
of the swing library class. The first method that is used is
pack. This packs all the components together into an object.
The next method, setLocationRelativeTo, with a parameter
null allows the components to be placed with no relation to
other objects. To allow the user to see the components the
setVisible method is called, which is set to true
by the passing of a parameter. top_container and
bottom_container use the same method, but the parameter
false is passed, meaning they will not be displayed at this
time.
Event Handler
Now that each button has been initialised with an event handler it is important the event handler is defined. The method below defines the event handler.
<<Event Handler>>= private class GUIEventHandler implements ActionListener { public void actionPerformed(ActionEvent event) { info_label.setText("Ready"); if (event.getSource()==select_image_button) { Container parent = select_image_button.getParent(); file_chooser.showOpenDialog(parent); try { File image_file = file_chooser.getSelectedFile(); if (image_file.getName().endsWith(".jpg") == false && image_file.getName().endsWith(".jpeg") == false) { throw new IOException(); } image = ImageIO.read(image_file); orig_image = ImageIO.read(image_file); image_icon.setIcon(new ImageIcon(image)); } catch (NullPointerException e) { info_label.setText("ERROR: No File Selected"); } catch (IOException e) { info_label.setText("ERROR: File Must Be Of Type .jpg Or .jpeg"); } } invert button event handler gamma button event handler convolve button event handler reset button event handler slow gamma button event handler fast gamma button event handler box 3x3 button event handler box 5x5 button event handler box 6x4 button event handler gaussian 3x3 button event handler high pass 3x3 button event handler select file button event handler custom filter button event handler select size button event handler execute button event handler } }
Notice that the GUIEventHandler is a private
class. This means that it cannot be seen by other classes. It also
implements ActionListener, which means it takes some of the
behaviour from the ActionListener and adds some functionality of its own.
The first and only method of the GUIEventHandler class is
called actionPerformed. The method signature shows it is of
return type void, which means it returns nothing. The method
takes a parameterevent of type ActionEvent, which
is part of the awt library class.
The method body begins by setting the value of info_label to
ready. This is achieved by using the setText method of the
swing library class.
The remainder of the method body involves a number of checks to see which
button has been clicked. An if statement is used to check what
button is clicked by calling the getSource method of the
ActionEvent library class. The result is then compared to each
button, if the result matches the button name, the following statement is
executed. If the result doesnt match the button name, the next else
if statement is executed to compare a different button name. This
process is repeated everytime a button is pressed.
The first button to be checked is the select_image_button
button. If the result of the getSource method call is equal to
the select_image_button the getParent method is
called. This is part of the awt library class which gets the
parent of the button, which in this case in the container it is
in.
The next statement tries to open the file_chooser dialog box by
calling the showOpenDialog method of the swing
library class. The parent container is passed as a paramter to
this method call. Once the dialog box has been opened, the method tries to
get the file that the user selects. This utilises a try-catch
block. The first part of this is a try section, which basically
attempts something that could result in an exception, which is undesirable
and needs to be caught in a catch statement. In this case the
try statement attempts to get the file that has been selected
by the user. This is achieved by calling the getSelectedFile
method of the swing library class and passing the result to the
variable image_file. The user then has the opportunity to
select any file type they want, which could cause problems as the program
can only deal with jpg image types. This means the program should perform a
check on the file name. This check is performed in an if statement that
calls the methods getName of the swing library class and
endsWith of the lang library class to check if the
extension of the file chosen is jpg or jpeg. If this check returns
false an IOException is thrown. This is caught in
a catch block which calls the setText method of
the swing library class to change the value of
info_label so it displays an error message informing the user
that the file type must be of jpg or jpeg.
If the check returns a true result, the image is opened and read into the
image variable, which is a BufferedImage. The
method read of the ImageIO library class allows
this to occur. It takes the image_file field as a parameter and
stores it in the BufferedImage variable. There may be a time
where the image needs to be reset, so the same procedure is repeated and the
result is stored in the orig_image variable so there is a copy
that can be used to reset the image. The image that is displayed in the GUI
then needs to be updated, so the setIcon method is called,
taking the image file as a parameter. This new image then
replaces the image_icon variable, meaning the image displayed
on the GUI is replaced.
<<invert button event handler>>= else if (event.getSource()==invert_button) { image=Invert(image); image_icon.setIcon(new ImageIcon(image)); } gamma button event handler
If the result of getSource method doesnt match the value of
theselect_image_button, the result is checked against the value
of the invert_button. If the results are equal, the
Invert method of the ImageProcessor is called to
manipulate the image. What this method does will be explained later in the
literate program. The result is then stored in the image
variable. The setIcon method of the swing is used
to update the GUI componentimage_icon.
<<gamma button event handler>>= else if (event.getSource()==gamma_button) { top_container.setVisible(false); bottom_container.setVisible(false); top_container.removeAll(); bottom_container.removeAll(); top_container.add(gamma_label); top_container.add(gamma_value_height); gamma_value_height.setText("1"); top_container.add(slow_gamma_button); top_container.add(fast_gamma_button); top_container.setVisible(true); } convolve button event handler
If the previous check was unsuccesful, the gamma_button value
is checked. If the result of gamma_button matches the result of
the getSource method the GUI is re-organised to allow for the
gamma options. To add new icons to a container, it needs to be
emptied and the new components need to be added to it once its empty. The
top_container and bottom_container are made
invisible by passing a false parameter to the
setVisible method of the swing library class. The
components of each container are removed by calling the
removeAll method of the swing library class. Once
the containers are empty, new components are added to them using the
add method of the swing library class. These
components are gamma_label and gamma_value_height. The
setText method of the awt library class is called
to set the value of gamma_value_height to 1. The components
slow_gamma_button and fast_gamma_button are then
added to top_container by calling the add method
of the swing library class. All the new components of the
top_container are displayed by calling the
setVisible method of the swing library class and
passing a true parameter to it.
<<convolve button event handler>>= else if (event.getSource()==convolve_button) { top_container.setVisible(false); bottom_container.setVisible(false); top_container.removeAll(); bottom_container.removeAll(); top_container.add(box_3x3_button); top_container.add(box_5x5_button); top_container.add(box_6x4_button); top_container.add(gaussian_3x3_button); top_container.add(high_3x3_button); bottom_container.add(select_file_button); bottom_container.add(custom_filter_button); top_container.setVisible(true); bottom_container.setVisible(true); } reset button event handler
If the previous check was unsuccesful, the result of getSource
is checked against the value of convolve_button. If these are
equal, the GUI needs to be re-organised to accomodate the convolution
components. The top_container and bottom_container
are made invisible and emptied in the same manor as described above. The
buttons are then added to the top_container by calling the
add method of the swing library class. These
buttons are box_3x3_button, box_5x5_button,
box_6x4_button, gaussian_3x3_button,
high_3x3_button. The same is repeated for
bottom_container, adding the select_file_button
and the customer_filter_button buttons. The new components are
then displayed by calling the setVisible method and passing
true as a parameter.
<<reset button event handler>>= else if (event.getSource()==reset_button) { image=Reset(image); image_icon.setIcon(new ImageIcon(image)); } slow gamma button event handler
The result of the method call getSource is then checked against
the value of reset_button, providing the previous check was
unsuccseful. If the result is equal to the value of
reset_button, the Reset method of the
ImageProcessor class is then called. What this method does is
explained later in the literate program. The result of this method is then
stored in the image variable. The new value of
image is then passed as a parameter to the setIcon
of the swing library class, which updates the
image_icon GUI component.
<<slow gamma button event handler>>= else if (event.getSource()==slow_gamma_button) { image=SlowGamma(image); image_icon.setIcon(new ImageIcon(image)); } fast gamma button event handler
If the results of the previous comparison are equal, the next button to be
tested against the result of getSource is the
slow_gamma_button. If the values match, the
SlowGamma method of the ImageProcessor class is
called. This takes the image variable as a parameter, processes
it in some way and returns a new version of the image. The processing of
this method will be descibred later in the literate program. The new result
is stored in the image variable, which is then passed as a
parameter to the setIcon method of the swing
library class, which updates the image_icon GUI component.
<<fast gamma button event handler>>= else if (event.getSource()==fast_gamma_button) { image=FastGamma(image); image_icon.setIcon(new ImageIcon(image)); } box 3x3 button event handler
If the result of getSource doesnt match the value of
slow_gamma_button, it is compared with the value of
fast_gamma_button. If the result matches the value of the
button, the FastGamma method is called. This method is part of
the ImageProcessor class and it takes the image
variable as a parameter. The method does some processing, which is described
later in the literate program and returns the new value of the image variable. This new value is stored in theimage variable, which is passed as a parameter to the setIcon method of the swing
library class. This is used to update the image_icon GUI
component.
<<box 3x3 button event handler>>= else if (event.getSource()==box_3x3_button) { height = 3; width = 3; int[][] filter = new int[height][width]; int j, i; for (j = 0; j < height; j ++) { for (i = 0; i < width; i++) { filter[j][i] = 1; } } image=Convolve(image, filter, width, height); image_icon.setIcon(new ImageIcon(image)); } <<box 5x5 button event handler>>=
If the previous check was unsucessful, the next value to be checked is the
value of the box_3x3_button. If the result of
getSource is equal to the value, the variables
height and width are set to 3. This represents the
size of the filter that is going to be used, ie 3x3. These values are used
to represent elements of an array of type int. This array is
called filter. A for loop is created, which uses
loop variables j and i. These loop variables are
used to iterate through the array until the size of height and
weight are reached, in this case 3 for both variables. After
the initialising and defining the array, the method Convolve is
called. The fields image, filter,
width and height are passed as parameters. The method
applies some processing that will be explained later in the literate program
and updates the image variable with the new result. The updated
image variable is then passed as a parameter when the
setIcon method of the swing library class is
called to update the image_icon GUI component.
<<box 5x5 button event handler>>= else if (event.getSource()==box_5x5_button) { height = 5; width = 5; int[][] filter = new int[height][width]; int j, i; for (j = 0; j < height; j ++) { for (i = 0; i < width; i++) { filter[j][i] = 1; } } image=Convolve(image, filter, width, height); image_icon.setIcon(new ImageIcon(image)); } box 6x4 button event handler
If the previous check was unsuccesful, the result of getSource
is checked against the value of box_5x5_button. If the values
are equal, the variables height and width are set
to the value of 5. The new values are then used to set the size of the array
filter. A for loop is created, which uses loop
variables j and i. These loop variables are used
to iterate through the array until the size of height and
weight are reached, in this case 5 for both variables. After
the initialising and defining the array, the method Convolve is
called. The fields image, filter,
width, height are passed as parameters. The method
applies some processing that will be explained later in the literate program
and updates the image variable with the new result. The updated
image variable is then passed as a parameter when the
setIcon method of the swing library class is
called to update the image_icon GUI component.
<<box 6x4 button event handler>>= else if (event.getSource()==box_6x4_button) { height = 6; width = 4; int[][] filter = new int[height][width]; int j, i; for (j = 0; j < height; j ++) { for (i = 0; i < width; i++) { filter[j][i] = 1; } } image=Convolve(image, filter, width, height); image_icon.setIcon(new ImageIcon(image)); } gaussian 3x3 button event handler
The next button to be compared against the result of getSource
is the box_6x4_button button. If the result matches the value,
the value of height is set to 6 and the value of
width is set to 4. The new values are then used to set the size
of the array filter. A for loop is created, which
uses loop variables j and i. These loop
variables are used to iterate through the array until the size of
height and weight are reached, in this case 6 and
4 for each variable, respectively. After the initialising and defining the array,
the methodConvolve is called. The fields image,
filter, width and height are passed as
parameters. The method applies some processing that will be explained later
in the literate program and updates the image variable with the
new result. The updated image variable is then passed as a
parameter when the setIcon method of the swing
library class is called to update the image_icon GUI component.
<<gaussian 3x3 button event handler>>= else if (event.getSource()==gaussian_3x3_button) { height = 3; width = 3; int[][] filter = new int[height][width]; filter[0][0] = 1; filter[0][1] = 3; filter[0][2] = 1; filter[1][0] = 3; filter[1][1] = 9; filter[1][2] = 3; filter[2][0] = 1; filter[2][1] = 3; filter[2][2] = 1; image=Convolve(image, filter, width, height); image_icon.setIcon(new ImageIcon(image)); } high pass 3x3 button event handler
If the previous check was unsuccesful, the result of the
getSource method call is compared to the value of
gaussian_3x3_button. If these values are equal, the value of
height and width are set to the value of 3. Each
element of the array is set to a certain value, in this case, the filter
that is going to be appiled to the image is a gaussian 3x3 filter, so the
array elements each represent one value in the filter ie 1,3,1,3,9,3,1,3,1.
After the initialising and defining the array, the
methodConvolve is called. The fields image,
filter, width and height are passed as
parameters. The method applies some processing that will be explained later
in the literate program and updates the image variable with the
new result. The updated image variable is then passed as a
parameter when the setIcon method of the swing
library class is called to update the image_icon GUI component.
<<high pass 3x3 button event handler>>= else if (event.getSource()==high_3x3_button) { height = 3; width = 3; int[][] filter = new int[height][width]; filter[0][0] = -1; filter[0][1] = -1; filter[0][2] = -1; filter[1][0] = -1; filter[1][1] = 8; filter[1][2] = -1; filter[2][0] = -1; filter[2][1] = -1; filter[2][2] = -1; image=Convolve(image, filter, width, height); image_icon.setIcon(new ImageIcon(image)); } <<select file button event handler>>=
If the check of getSource result and the previous button was
unsuccesful, the result of the getSource method call is
compared to the value of high_3x3_button. If these values are
equal, the value of height and width are set to
the value of 3. Each element of the array is set to a certain value, in this
case, the filter that is going to be appiled to the image is a high pass 3x3
filter, so the array elements each represent one value in the filter ie -1,
-1, -1, -1, 8, -1, -1, -1, -1. After the initialising and defining the
array, the method Convolve is called. The fields
image, filter, width,
height are passed as parameters. The method applies some
processing that will be explained later in the literate program and updates
the image variable with the new result. The updated
image variable is then passed as a parameter when the
setIcon method of the swing library class is
called to update the image_icon GUI component.
<<select file button event handler>>= else if (event.getSource()==select_file_button) { Container parent = select_file_button.getParent(); file_chooser.showOpenDialog(parent); try { File filter_file = file_chooser.getSelectedFile(); if (filter_file.getName().endsWith(".filt") == false) { throw new IOException(); } ArrayList filter_info = FileFilterArray(filter_file); int[][] filter = (int[][])filter_info.get(0); int[] dimentions = (int[])filter_info.get(1); width = dimentions[0]; height = dimentions[1]; image=Convolve(image, filter, width, height); image_icon.setIcon(new ImageIcon(image)); } catch (NullPointerException e) { info_label.setText("ERROR: No File Selected"); } catch (IOException e) { info_label.setText("ERROR: File Must Be Of Type .filt"); } } custom filter button event handler
The next button to be compared against the result of the
getSource is select_file_button. If the values
match, the parent container is obtained by calling the
getParent method of the awt library class. The
result is stored in a field parent which is of type
Container. This field is passed as a parameter to the
showOpenDialog method of the swing library class.
This is called to open the file_chooser window. Once the
file_chooser window is open a try block is used to
attempt to get the selected filter, this is achieved by calling the
getSelectedFile of the swing library class. The
result of this method call is passed to the field filter_file,
which is of type File. A check is then performed on the file
type of filter_file by calling the methods getName
and endsWith of the library class lang. If the result
of these method calls isnt .filt then an
IOException is thrown. This is dealt with in a
catch block that calls the setText method of the
awt library class to change the value of
info_label to inform the user a .filt file is
needed.
If the file is of the correct type, the FileFilterArray method
of the image_processor class is called, passing the
filter_file as a parameter. This method creates a filter from a
file. The result of the method call is stored in a field called
filter_info, which is of type ArrayList. Before
passing the fields image, filter, width and height as
parameters to the Convolve method, the values in the filter
need to be seperated from the dimensions of the filter. This is achieved by
calling the get method of the ArrayList library
class to retrieve the information of filter_info. The results
are then cast using the (int[] []),to turn the information into
type two dimensional array. This makes it compatible with the two dimesional
array. The first element of filter_info is the values of the
filter. These values are stored in the two dimensional array
filter. The second element of the filter_info is
the dimensions of the filter. These are stored in the one dimensional array
dimentions. The values of the first two elements of
dimentions are then stored in width and
height, repectively.
Now that the values of the filter_info have been seperated,
they can be passed to the Convolve method of the
ImageProcessor class, which provides some form of image
processing that will be described later in the literate program. The result
of this method is stored in the image field, which is then
passed as a parameter to the setIcon of the swing
library class. This method is used to update the GUI component
image_icon to the new value of image.
<<custom filter button event handler>>= else if (event.getSource()==custom_filter_button) { top_container.setVisible(false); bottom_container.setVisible(false); top_container.removeAll(); bottom_container.removeAll(); top_container.add(height_label); top_container.add(gamma_value_height); gamma_value_height.setText("1"); top_container.add(width_label); top_container.add(width_field); width_field.setText("1"); top_container.add(select_size_button); top_container.add(execute_button); execute_button.setEnabled(false); top_container.setVisible(true); } select size button event handler
The custom_filter_button is then checked against the result
ofgetSource providing the previous results do not match. If
these results are equal, the GUI needs to be reorganised to accomodate the
custom filter. The setVisible function of the awt
library class is called, with a false value as a parameter to
make the top_container and bottom_container
invisible. Thier contents are then removed with a method call of
removeAll, which is part of the awt library class.
The new components are then added by calling the add method of
the awt library class. Each component to be added is passed as
a parameter to this method, these components are height_label,
gamma_value_height, width_label,
width_field, select_size_button and
execute_button. The setText method of the
awt is called to set the text of width_field and
gamma_value_height to 1. The execute_button is
disabled by calling the setEnabled method of the
awtlibrary class and passing false as a parameter.
Once all the components are added, the setVisible method is
called, with true passed as a parameter. This displays the new
components of the top_container on the GUI.
<<select size button event handler>>= else if (event.getSource()==select_size_button) { bottom_container.setVisible