0% found this document useful (0 votes)
36 views

C Tutorial 3 - Thresholding and Histogram

This document adds thresholding functionality to an image processing program. Thresholding compares pixel values to a threshold value and sets pixels below the threshold to black (0) and above to white (255). Code is provided to threshold an image by returning a new image with pixels thresholded. A button is also added to allow selecting images and saving them as JPEGs.

Uploaded by

Barbara Martin
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
36 views

C Tutorial 3 - Thresholding and Histogram

This document adds thresholding functionality to an image processing program. Thresholding compares pixel values to a threshold value and sets pixels below the threshold to black (0) and above to white (255). Code is provided to threshold an image by returning a new image with pixels thresholded. A button is also added to allow selecting images and saving them as JPEGs.

Uploaded by

Barbara Martin
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 19

C] Tutorial 3 - Thresholding and Histogram

Terence Morley

02 October 2012

http://www.tmorley.net
http://sites.google.com/site/morleysoftware

1 Introduction
This document adds the intensity transformation Thresholding to the IpTestBed program
created in Tutorial 2. Intensity transformations simply change the grey level of each pixel
according some algorithm. The ability to create an image histogram is also added.

The code described was written using Microsoft C] Express 2010 which can be downloaded
free of charge from Microsoft.

This document was created using LATEX on MiKTeX. MiKTeX can be downloaded
from http://miktex.org/.

2 New Negative Function


In the previous tutorial we created a negative function, the code for which is shown below.

public void Negative()


{
// Loop through all pixels in the image and invert them
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int i = width * y + x;
pixels[i] = (byte)(255 - pixels[i]);
}
}
}

This function modifies the image in-place, i.e. the original is no longer available to us.
In more complicated processing we may need the original image to use again later. So we
will change this function to return a new image. The code is shown below.

1
3 SAVING YOUR IMAGES

public GreyImage Negative()


{
// Create new image for the result
GreyImage imgResult = new GreyImage(this.ImageWidth, this.ImageHeight);

// Loop through all pixels in the image and invert them


for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int i = width * y + x;
imgResult.pixels[i] = (byte)(255 - pixels[i]);
}
}
return imgResult;
}

For this, we have made a new constructor that just takes the width and height and
allocates the memory for it. This can be seen in the accompanying project or in the full
listing at the end of the tutorial.
In the project we previously called the function like this:

// Process the image for the button that was clicked


if (sender == btnNegative)
{
// Create negative of the image
testImage.Negative();
}

It will now be called like this:

// Process the image for the button that was clicked


if (sender == btnNegative)
{
// Create negative of the image
testImage = testImage.Negative();
}

So in this case we are effectively still doing the processing in-place but we now have
the flexibility to keep the original if we need to.

3 Saving Your Images


Now we will add functionality to the IpTestBed program so that it can save your processed
images to file. Initially, we will only save images in jpeg format using the JpegBitmapEncoder
class. Feel free to expand on this by adding the GifBitmapEncoder, PngBitmapEncoder
and BmpBitmapEncoder classes.

Add a button to the main window and name it btnSave. Set the Content property to
‘Save...’ and double-click on the button to be taken into the code window for the event
function. Paste the contents of the following function into your click event.

Terence Morley 2
3 SAVING YOUR IMAGES

private void btnSave_Click(object sender, RoutedEventArgs e)


{
string imageFilename;

// Get the name of the image file


imageFilename = getSaveImageFilename();
if (imageFilename == null)
{
return;
}

if (imgRight.Source is BitmapSource)
{
try
{
BitmapSource image = (BitmapSource)imgRight.Source;

FileStream stream = new FileStream(imageFilename, FileMode.Create);


JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Save(stream);
stream.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error occurred");
}
}
}

This function calls the getSaveImageFile function below. Paste this function into your
MainWindow class:

private string getSaveImageFilename()


{
string filename = null;

// Configure save file dialog box


Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.DefaultExt = ".jpg";
dlg.Filter =
"Jpeg Image (*.JPG)|*.JPG";

// Show open file dialog box


Nullable<bool> result = dlg.ShowDialog();

// Process save file dialog box results


if (result == true)
{
filename = dlg.FileName;
}

return filename;
}

