76
Digital Image Processing (using Java) (p.22) java ResolutionSimulator mathead.png low spatial frequency = coarsely-sampling Nyquist criterion: sampling freq 2 * (highest spatial freq.) Effect of aliasing – do not meet Nyquist criterion e.g. Fig3.2 (a) & (b) Fig3.4 (b) - 1 -

Digital Image Processing Java3

  • Upload
    stkim

  • View
    133

  • Download
    3

Embed Size (px)

Citation preview

Page 1: Digital Image Processing Java3

Digital Image Processing (using Java)

(p.22)

java ResolutionSimulator mathead.png

low spatial frequency = coarsely-sampling

Nyquist criterion: sampling freq ≧ 2 * (highest spatial freq.)

Effect of aliasing – do not meet Nyquist criterion

e.g. Fig3.2 (a) & (b) Fig3.4 (b)

- 1 -

Page 2: Digital Image Processing Java3

(p.24)

anti-aliasing → a process that meets the Nyquist Criterion

(p.26)

- 2 -

Page 3: Digital Image Processing Java3

java LogPolar matthead.png 256 256

java QuantisationSimulator matthead.png

(p.29)

- 3 -

Page 4: Digital Image Processing Java3

(p.30)

- 4 -

Page 5: Digital Image Processing Java3

(p.31)

HSICalc.java: RGB → HIS

(0~255) (0~1)

LISTING 3.1 A program to convert RGB colours into values of hue, saturation and

intensity. A conversion method from Java’s Color class is used.

import java.awt.Color;

import java.text.DecimalFormat;

public class HSICalc {

public static void main(String[] argv) {

if (argv.length > 2) {

int[] rgb = new int[3];

for (int i = 0; i < 3; ++i)

rgb[i] = Integer.parseInt(argv[i]);

float[] values = Color.RGBtoHSB(rgb[0], rgb[1], rgb[2], null);

String[] labels = { "H=", "S=", "I=" };

DecimalFormat floatValue = new DecimalFormat("0.000");

for (int i = 0; i < 3; ++i)

System.out.println(labels[i] + floatValue.format(values[i]));

}

else {

System.err.println("usage: java HSICalc <r> <g> <b>");

System.exit(1);

}

}

}

- 5 -

Page 6: Digital Image Processing Java3

(p.34)

(p.36)

java Limits

LISTING 3.2 Program to print limits for the primitive types. The limits are defined as

static constants in the standard Java ‘wrapper’ classes Byte, Short, Integer, Float

and Double.

public class Limits {

public static void main(String[] argv) {

java.io.PrintStream s = System.out;

s.println("Min byte value = " + Byte.MIN_VALUE);

s.println("Max byte value = " + Byte.MAX_VALUE);

s.println("Min short value = " + Short.MIN_VALUE);

s.println("Max short value = " + Short.MAX_VALUE);

s.println("Min int value = " + Integer.MIN_VALUE);

s.println("Max int value = " + Integer.MAX_VALUE);

s.println("Min float value = " + Float.MIN_VALUE);

s.println("Max float value = " + Float.MAX_VALUE);

s.println("Min double value = " + Double.MIN_VALUE);

s.println("Max double value = " + Double.MAX_VALUE);

}

}

- 6 -

Page 7: Digital Image Processing Java3

(p.37)

(p.37)

- 7 -

Page 8: Digital Image Processing Java3

(p.38)

(p.39)

- 8 -

Page 9: Digital Image Processing Java3

(p.40)

- 9 -

Page 10: Digital Image Processing Java3

(p.41)

(p.42)

LISTING 3.3 Example of polymorphism.

public class Mean {

public static void print1 (ByteImage image){

System.out.println (“mean value is “ + image.getMeanValue());

}

public static void print2 (BaseImage image){

System.out.println (“mean value is “ + image.getMeanValue());

}

public static void print3 (BaseArray array){

System.out.println (“mean value is “ + array.getMeanValue());

}

}

- 10 -

Page 11: Digital Image Processing Java3

(p.79)

usage: java convert infile outfile

LISTING 5.6 A simple image format conversion program.

public class Convert {

public static void main(String[] argv) {

if (argv.length > 1) {

try {

ImageDecoder input = ImageFile.createImageDecoder(argv[0]);

BufferedImage image = input.decodeAsBufferedImage();

ImageEncoder output = ImageFile.createImageEncoder(argv[1]);

output.encode(image);

System.exit(0);

}

catch (Exception e) {

System.err.println(e);

System.exit(1);

}

}

else {

System.err.println("usage: java Convert <infile> <outfile>");

System.exit(1);

}

}

}

(p.85)

usage: java Display imagefile

LISTING 5.9 A simple image display application using Swing components.

import java.awt.*;

import java.awt.image.*;

import javax.swing.*;

import com.pearsoneduc.ip.io.*;

public class Display extends JFrame{

public Display (String filename){

super (filename);

ImageDecoder input = ImageFile.createImageDecoder (filename);

BufferedImage image = input.decodeAsBufferedImage();

- 11 -

Page 12: Digital Image Processing Java3

Jlabel view = new Jlabel (new ImageIcon (image));

getContentPane().add(view);

addWindowListener (new WindowEvent event){

public void windowClosing (WindowEvent event){

System.exit(0);

}

});

}

public static void main (String[] argv){

if (argv.length > 0){

try {

JFrame frame = new Display (argv[0]);

frame.pack();

frame.setVisible (true);

}

catch (Exception e){

System.err.println (e);

System.exit (1);

}

}

else {

System.err.println (“usage: java Display imagefile”);

System.exit (1);

}

}

}

(p.86)

usage: java ImageViewer matthead.png