Terence Morley 3
4 THRESHOLDING

4 Thresholding
So now that we have got code to open, save and display greyscale images we can go about
adding more image processing functions to the IpTestBed program.
This section will explain Thresholding. An image and a thresholded version is shown
below.

Original image. Thresholded image.

As we have described, pixels in a greyscale image are represented by one of the 256
grey-levels 0 to 255, where 0 is black and 255 is white. The technique of thresholding
compares each pixel value to a particular threshold value and if the pixel value is less than
the threshold valve, the pixel is set 0. If the pixel value is greater than or equal to the
threshold value, the pixel is set to 255. In the above picture, the chosen threshold value
was 128 which is mid-grey.
Thresholding can be described mathematically as follows:

0 if r(x, y) < T ,
s(x, y) =
255 Otherwise.

This means that for any pixel s(x, y) in a resulting image, the value is set to 0 if
the corresponding pixel in the source image is less than the threshold value, T , and 255
otherwise. As an example for a threshold value of T = 100, if a pixel has a value of 54 it
is set to black and if it has a value of 177 it is set to white.
The value of T must be chosen to achieve the desired result. A method of choosing a
suitable value is described later in this tutorial.

4.1 Thresholding Code

We will now modify the IpTestBed program to allow it to threshold images.

1. Paste the following function into the GreyImage class in the IpTestBed program.

public GreyImage Threshold(byte ThresholdLevel)


{
// Create new image for the result
GreyImage imgResult = new GreyImage(this.ImageWidth, this.ImageHeight);

Terence Morley 4
4.1 Thresholding Code 4 THRESHOLDING

// Loop through all pixels in the image and threshold


for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int i = width * y + x;
if (this.pixels[i] < ThresholdLevel)
{
imgResult.pixels[i] = (byte)0;
}
else
{
imgResult.pixels[i] = (byte)255;
}
}
}
return imgResult;
}

2. Add a button to the window, name it btnThreshold and set the Content property
to ‘Threshold...’.

3. With the threshold button selected in the window, go to the Properties window and
click on ‘Events’ at the top. Find the Click event and set it to ‘btnProcess Click’.
This, you will remember, is the general click event function that we are using for
multiple image processing functions in the MainWindow class.

4. Go into the code editor window for the MainWindow and locate the btnProcess Click
function. Modify it so it matches that shown below.

private void btnProcess_Click(object sender, RoutedEventArgs e)


{
try
{
BitmapSource bitmapIn;
string imageFilename;

// Get the name of the image file


imageFilename = getOpenImageFilename();
if (imageFilename == null)
{
return;
}

// Load the image file


bitmapIn = new BitmapImage(new Uri(imageFilename));

// Create a greyscale image from the bitmap


GreyImage testImage = new GreyImage(bitmapIn);

// Display the original


displayImage(testImage, Display.Left);

// Process the image for the button that was clicked


if (sender == btnNegative)

Terence Morley 5
4.1 Thresholding Code 4 THRESHOLDING

{
// Create negative of the image
testImage = testImage.Negative();
}
if (sender == btnThreshold)
{
// Create thresholded image
testImage = testImage.Threshold(128);
}

// Display the result of processing


displayImage(testImage, Display.Right);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error occurred");
}
}

This modification is just to add the section shown below.

if (sender == btnThreshold)
{
// Create thresholded image
testImage = testImage.Threshold(128);
}

So, the event function opens an image as it did with the Negative function then
it performs the threshold and displays the original and processed images in the
window. The Threshold function in the GreyImage class is called with a value of
128 as described in the discussion above. You can change this value to see different
effects or you can work out how to write C] code to ask the user for a value.

You may have noticed that the btnProcess Click function is slightly different to
that given in the previous tutorial. The change was to remove the bits of code
that display the images in the image controls on the window. This code was
moved into a displayImage function. The code for this can be seen in the project
code supplied with this tutorial. The function accepts a GreyImage object and a
Display enumeration which has been declared to contain the constants Left and
Right. For example, displayImage can be called with Display.Right to display an
image in the right-hand image control.