LISTING 5.10 A Swing component to display images.

import java.awt.*;

import java.awt.image.*;

import javax.swing.*;

public class ImageView extends JLabel implements Scrollable{

private BufferedImage image; //image to be displayed

private Dimension viewSize; //size of view, if in a JScrollPane

- 12 -

Page 13: Digital Image Processing Java3

public ImageView (BufferedImage img){

image = img;

int width = Math.min (256, image.getWidth());

int height = Math.min (256, image.getHeight());

viewSize = new Dimension (width, height);

setPreferredSize (new Dimension (image.getWidth(), image.getHeight()));

}

public void paintComponent (Graphics g){

g.drawImage (image, 0, 0, this);

}

public void setViewSize (Dimension newSize){

viewSize.setSize (newSize);

}

public Dimension getPreferredScrollableViewportSize(){

return viewSize;

}

public int getScrollableUnitIncrement (Rectangle rect, int orient, int dir){

return 1;

}

public int getScrollableBlockIncrement (Rectangle rect, int orient, int dir){

if (orient == SwingConstants.HORIZONTAL)

return image.getWidth() / 10;

else

return image.getHeight() / 10;

}

public boolean getScrollableTracksViewportWidth(){

return false;

}

public boolean getScrollableTracksViewportHeight(){

return false;

}

}

- 13 -

Page 14: Digital Image Processing Java3

(p.88)

halftoning: gray → binary

1. patterning-replacing each pixel by a pattern taken from a ‘binary font’.

(e.g.: fig 5.10)

2. Dithering:

Java Dither matthead.png

3. Error diffusion:

Java ErrorDiffustion matthead.png

- 14 -

Page 15: Digital Image Processing Java3

(p.92)

ALGORITHM 5.1 Dithering BY Floyd-Steinberg error diffusion.

threshold = (black + white) /2

for all x and y do

if ƒ (x, y) < threshold then

g (x, y) = black

ε = ƒ (x, y) – black

else

g (x, y) = white

ε = ƒ (x, y) – white

end if

ƒ (x+1, y) = ƒ (x+1,y) + 7ε/16

ƒ (x-1, y+1) = ƒ (x-1, y+1) + 3ε/16

ƒ (x, y+1) = ƒ (x,y+1) + 5ε/16

ƒ (x+1, y+1) = ƒ (x+1, y+1) + ε/16

end for

(p.93)

LISTING 5.12 Java implementation of Algorithm 5.1

public static BufferedImage errorDiffusion (BufferedImage image) {

// Create a binary output image (0=black, 1=white)

int w = image.getWidth()-1;

int h = image.getHeight()-1;

outputImage = new BufferedImage(w, h, bufferedImage.TYPE_BYTE_BINARY);

- 15 -

Page 16: Digital Image Processing Java3

// Copy input image because error diffusion modifies it

WritableRaster input = image.copyData(null);

WritableRaster output = outputImage.getRaster();

final int threshold = 128;

int value, error;

for (int y = 1; y < h; ++y)

for (int x = 1; x < w; ++x) {

// Threshold value and compute error

value = input.getSample(x, y, 0);

if (value < threshold) {

output.setSample(x, y, 0, 0); //set to black

error = value;

}

else {

output.setSample(x, y, 0, 1); //set to white

error = value - 255;

}

// Disperse error to pixels that are ahead of us

value = input.getSample(x+1, y, 0);

input.setSample(x+1, y, 0, clamp(value + 0.4375f * error));

value = input.getSample(x-1, y+1, 0);

input.setSample(x-1, y+1, 0, clamp(value + 0.1875f * error));

value = input.getSample(x, y+1, 0);

input.setSample(x, y+1, 0, clamp(value + 0.3125f * error));

value = input.getSample(x+1, y+1, 0);

input.setSample(x+1, y+1, 0, clamp(value + 0.0625f * error));

}

return outputImage;

}

// Rounds a float to the nearest int between 0 and 255

- 16 -

Page 17: Digital Image Processing Java3

public static int clamp(float value) {

return Math.min(Math.max(Math.round(value), 0), 255);

}

ROI (region of interest)

Java MeanROI matthead.png

LISTING 5.13 Example of using a ROI in the calculation of mean grey level.

public double meanValue(BufferedImage img) {

Raster raster = img.getRaster();

double sum = 0.0;

for (int y = 0; y < img.getHeight(); ++y)

for (int x = 0; x < img.getWidth(); ++x)

sum += raster.getSample(x, y, 0);

return sum / (img.getWidth()*img.getHeight());

}

public double meanValue(BufferedImage img, Rectangle region) {

return meanValue(img.getSubimage(region.x, region.y,

region.width, region.height));

}

(p.97)

LISTING 5.14 Java code to enlarge an image by pixel replication.

public static BufferedImage enlarge (BufferedImage image, int n ){

int w = n*image.getWidth();

int h = n*image.getHeight();

BufferedImage enlargedImage = new BufferedImage(w, h, image.getType());

for (int y = 0; y < h; ++y)

for (int x=0; x < w; ++x)

enlargedImage.setRGB(x, y, image.getRGB(x/n, y/n));

return enlargedImage;

}

LISTING 5.15 Java code to shrink an image by skipping pixels.

- 17 -

Page 18: Digital Image Processing Java3

public static BufferedImage shrink (BufferedImage image, int n ){

int w = image.getWidth() / n;

int h = image.getHeight() / n;

BufferedImage shrunkdImage = new BufferedImage(w, h, image.getType());

for (int y = 0; y<h; ++y)

for (int x=0; x<w; ++x)

shrunkImage.setRGB(x, y, image.getRGB(x*n, y*n));

return shrunkImage;

}

(p.98)

LISTING 5.16 Java code for in-place horizontal reflection of an image.

public static void xReflectionInPlace (BufferedImage image){

int w = image.getWidth();

int xmax = w/2;

for (int y = 0; y < image.getHeight(); ++y)

for (int x=0; x < xmax; ++x){

// swap value at (x,y) with its mirror image

int value = image.getRGB(x, y);

image.setRGB(x, y, image.getRGB(w-x-1, y));

image.setRGB(w-x-1, y, value);

}

}

(p.100)

- 18 -

Page 19: Digital Image Processing Java3

LISTING 5.17 Java code to average a set of images.

public static BufferedImage average (BufferedImage[] imgArray ){

int n = imgArray.length;

int w = imgArray[0].getWidth(); //assume that they all have

int h = imgArray[0].getHeight(); //the same dimensions

BufferedImage average =

new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);

for (int y = 0; y < h; ++y)

for (int x=0; x < w; ++x)

float sum = 0.0f;

for (int I = 0; I < n; ++i)

sum += imgArray[i].getRaster().getSample(x, y, 0);

ter.setSample (x, y, Math.round (sum/n)); ras

}

return average;

}

(p.102)

xercise 5.7

. Write a Java program that will

elect a region of interest (ROI)

file

.111)

E

1

(a) Display an image

(b) Allow the user to s

(c) Extract this ROI from the image

(d) Write the ROI to a user-specified