5. If you now select ‘Start without debugging’ from the Debug menu, if no mistakes
have been made, you should be able to click on the ‘Threshold...’ button, select an
image and see the results in the window as shown below.

Terence Morley 6
5 IMAGE HISTOGRAM

5 Image Histogram
While you were experimenting with different threshold values with the Threshold function,
you may have found that you didn’t know exactly what value to use to extract a particular
feature of your sample image. What you needed was some way of seeing what grey-levels
are present in your image. This is where the Image Histogram comes in.
The image histogram is a bar-chart which has on the x-axis the values 0 to 255 for
the grey-levels in the image. The chart has a vertical bar at each grey-level whose height
represents the number of pixels in the image with that grey-level. Below is shown an image
and its histogram.

Original image. Histogram.

In the image histogram shown above the ticks on the x-axis are for greyscale values
0, 64, 128, 192 and 255. The grey-level that has the largest count of pixels is about 10
(the spike near the left). This is scaled to fit the maximum height of the histogram. The
counts for the other grey-levels are then shown as a proportion of this maximum count.
As can be seen from this histogram, the image mostly contains dark pixels - this is
because most of the histogram is towards the left side of the graph. You can also see a
peak near the centre of the histogram. This is made by the mid-grey pixels making up
the lilies themselves.
In the threshold example given above, the thresholding was done at a grey-value of
128. In the histogram, you can see that the mid-grey peak finishes slightly after 128. We

Terence Morley 7
5.1 Histogram Code 5 IMAGE HISTOGRAM

can do the thresholding again at a value of 192 for example to get rid of some of mid-greys
that were sent to white. These thresholded images can be compared below.

Image thresholded at 128. Image thresholded at 192.

5.1 Histogram Code

We will now modify the IpTestBed program to allow it to generate the histogram of an
image. The histogram will be created as a greyscale image. This is simply because we have
already written the code to display and save images so we may as well use that instead
of writing more code to draw a histogram using vector graphics (if you want to, you can
rewrite the code to create a vector graphics histogram - you could then write axis labels
on the histogram).

1. Paste the following function into the GreyImage class in the IpTestBed program.

public void calculateHistogram(double[] hist)


{
// Loop through all pixels in the image and count grey-levels
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int i = width * y + x;
hist[pixels[i]]++;
}
}

// Normalise the array


double max = hist.Max();
if (max != 0)
{
for (int i = 0; i < 256; i++)
{
hist[i] = hist[i] / max;
}
}
}

This function accepts an array of floating-point numbers (double precision). The


array must have 256 entries for the 256 grey-levels in an image. (I have not put any
checking in this function, so if you don’t pass in a large enough array, the program

Terence Morley 8
5.1 Histogram Code 5 IMAGE HISTOGRAM

will throw an exception. It then goes through the image one pixel at a time and
increments the count in the array for the grey-level for that particular pixel. Finally
it finds the maximum count in the array and divides all the counts by the maximum.
This then leaves the largest count with a value of 1 and all other counts as a fraction
of 1.

2. Paste the following functions into the GreyImage class.

private int convertY(int y, int imgHeight)


{
return imgHeight - y - 1;
}

public void ClearImageToValue(byte value)


{
long size = width * height;
for (int i = 0; i < size; i++)
{
pixels[i] = value;
}
}

The y-coordinates in an image go down the screen but when drawing a graph it is
convenient for the origin to be at the bottom-left. The convertY function performs
this conversion. There is no need to do this for the x-coordinates because they go
from left to right anyway.

In C] , an array is automatically cleared to zeroes. The array of bytes used for the
images are set to 0 which gives a black image but we want the background of the
histogram to be white. The ClearImageToValue function is used to set all pixels in
the image to 255 (white).

3. Paste the following Histogram function into the GreyImage class.

public GreyImage Histogram()