(p

- 19 -

Page 20: Digital Image Processing Java3

(p.112)

IntervalTimer timer = new IntervalTimer();

Timer.start();

//some code to be timed

System.out.println(timer.elapsed()); //doesn’t stop the clock

//more code to be timed

System.out.println(timer.stop()); //stops clock

MapTest1.java

import java.util.Random;

public class MapTest1 {

public static void randomFill(short[] array) {

Random random = new Random();

for (int i = 0; i < array.length; ++i)

array[i] = (short) random.nextInt(256);

}

public static void main(String[] argv) {

int n = 512;

if (argv.length > 0)

n = Integer.parseInt(argv[0]);

// Create image and fill it with random values

- 20 -

Page 21: Digital Image Processing Java3

int numPixels = n*n;

short[] image = new short[numPixels];

randomFill(image);

// Perform the mapping directly

IntervalTimer timer = new IntervalTimer();

timer.start();

for (int i = 0; i < numPixels; ++i)

image[i] = (short) Math.round(Math.sqrt(image[i]));

System.out.println("direct calculation: " + timer.stop() + " sec");

// Perform the mapping with a lookup table

randomFill(image);

timer.start();

short[] table = new short[256];

for (int i = 0; i < 256; ++i)

table[i] = (short) Math.round(Math.sqrt(i));

for (int i = 0; i < numPixels; ++i)

image[i] = table[image[i]];

System.out.println("lookup table: " + timer.stop() + " sec");

System.exit(0);

}

}

Java MapTest1

- 21 -

Page 22: Digital Image Processing Java3

(p.113)

- 22 -

Page 23: Digital Image Processing Java3

public LookupOp(LookupTable table, RenderingHints hints)

ex: byte[] table = new byte[256];

for (int I = 0; I < 256; ++i)

table[i] = (byte) (255-i);

ByteLookupTable invertTable = new ByteLookupTable(0, table);

LookupOp invertOp = new LookupOp(invertTable, null);

BufferedImage invertedImage = invertOp.filter(image, null);

(p.116)

LISTING 6.3 A Java class to perform mapping of grey levels in an image.

package com.pearsoneduc.ip.op;

import java.awt.image.*;

public abstract class GreyMapOp implements BufferedImageOp {

protected byte[] table = new byte[256];

public int getTableEntry(int i) {

if (table[i] < 0)

return 256 + (int) table[i];

else

return (int) table[i];

}

protected void setTableEntry(int i, int value) {

if (value < 0)

table[i] = (byte) 0;

else if (value > 255)

table[i] = (byte) 255;

else

table[i] = (byte) value;

}

public void computeMapping() {

computeMapping(0, 255);

}

- 23 -

Page 24: Digital Image Processing Java3

public abstract void computeMapping(int low, int high);

public BufferedImage filter(BufferedImage src, BufferedImage dest) {

checkImage(src);

if (dest == null)

dest = createCompatibleDestImage(src, null);

LookupOp operation = new LookupOp(new ByteLookupTable(0, table), null);

operation.filter(src, dest);

return dest;

}

}

(p.117)

LISTING 6.4 A subclass of GreyMapOp that applies a linear grey level mapping

function to an image.

public class LinearOp extends GreyMapOp {

public LinearOp() {

computeMapping();

}

public LinearOp(int low, int high) {

computeMapping(low, high);

}

public void computeMapping(int low, int high) {

if (low < 0 || high > 255 || low >= high)

throw new java.awt.image.ImagingOpException("invalid mapping limits");

float scaling = 255.0f / (high - low);

for (int i = 0; i < 256; ++i)

setTableEntry(i, Math.round(scaling*(i - low)));

}

}

- 24 -

Page 25: Digital Image Processing Java3

GreyMap.java

java GreyMap in.jpg out.jpg linear

java GreyMap in. jpg out.jpg log 10 220

//logarithmic mapping of [10,220] onto [0,255]

// lin: linear

inv: inverted linear

sq: square-root

exp: exponential

java GreyMapTool matthead.png

Grey MapTool.java

import java.awt.FlowLayout;

import java.awt.image.BufferedImage;

import java.io.IOException;

import java.util.*;

import javax.swing.*;

public class GreyMapTool extends JFrame {

public GreyMapTool(String filename)

throws IOException, ImageDecoderException, HistogramException {

// Load image from file and create display component

super("GreyMapTool: " + filename);

ImageDecoder input = ImageFile.createImageDecoder(filename);

BufferedImage image = input.decodeAsBufferedImage();

LinearOp op = new LinearOp();

ImageView imageView = new ImageView(image, op);

// Create and store a set of grey level mapping operations

Hashtable ops = new Hashtable();

ops.put("linear", op);

ops.put("square-root", new SquareRootOp());

ops.put("logarithmic", new LogOp());

ops.put("exponential", new ExpOp());

ops.put("inverted", new InvertOp());

ops.put("thresholded", new ThresholdOp(128));

ops.put("equalised", new EqualiseOp(new Histogram(image)));

// Create labels for the operations

- 25 -

Page 26: Digital Image Processing Java3

Vector names = new Vector();

names.addElement("linear");

names.addElement("square-root");

names.addElement("logarithmic");

names.addElement("exponential");

names.addElement("inverted");

names.addElement("thresholded");

names.addElement("equalised");

// Add a control panel and a scrolling image display to the frame

JPanel pane = new JPanel();

pane.setLayout(new FlowLayout());

pane.add(new GreyMapPanel(imageView, ops, names));

pane.add(new JScrollPane(imageView));

setContentPane(pane);

addWindowListener(new WindowMonitor());

}

public static void main(String[] argv) {

if (argv.length > 0) {

try {

JFrame frame = new GreyMapTool(argv[0]);

frame.pack();

frame.setVisible(true);

}

catch (Exception e) {

System.err.println(e);

System.exit(1);

}

}

else {

System.err.println("usage: java GreyMapTool <imagefile>");

System.exit(1);

}

}

}

- 26 -

Page 27: Digital Image Processing Java3

(p.119)

ALGORITHM 6.3 Calculation of an image histogram.

Create an array histogram with 2b elements

for all grey levels, i , do

histogram[i ] = 0;

end for

for all pixel coordinates, x and y, do

Increment histogram[ƒ (x,y)] by 1

end for

(p.123)

- 27 -

Page 28: Digital Image Processing Java3

(p.124)

HistogramTool.java

import java.awt.*;

import java.awt.event.*;

import java.awt.image.*;

import java.io.*;

import javax.swing.*;

import javax.swing.border.*;

public class HistogramTool extends JFrame implements ActionListener {

private Histogram histogram; // histogram data to be displayed

private HistogramView[] view; // plot of the histogram

private HistogramInfoPane infoPane; // displays value and frequency

private JPanel mainPane; // contains histogram and info panel

private JMenu menu; // input/output menu

private JFileChooser fileChooser = // handles selection of files

new JFileChooser(System.getProperty("user.dir"));

public HistogramTool(Histogram theHistogram, String description) {

super(description); // labels the frame

// Create components to display histogram and information

histogram = theHistogram;

infoPane = new HistogramInfoPane(histogram);

mainPane = new JPanel(new BorderLayout());

if (histogram.getNumBands() == 3)

createMultipleViews(); // three views (R, G, B) in a tabbed pane

else

createSingleView();

mainPane.add(infoPane, BorderLayout.SOUTH);

setContentPane(mainPane);

// Add a menu bar to support image input and histogram output

JMenuBar menuBar = new JMenuBar();

menuBar.setBorder(new BevelBorder(BevelBorder.RAISED));

createFileMenu();

- 28 -

Page 29: Digital Image Processing Java3

menuBar.add(menu);

setJMenuBar(menuBar);

addWindowListener(new WindowMonitor());

}

// Creates a single HistogramView object to display a

// greyscale histogram and adds it to the GUI

public void createSingleView() {

view = new HistogramView[1];

view[0] = new HistogramView(histogram, infoPane);

mainPane.add(view[0], BorderLayout.CENTER);

}

// Creates three HistogramView objects for the red, green

// and blue bands of a colour histogram, places these in a

// tabbed pane and adds the tabbed pane to the GUI

public void createMultipleViews() {

view = new HistogramView[3];

Color[] bandColor = { Color.red, Color.green, Color.blue };

String[] tabLabel = { "Red", "Green", "Blue" };

JTabbedPane views = new JTabbedPane(JTabbedPane.BOTTOM);

for (int i = 0; i < 3; ++i) {

view[i] = new HistogramView(histogram, i, infoPane);

view[i].setColor(bandColor[i]);

views.add(tabLabel[i], view[i]);

}

mainPane.add(views, BorderLayout.CENTER);

}

// Creates a menu to support image input, histogram output

// and termination of the application

public void createFileMenu() {

menu = new JMenu("File");

menu.setMnemonic('F');

String[] itemName = { "Load image", "Save histogram", "Exit" };

- 29 -

Page 30: Digital Image Processing Java3

char[] shortcut = { 'L', 'S', 'X' };

for (int i = 0; i < 3; ++i) {

JMenuItem item = new JMenuItem(itemName[i], shortcut[i]);

item.addActionListener(this);

menu.add(item);

}

}

// Handles Action events triggered by menu selections

public void actionPerformed(ActionEvent event) {

String command = event.getActionCommand();

if (command.startsWith("Load")) {

loadImage();

repaint();

}

else if (command.startsWith("Save")) {

saveHistogram();

repaint();

}

else if (command.equals("Exit")) {

setVisible(false);

dispose();

System.exit(0);

}

}

// Loads a new image, computes its histogram and updates the GUI

public void loadImage() {

fileChooser.setDialogTitle("Load image");

if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {

// Load image and compute its histogram

try {

File file = fileChooser.getSelectedFile();

ImageDecoder input =

ImageFile.createImageDecoder(file.getAbsolutePath());

- 30 -

Page 31: Digital Image Processing Java3

BufferedImage image = input.decodeAsBufferedImage();

histogram.computeHistogram(image);

setTitle(file.getName());

}

catch (FileNotFoundException e) {

error("File not found.");

return;

}

catch (ImageDecoderException e) {

error("Cannot read this image format.");

return;

}

catch (IOException e) {

error("Failed to read image data.");

return;

}

catch (HistogramException e) {

error("Cannot compute histogram for this image type.");

return;

}

// Rebuild GUI

mainPane.removeAll();

if (histogram.getNumBands() == 3)

createMultipleViews();

else

createSingleView();

mainPane.add(infoPane, BorderLayout.SOUTH);

mainPane.invalidate();

validate();

pack();

}

}

// Saves current histogram to a file selected by user

public void saveHistogram() {

if (histogram.getNumBands() == 0) {

- 31 -

Page 32: Digital Image Processing Java3

error("No histogram data to save!");

return;

}

else {

fileChooser.setDialogTitle("Save histogram");

if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {

try {

File file = fileChooser.getSelectedFile();

if (file.exists()) {

int response = JOptionPane.showConfirmDialog(this,

"File will be overwritten! Are you sure?", "File exists",

JOptionPane.OK_CANCEL_OPTION);

if (response != JOptionPane.OK_OPTION)

return;

}

histogram.write(new FileWriter(file));

fileChooser.rescanCurrentDirectory();

}

catch (IOException e) {

error("Cannot open output file.");

}

}

}

}

// Displays an error message in a dialog box

public void error(String message) {

JOptionPane.showMessageDialog(this, message, "Error",

JOptionPane.ERROR_MESSAGE);

}

public static void main(String[] argv) {

if (argv.length > 0) {

try {

ImageDecoder input = ImageFile.createImageDecoder(argv[0]);

BufferedImage image = input.decodeAsBufferedImage();

Histogram hist = new Histogram(image);

HistogramTool histTool = new HistogramTool(hist, argv[0]);

- 32 -

Page 33: Digital Image Processing Java3

histTool.pack();

histTool.setVisible(true);

}

catch (Exception e) {

System.err.println(e);

System.exit(1);

}

}

else {

Histogram hist = new Histogram();

HistogramTool histTool = new HistogramTool(hist, "HistogramTool");

histTool.pack();

histTool.setVisible(true);

}

}

}

CalcHist.java

import java.awt.image.BufferedImage;

import java.io.FileWriter;

public class CalcHist {

public static void main(String[] argv) {

if (argv.length > 1) {

try {

ImageDecoder input = ImageFile.createImageDecoder(argv[0]);

BufferedImage image = input.decodeAsBufferedImage();

Histogram histogram = new Histogram(image);

FileWriter histFile = new FileWriter(argv[1]);

histogram.write(histFile);

if (argv.length > 2) {

FileWriter cumHistFile = new FileWriter(argv[2]);

histogram.writeCumulative(cumHistFile);

}

System.exit(0);

}

catch (Exception e) {

System.err.println(e);

- 33 -

Page 34: Digital Image Processing Java3

System.exit(1);

}

}

else {

System.err.println(

"usage: java CalcHist <imageFile> <histFile> [<cumHistFile>]");

System.exit(1);

}

}

}

Java HistogramTool

(p.125)

- 34 -

Page 35: Digital Image Processing Java3

(p.126)

(p.128)

LISTING 6.5 A subclass of GreyMapOp that performs histogram equalisation.

pckage com.pearsoneduc.ip.op;

public class EqualiseOp extends GreyMapOp {

/**

* Constructs an EqualiseOp object using histogram data.

* @param hist Histogram of the image to be equalised

* @exception HistogramException if the histogram is from a colour image.

*/

public EqualiseOp(Histogram hist) throws HistogramException {

float scale = 255.0f / hist.getNumSamples();

for (int i = 0; i < 256; ++i)

table[i] = (byte) Math.round(scale*hist.getCumulativeFrequency(i));

}

public void computeMapping(int low, int high) {

// Does nothing - limits are meaningless in histogram equalisation

}

}

- 35 -

Page 36: Digital Image Processing Java3

Histogram hist = new Histogram(image);

EqualiseOp eq = new EqualiseOp(hist);

BufferedImage eq_img = eq.filter(image, null);

(p.130)

(p.135)

- 36 -

Page 37: Digital Image Processing Java3

(p.136)

- 37 -

Page 38: Digital Image Processing Java3

(p.138)

- 38 -

Page 39: Digital Image Processing Java3

(p.142)

- 39 -

Page 40: Digital Image Processing Java3

(p.144)

(p.145)

(p.146)

Listing 7.1: WriteKernel.java

LISTING 7.1 A simple program demonstrating how a convolution kernel can be

created and written to an output stream.

import java.io.OutputStreamWriter;

import com.pearsoneduc.ip.op.StandardKernel;

public class WriteKernel{

- 40 -

Page 41: Digital Image Processing Java3

public static void main(String[] argv){

float[] data = new float[25];

float coeff = 0.04f;

for (int i = 0; I < 25; ++i)

data[i] = coeff;

StandardKernel kernel = new StandardKernel (5, 5, data, 2);

Kernel.write(new OutputStreamWriter(System.out));

}

}

(p.147)

Reader input = new FileReader(“test.ker”);

Kernel kernel = StandardKernel.createJerbek(input);

Listing 7.2: Convolve.java

usage: java ConvolutionTool matthead.png

(p.152)

LISTING 7.2 A convolution application with a command line interface.

import java.awt.image.*;

import java.io.*;

import com.pearsoneduc.ip.io.*;

import com.pearsoneduc.ip.op.*;

import com.pearsoneduc.ip.util.IntervalTimer;

public class Convolve {

public static void main(String[] argv) {

if (argv.length > 5) {

try {

// Parse command line arguments

ImageDecoder input = ImageFile.createImageDecoder(argv[0]);

ImageEncoder output = ImageFile.createImageEncoder(argv[1]);

Reader kernelInput = new FileReader(argv[2]);

boolean normaliseKernel = (Integer.parseInt(argv[3]) != 0);

int borderStrategy =

- 41 -

Page 42: Digital Image Processing Java3

Math.max(1, Math.min(4, Integer.parseInt(argv[4])));

int rescaleStrategy =

Math.max(1, Math.min(3, Integer.parseInt(argv[5])));

// Load image and kernel

BufferedImage inputImage = input.decodeAsBufferedImage();

Kernel kernel =

StandardKernel.createKernel(kernelInput, normaliseKernel);

// Create convolution operator and convolve image

ConvolutionOp convOp = new ConvolutionOp(kernel,

borderStrategy, ConvolutionOp.SINGLE_PASS, rescaleStrategy);

IntervalTimer timer = new IntervalTimer();

timer.start();

BufferedImage outputImage = convOp.filter(inputImage, null);

System.out.println("Convolution finished [" + timer.stop() + " sec]");

// Write results to output file

output.encode(outputImage);

System.exit(0);

}

catch (Exception e) {

System.err.println(e);

System.exit(1);

}

}

else {

System.err.println("usage: java Convolve " +

"<infile> <outfile> <kernel> <norm> <border> <rescale>");

System.exit(1);

}

}

}

- 42 -

Page 43: Digital Image Processing Java3

(p.153)

(p.155)

low pass filtering: convolution kernel >0

e.g.: mean filter (Fig.7.12、Fig.7.13), Gaussian filter ((7.13)、Fig.7.14)

(p.156)

- 43 -

Page 44: Digital Image Processing Java3

(p.157)

- 44 -

Page 45: Digital Image Processing Java3

(p.158)

High pass filtering: kernel has +, - coefficients.

(p.159)

high boost filtering:

if c=8 => high pass filter

if c is more close to 8 => sharper

(p.160)

Listing 7.3: High PassKernel.java

Usage:java HighPassKernel > highpass.ker

LISTING 7.3 A kernel class that performs high pass filtering.

public class HighPassKernel extends StandardKernel {

private static final float[] data = { -1.0f, -1.0f, -1.0f,

-1.0f, 8.0f, -1.0f,

-1.0f, -1.0f, -1.0f };

public HighPassKernel() {

super(3, 3, data, 0);

- 45 -

Page 46: Digital Image Processing Java3

}

public static void main(String[] argv) {

StandardKernel kernel = new HighPassKernel();

kernel.write(new java.io.OutputStreamWriter(System.out));

}

}

(p.161)

java GaussianKernel: generate for σ=1.0 Gussian filter

BufferedImage outputImage = ConvolutionOp.gaussianBlur(inputImage, 3.0f);

↖σ

(p.162)

LISTING 7.4 A kernel class to support Gaussian low pass filtering

public class GaussianKernel extends StandardKernel {

public GaussianKernel() {

this(1.0f);

}

public GaussianKernel(float sigma) {

super(getSize(sigma), getSize(sigma), createKernelData(sigma));

}

public static int getSize(float sigma) {

int radius = (int) Math.ceil(4.0f*sigma);

return 2*radius+1;

}

public static float[] createKernelData(float sigma) {

int n = (int) Math.ceil(4.0f*sigma);

int size = 2*n+1;

float[] data = new float[size*size];

double r, s = 2.0*sigma*sigma;

float norm = 0.0f;

- 46 -

Page 47: Digital Image Processing Java3

int i = 0;

for (int y = -n; y <= n; ++y)

for (int x = -n; x <= n; ++x, ++i) {

r = Math.sqrt(x*x + y*y);

data[i] = (float) Math.exp(-r*r/s);

norm += data[i];

}

for (i = 0; i < size*size; ++i)

data[i] /= norm;

return data;

}

public static void main(String[] argv) {

float sigma = 1.0f;

if (argv.length > 0)

sigma = Float.valueOf(argv[0]).floatValue();

StandardKernel kernel = new GaussianKernel(sigma);

kernel.write(new java.io.OutputStreamWriter(System.out));

}

}

- 47 -

Page 48: Digital Image Processing Java3

(p.163)

LISTING 7.5 A mean filtering application.

import java.awt.image.*;

import com.pearsoneduc.ip.io.*;

import com.pearsoneduc.ip.op.MeanKernel;

import com.pearsoneduc.ip.util.IntervalTimer;

public class MeanFilter {

public static void main(String[] argv) {

if (argv.length > 3) {

try {

ImageDecoder input = ImageFile.createImageDecoder(argv[0]);

ImageEncoder output = ImageFile.createImageEncoder(argv[1]);

int w = Integer.parseInt(argv[2]);

int h = Integer.parseInt(argv[3]);

BufferedImage inputImage = input.decodeAsBufferedImage();

Kernel kernel = new MeanKernel(w, h);

ConvolveOp blurOp = new ConvolveOp(kernel);

IntervalTimer timer = new IntervalTimer();

timer.start();

BufferedImage outputImage = blurOp.filter(inputImage, null);

System.out.println("Mean filtering finished [" +

timer.stop() + " sec]");

output.encode(outputImage);

System.exit(0);

}

catch (Exception e) {

System.err.println(e);

System.exit(1);

}

}

else {

System.err.println("usage: java MeanFilter <infile> <outfile> <w> <h>");

System.exit(1);

}

}

}

- 48 -

Page 49: Digital Image Processing Java3

w 3 h←3 1←σ

java MeanFilter matthead.png matt-mean.png

java GaussianBlur matthead.png matt-gaus.png

(p.164)

Edge detection:

gx(x,y) = hx * ƒ (x,y),

gy(x,y) = hy * ƒ (x,y),

Prewitt kernel:

Sobel kernel:

(p.165)

gradient vector

gradient magnitude: ≒

gradient direction:

- 49 -

Page 50: Digital Image Processing Java3

(p.166)

- 50 -

Page 51: Digital Image Processing Java3

(p.169)

Laplacian

- 51 -

Page 52: Digital Image Processing Java3

LOG (Laplacian of Gaussian) filter

(p.171)

DOG (Difference of Gaussian) filter

(p.172)

algorithm 7.7 -Canny edge dector

(p.175)

BufferedImageOp op = new CannyEdgeOp(2.0f, 50, 100);

BufferedImage edgeMap = op.filter (image, null);

BufferedImage mapImage = op.getGradientOrientationImage();

BufferedImage orientImage = op.getGradientOrientationImage();

- 52 -

Page 53: Digital Image Processing Java3

(p.176)

mean filter:

median filter: sort the 9 elements. Find the median value. (for impulsive noise)

java MedianTest matthead.png 3 3

java MinTest matthead.png 3 3

java RankFilterTool matthead.png

- 53 -

Page 54: Digital Image Processing Java3

(p.184)

σ-trimmed mean filter: f1≦ f2≦…≦ fn2

σ: the number of values removed from each end of the list.

(p.186)

MMSE filter:

java MMSEFilter matthead.png matt-mmse.png

(p.189)

- 54 -

Page 55: Digital Image Processing Java3

(P.190)

- 55 -

Page 56: Digital Image Processing Java3

(p.194)

(p.231)

affine transformation

(p.232)

- 56 -

Page 57: Digital Image Processing Java3

import java.awt.geom.AffineTransform

AffineTransform transform = new AffineTransform();

AffineTransform scale = AffineTransform.getScaleInstance(1.5, 1.5);

// increase image size by 50%

double angle = Math.Pi/4.0;

double x = image.getWidth()/2.0;

double y = image.getHeight()/2.0;

AffineTransform rotate = AffineTransform.getRotateInstance(angel, x, y);

(p.233)

(p.234)

(p.235)

- 57 -

Page 58: Digital Image Processing Java3

AffineTransform t = new AffineTransform();

t.setToTranslation(10,20);

t.rotate(30.0*Math.PI/180.0);

AffineTransform translate = AffineTransform.getTranslateInstance(5. 0);

t.concatenate(translate);

AffineTransform scale = AffineTransform.getScaleInstance(0.3, 0.3);

t.preConcatenate(scale);

(p.236)

(p.237)

- 58 -

Page 59: Digital Image Processing Java3

(p.238)

LISTING 9.2 Java implementation of Algorithm 9.1

public static BufferedImage rotate(BufferedImage input, double angle){

int width = input.getWidth();

int height = input.getHeight();

BufferedImage output = new BufferedImage(width, height, input.getType());

double a0 = Math.cos(angle*Math.PI/180.0);

double b0 = Math.sin(angle*Math.PI/180.0);

double a1 = -b0, b1 = a0;

int rx, ry;

for (int y = 0; y < height; ++y)

for (int x = 0; x < width; ++x){

rx = (int) Math.round(a0*x + a1*y);

ry = (int) Math.round(b0*x + b1*y);

if (rx >= 0 && rx < width && ry >=0 && ry < height)

output.setRGB(rx, ry, input.getRGB(x,y));

}

return output;

}

(p.239)

- 59 -

Page 60: Digital Image Processing Java3

(p.240)

- 60 -

Page 61: Digital Image Processing Java3

(p.241)

(p.243)

- 61 -

Page 62: Digital Image Processing Java3

(p.244)

LISTING 9.3 A method to calculate the bounding box of a transformed image.

public static Rectangle2D getBoundingBox(BufferedImage image, AffineTransform

transformation){

// Apply transformation to image corners

int xmax = image.getWidth()-1;

int ymax = image.getHeight()-1;

Point2D[] corners = new Point2D.Double[4];

Corners[0] = new Point2D.Double(, );

}

java Rotate1 input.png output.png 0 62.5

java Rotate2 input.png output.png ↑interp. ↑angle

java AffineTransformTool matthead.png

(p.247)

- 62 -

Page 63: Digital Image Processing Java3

(p.248)

(p.255)

- 63 -

Page 64: Digital Image Processing Java3

(p.258)

LISTING 10.1 A Java class to perform grey level thresholding.

public class ThresholdOp extends GreyMapOp {

public ThresholdOp(int threshold) {

computeMapping(threshold, 255);

}

public ThresholdOp(int low, int high) {

computeMapping(low, high);

}

public void setThreshold(int threshold) {

computeMapping(threshold, 255);

}

public void setThresholds(int low, int high) {

computeMapping(low, high);

}

public void computeMapping(int low, int high) {

if (low < 0 || high > 255 || low >= high)

throw new java.awt.image.ImagingOpException("invalid thresholds");

int i;

for (i = 0; i < low; ++i)

table[i] = (byte) 0;

for (; i <= high; ++i)

table[i] = (byte) 255;

for (; i < 256; ++i)

table[i] = (byte) 0;

}

}

(p.259)

java Threshold grey.jpg thresholded.pbm 175

java Threshold grey.jpg thresholded.pbm 92 140

java Threshold color.jpg thresholded.pbm 200 75 128

- 64 -

Page 65: Digital Image Processing Java3

(p.260)

(p.261)

LISTING 10.2 Java code to perform connected region labelling, taken from the

RegionLabelOp class.

public BufferedImage filter(BufferedImage src, BufferedImage dest) {

checkImage(src);

if (dest == null)

dest = createCompatibleDestImage(src, null);

width = src.getWidth();

height = src.getHeight();

WritableRaster in = src.copyData(null);

WritableRaster out = dest.getRaster();

int n = 1;

for (int y = 0; y < height; ++y)

for (int x = 0; x < width; ++x)

if (in.getSample(x, y, 0) > 0) {

label(in, out, x, y, n);

++n;

if (n > MAX_REGIONS)

return dest;

}

return dest;

}

private void label(WritableRaster in, WritableRaster out,

- 65 -

Page 66: Digital Image Processing Java3

int x, int y, int n) {

in.setSample(x, y, 0, 0);

out.setSample(x, y, 0, n);

int j, k;

for (int i = 0; i < connectivity; ++i) {

j = x + delta[i].x;

k = y + delta[i].y;

if (inImage(j, k) && in.getSample(j, k, 0) > 0)

label(in, out, j, k, n);

}

}

private final boolean inImage(int x, int y) {

return x >= 0 && x < width && y >= 0 && y < height;

}

}

(p.263)

- 66 -

Page 67: Digital Image Processing Java3

java RegionGrowingTool matthead.png ↗4-connet

java RegionGrow test.jpg region.pbm 100 100 4 35

( x , y ) ↘threshold

(p.273)

- 67 -

Page 68: Digital Image Processing Java3

(p.277)

Erosion: ƒΘ s (ƒ→ image; s→ stnecturing element)

(p.278)

boundary: ƒ – (ƒΘ s) = ƒ – erosion(ƒ)

- 68 -

Page 69: Digital Image Processing Java3

Dilation: ƒ ♁ s

(p.282)

LISTING 11.1 BinaryErodeOp’s filter() method.

public BufferedImage filter(BufferedImage src, BufferedImage dest) {

checkImage(src);

if (dest == null)

dest = createCompatibleDestImage(src, null);

int w = src.getWidth();

int h = src.getHeight();

Raster srcRaster = src.getRaster();

WritableRaster destRaster = dest.getRaster();

// Determine range of pixels for which operation can be performed

Point origin = structElement.getOrigin(null);

int xmin = Math.max(origin.x, 0);

int ymin = Math.max(origin.y, 0);

int xmax = origin.x + w - structElement.getWidth();

- 69 -

Page 70: Digital Image Processing Java3

int ymax = origin.y + h - structElement.getHeight();

xmax = Math.min(w-1, xmax);

ymax = Math.min(h-1, ymax);

// Fit structuring element into source image

for (int y = ymin; y <= ymax; ++y)

for (int x = xmin; x <= xmax; ++x)

if (structElement.fits(srcRaster, x, y))

destRaster.setSample(x, y, 0, nonZeroValue);

return dest;

}