{
double[] hist = new double[256];
const int margin = 10;
const int fullBarHeight = 200;
// Create new image for the result
GreyImage imgHistogram = new GreyImage(256 + 2 * margin, 200 + 2 * margin);
int i, x, y, level, tick;
int[] xTickPositions = { 0, 64, 128, 192, 255 };
double[] yTickPositions = { 0.0, 0.25, 0.50, 0.75, 1.0 };

imgHistogram.ClearImageToValue(255);

calculateHistogram(hist);

// Draw x-axis line


y = margin;
for (x = margin; x < margin + 256; x++)
{

Terence Morley 9
5.1 Histogram Code 5 IMAGE HISTOGRAM

i = imgHistogram.ImageWidth *
convertY(y, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}
// Draw x-axis ticks
for (tick = 0; tick <= 4; tick++)
{
x = margin + xTickPositions[tick];
for (y = margin / 2; y < margin; y++)
{
i = imgHistogram.ImageWidth *
convertY(y, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}

i = imgHistogram.ImageWidth *
convertY(y, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}
// Draw y-axis line
x = margin / 2;
for (y = margin; y < margin + fullBarHeight; y++)
{
i = imgHistogram.ImageWidth *
convertY(y, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}
// Draw y-axis ticks
for (tick = 0; tick <= 4; tick++)
{
y = margin + (int)(fullBarHeight * yTickPositions[tick]);
for (x = 0; x < margin / 2; x++)
{
i = imgHistogram.ImageWidth *
convertY(y, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}

i = imgHistogram.ImageWidth *
convertY(y, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}

// Draw histogram
for (level = 0; level < 256; level++)
{
int barHeight = (int)(hist[level] * fullBarHeight);
x = margin + level;
for (y = 0; y < barHeight; y++)
{
i = imgHistogram.ImageWidth *
convertY(y + margin, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}
}
return imgHistogram;
}

This function, calls the calculateHistogram function to fill an array with the histogram

Terence Morley 10
6 PROGRAM LISTINGS

values. There are then loops that draw the x and y axes and the tick marks. They
do this by setting particular pixels to 0 (black). Finally there is a loop that draws
each histogram bar from the histogram array.

4. Add a button to the window using the window editor. Name it btnHistogram, set
the Content property to ‘Histogram...’ and set the Click event to btnProcess Click
so that it calls our general processing event function when clicked.

5. Add the following fragment of code to the btnProcess Click function in the MainWindow
class below the fragment that was added for Thresholding in the previous section.
(This can be seen in the listings at the end of this tutorial or in the supplied C]
project.

if (sender == btnHistogram)
{
// Generate Histogram
testImage = testImage.Histogram();
}

6. Run the program and you should be able to view a histogram as shown below.

6 Program Listings

6.1 GreyImage.cs

The code below is the entire contents of the GreyImage.cs file.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// For bitmap handling:
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace IpTestBed
{
class GreyImage
{

Terence Morley 11
6.1 GreyImage.cs 6 PROGRAM LISTINGS

private int width = 0;


private int height = 0;
private byte[] pixels = null;

///////////////////////////////////////////////
// Constructor
public GreyImage(int Width, int Height)
{
width = Width;
height = Height;
pixels = new byte[width * height];
}

///////////////////////////////////////////////
// Constructor
public GreyImage(int Width, int Height, byte[] PixelArray)
{
width = Width;
height = Height;
pixels = new byte[width * height];
pixels = PixelArray;
}

///////////////////////////////////////////////
// Constructor
public GreyImage(BitmapSource bitmap)
{
// Convert the image to greyscale format
if (bitmap.Format != PixelFormats.Gray8)
{
bitmap = new FormatConvertedBitmap(bitmap, PixelFormats.Gray8, null, 0);
}

// Allocate array to hold pixels


width = bitmap.PixelWidth;
height = bitmap.PixelHeight;
pixels = new byte[bitmap.PixelWidth * bitmap.PixelHeight];

// Copy pixels
bitmap.CopyPixels(pixels, bitmap.PixelWidth, 0);
}

///////////////////////////////////////////////
// Width property
public int ImageWidth
{
get { return this.width; }
}

///////////////////////////////////////////////
// Height property
public int ImageHeight
{
get { return this.height; }
}

///////////////////////////////////////////////
// PixelData property
public byte[] PixelData

Terence Morley 12
6.1 GreyImage.cs 6 PROGRAM LISTINGS

{
get { return this.pixels.Clone() as byte[]; }
}

///////////////////////////////////////////////
//
public void Create(int Width, int Height)
{
width = Width;
height = Height;
pixels = new byte[width * height];
}

///////////////////////////////////////////////
//
public GreyImage Negative()
{
// Create new image for the result
GreyImage imgResult = new GreyImage(this.ImageWidth, this.ImageHeight);

// Loop through all pixels in the image and invert them


for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int i = width * y + x;
imgResult.pixels[i] = (byte)(255 - pixels[i]);
}
}
return imgResult;
}

///////////////////////////////////////////////
//
public GreyImage Threshold(byte ThresholdLevel)
{
// Create new image for the result
GreyImage imgResult = new GreyImage(this.ImageWidth, this.ImageHeight);

// Loop through all pixels in the image and threshold


for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int i = width * y + x;
if (this.pixels[i] < ThresholdLevel)
{
imgResult.pixels[i] = (byte)0;
}
else
{
imgResult.pixels[i] = (byte)255;
}
}
}
return imgResult;
}

///////////////////////////////////////////////

Terence Morley 13
6.1 GreyImage.cs 6 PROGRAM LISTINGS

//
public void calculateHistogram(double[] hist)
{
// Loop through all pixels in the image and count grey-levels
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int i = width * y + x;
hist[pixels[i]]++;
}
}

// Normalise the array


double max = hist.Max();
if (max != 0)
{
for (int i = 0; i < 256; i++)
{
hist[i] = hist[i] / max;
}
}
}

///////////////////////////////////////////////
//
private int convertY(int y, int imgHeight)
{
return imgHeight - y - 1;
}

///////////////////////////////////////////////
//
public void ClearImageToValue(byte value)
{
long size = width * height;
for (int i = 0; i < size; i++)
{
pixels[i] = value;
}
}

///////////////////////////////////////////////
//
public GreyImage Histogram()
{
double[] hist = new double[256];
const int margin = 10;
const int fullBarHeight = 200;
// Create new image for the result
GreyImage imgHistogram = new GreyImage(256 + 2 * margin, 200 + 2 * margin);
int i, x, y, level, tick;
int[] xTickPositions = { 0, 64, 128, 192, 255 };
double[] yTickPositions = { 0.0, 0.25, 0.50, 0.75, 1.0 };

imgHistogram.ClearImageToValue(255);

calculateHistogram(hist);

Terence Morley 14
6.1 GreyImage.cs 6 PROGRAM LISTINGS

// Draw x-axis line


y = margin;
for (x = margin; x < margin + 256; x++)
{
i = imgHistogram.ImageWidth *
convertY(y, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}
// Draw x-axis ticks
for (tick = 0; tick <= 4; tick++)
{
x = margin + xTickPositions[tick];
for (y = margin / 2; y < margin; y++)
{
i = imgHistogram.ImageWidth *
convertY(y, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}

i = imgHistogram.ImageWidth *
convertY(y, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}
// Draw y-axis line
x = margin / 2;
for (y = margin; y < margin + fullBarHeight; y++)
{
i = imgHistogram.ImageWidth *
convertY(y, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}
// Draw y-axis ticks
for (tick = 0; tick <= 4; tick++)
{
y = margin + (int)(fullBarHeight * yTickPositions[tick]);
for (x = 0; x < margin / 2; x++)
{
i = imgHistogram.ImageWidth *
convertY(y, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}

i = imgHistogram.ImageWidth *
convertY(y, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}

// Draw histogram
for (level = 0; level < 256; level++)
{
int barHeight = (int)(hist[level] * fullBarHeight);
x = margin + level;
for (y = 0; y < barHeight; y++)
{
i = imgHistogram.ImageWidth *
convertY(y + margin, imgHistogram.ImageHeight) + x;
imgHistogram.pixels[i] = 0;
}
}

Terence Morley 15
6.2 MainWindow.xaml.cs 6 PROGRAM LISTINGS

return imgHistogram;
}
} // end class
} // end namespace

6.2 MainWindow.xaml.cs

The code below is the entire contents of the MainWindow.xaml.cs file.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
//
using System.IO;

namespace IpTestBed
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private Image imgLeft;
private Image imgRight;
private enum Display { Left, Right };

public MainWindow()
{
InitializeComponent();

// Create images to hold the bitmaps


imgLeft = new Image();
imgRight = new Image();

// Put the image controls in the scroll viewers to scroll larger images
scrollerLeft.Content = imgLeft;
imgLeft.Stretch = Stretch.None;
scrollerRight.Content = imgRight;
imgRight.Stretch = Stretch.None;
}

///////////////////////////////////////////////
// Display a GreyImage in one of the image controls
private void displayImage(GreyImage img, Display pos)
{
WriteableBitmap bitmapOut;

bitmapOut = new WriteableBitmap(img.ImageWidth, img.ImageHeight,

Terence Morley 16
6.2 MainWindow.xaml.cs 6 PROGRAM LISTINGS

96, 96, PixelFormats.Gray8, null);


// Apply the pixels to bitmap
bitmapOut.WritePixels(new Int32Rect(0, 0, img.ImageWidth,
img.ImageHeight), img.PixelData, img.ImageWidth, 0);

if (pos == Display.Left)
{
imgLeft.Source = bitmapOut;
}
else
{
imgRight.Source = bitmapOut;
}
}

///////////////////////////////////////////////
//
private string getOpenImageFilename()
{
string filename = null;

// Configure open file dialog box


Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
//dlg.FileName = "Document";
dlg.DefaultExt = ".jpg";
dlg.Filter =
"Image Files (*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*";

// Show open file dialog box


Nullable<bool> result = dlg.ShowDialog();

// Process open file dialog box results


if (result == true)
{
filename = dlg.FileName;
}

return filename;
}

///////////////////////////////////////////////
//
private string getSaveImageFilename()
{
string filename = null;

// Configure save file dialog box


Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
//dlg.FileName = "Document";
dlg.DefaultExt = ".jpg";
//dlg.Filter =
// "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*";
dlg.Filter =
"Jpeg Image (*.JPG)|*.JPG";

// Show open file dialog box


Nullable<bool> result = dlg.ShowDialog();

// Process save file dialog box results

Terence Morley 17
6.2 MainWindow.xaml.cs 6 PROGRAM LISTINGS

if (result == true)
{
filename = dlg.FileName;
}

return filename;
}

///////////////////////////////////////////////
// Function called by different processing buttons
private void btnProcess_Click(object sender, RoutedEventArgs e)
{
try
{
BitmapSource bitmapIn;
string imageFilename;

// Get the name of the image file


imageFilename = getOpenImageFilename();
if (imageFilename == null)
{
return;
}

// Load the image file


bitmapIn = new BitmapImage(new Uri(imageFilename));

// Create a greyscale image from the bitmap


GreyImage testImage = new GreyImage(bitmapIn);

// Display the original


displayImage(testImage, Display.Left);

// Process the image for the button that was clicked


if (sender == btnNegative)
{
// Create negative of the image
testImage = testImage.Negative();
}
if (sender == btnThreshold)
{
//There is no c# InputBox to get a value of the user
// Create thresholded image
testImage = testImage.Threshold(128);
}
if (sender == btnHistogram)
{
// Generate Histogram
testImage = testImage.Histogram();
}

// Display the result of processing


displayImage(testImage, Display.Right);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error occurred");
}
}

Terence Morley 18
7 DOCUMENT HISTORY

private void btnSave_Click(object sender, RoutedEventArgs e)


{
string imageFilename;

// Get the name of the image file


imageFilename = getSaveImageFilename();
if (imageFilename == null)
{
return;
}

if (imgRight.Source is BitmapSource)
{
try
{
BitmapSource image = (BitmapSource)imgRight.Source;

FileStream stream = new FileStream(imageFilename, FileMode.Create);


JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Save(stream);
stream.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error occurred");
}
}
}

}
}

7 Document History
22 December 2011 First issue.
02 October 2012 Added hyperlinks and bookmarks.

Terence Morley 19

You might also like