BinaryStructElement structElement = new

BinaryStructElement(StructElementType.DIAMOND_5x5);

BufferedImageOp erosion = new BinaryErodeOp(structElement);

# binary structuring element

# width = 5

# height = 5

# xorigin = 2

# yorigin = 2

00|00

00|00

11|11

00|00

00|00

java BinaryErode reg1.jpg ero1.jpg disk.se

java BinaryDilate reg1.jpg dia1.jpg disk.se

(p.283)

Binary operations:

complement:

intersection:

- 70 -

Page 71: Digital Image Processing Java3

union:

(p.284)

Opening = erosion dilate

(p.286)

closing: dilate → erode

(p.287)

hit and miss transform:

(p.288)

- 71 -

Page 72: Digital Image Processing Java3

(p.289)

LISTING 11.2 filter() method of BinaryOpenOp.

public BufferedImage filter(BufferedImage src, BufferedImage dest){

BinaryErodeOp erodeOp = new BinaryErodeOp(structElement);

BinaryDilateOp dilateOp = new BinaryDilateOp(structElement);

if (dest == null)

dest = createCompatibleDestImage(src, null);

return dilateOp.filter(erodeOp.filter(src, null), dest);

}

# binary structuring

element

# width =3

# height = 3

# xorigin = 1

# yorigin = 1

111

111

111 width

height

java BinaryOpen input.pbm result.pbm sq3x3.bas

java HitAndMiss <image> <innerElement>

<outerElement> <outfile>

java BinaryMorphologyTool char_a.png 5 5

- 72 -

Page 73: Digital Image Processing Java3

(p.291)

- 73 -

Page 74: Digital Image Processing Java3

(p.292)

greyscale erosion

greyscale dilation

(p.293)

- 74 -

Page 75: Digital Image Processing Java3

(p.294)

closing

open

detect peakstop-hat transform: g = ƒ -(ƒ ο s).

(ƒ․s) – ƒ → detect valleys in the grey level surface

(p.296)

GreyErode

GreyDilate

GreyOpen

GreyClose

(p.297)

Exercises

4. Using the classes described in this chapter, write a Java program to perform the

top-hat transform.

(p.301)

RMS error (root-mean-square) for MXN image

- 75 -

Page 76: Digital Image Processing Java3

(p.303)

entropy

(p.304)

information redundancy

compression ratio

insideContour(A,B) = A – erode(A,B)

outsideContour(A,B) = dilate(A,B)-A

middleContour(A,B) = dilate(A,B)-erode(A,B)

http://iris.usc.edu/ision-Notes/bibliogruphy/text/contents.html

http://140.115.11.235/~chen/course/vision

- 76 -