Image Processing Using Delphi
Image Processing Using Delphi
Introduction
• Brightness Modification
• Contrast Enhancement
• Color Inversion
• Thresholding
CHAPTER 1
Introduction
Have you ever used Photoshop or other image processing software to make a cool impressive oil
painting style of your photograph? Do you know that number of cars parking in basement can be
deducted automatically by computer using the image captured by a camera in real time? That's what
image processing done to make them possible.
Using Delphi is fun because you can design graphical user interface easily and rapidly. If you're
familiar with Photoshop, Gimp, or other image processing software, you might be wonder how such
software is written. With image processing techniques, you can write a software to manipulate image
brightness, contrast, finding the edge feature, giving emboss effect, or change the picture to an oil
painting look. Learning image processing is really fun, and using Delphi as the development tools
make it more fun. You will learn basic image processing concept, formulas, and advanced application
of it.
Image processing deals with color manipulation, pixel-by-pixel operation, even frame-by-frame
operation. In this blog, I will try to share and discuss many image processing techniques, rangin from
basic to advanced topics.
2. Global operation, when a global characteristic of an image is used to deduct the parameter to
operate each pixel. The global characteristic is usually determined using statistical method,
for example is automatic brightness and contrast equalization, where the histogram is
redistributed for a better distribution.
3. Multi-frame operation, where an image is operated with other images to get a result. For
example is the generation of transitional image of subsequent slow motion picture. When a 20
fps (frames per second) movie will be played back four times slower, it looks smoother if we
show them in 20 fps with 3 additional transition frames between the two original frames,
rather than show only the original frames by 5 fps.
4. Geometric operation, where the shape, size, or the orientation is modified. Resizing and
skewing are some examples.
5. Neighboring pixels operation, where the result of a pixel operation depends not only on its
previous value but also on other surrounding pixels values. Smoothing and sharpening
operation are some examples.
6. Morphologic operation, is operation that is focused on specific image region. This operation is
closely related to image analysis, because it deals with object/morph detection algorithm.
Digital Image Formats
There are many digital image representation such as raster and vector format. The raster type
represent the image in pixels, while vector type represent the image in vector notation (curve, line,
circle, etc). Only raster type will be discussed here. Raster image is constructed by many pixels, where
each pixel is arranged in rows and columns. Each pixel can be addressed by its Cartesian coordinate.
Within raster image, there are some very popular formats: binary, gray scale, true color, and indexed
color.
Binary Image
In binary image, there are only two values: 0 or 1, representing two different colors. Most common
color mapping is black for 0 and white for 1. Example of binary image is shown in figure 1.
Gray Scale
Using gray scale, the intensity of a pixel can vary in many values, giving smoother image. Each pixel
can has many possible values, depending on the bit-depth of the format, for example, an 8 bit gray
scale has 256 possible value for each pixel to represent the dot intensity. The most common color
mapping for gray scale is black for 0 (zero) value, white for maximum value (255 in case of 8-bit
image), and gray for values in between. Other color mapping is possible such as dark brown for zero
and light orange for maximum value. An example of a gray scale image is shown in figure 2.
This color table is known as color pallet or color map. Using this format, we can manipulate the color
in all pixels faster, because we just need to manipulate the color map, which have much fewer element
that the pixels.Figure 4 is a typical indexed 256-color image and its own palette (shown as a rectangle
of swatches).
CHAPTER 2 Delphi Components and Graphical User Interface
This component has Picture property that can be used to store image data. Picture property has a
method called LoadFromFile that can be used to retrieve image data from a file. Other important
TPicture sub-properties are:
• Bitmap, contain the data format information and the pixels values of the image.
The most common used format for for the bitmap are:
• pf1bit The bitmap is a device-independent bitmap with one bit per pixel (black and white
palette)
• pf24bit The bitmap is a device-independent true-color bitmap that uses 24 bits per pixel.
When an image is first loaded from a file, the format will be the original format stored on that file, but
we can change the bitmap format, and the data in the bitmap will be changed accordingly. Just be
careful because this format conversion is not reversible.
4. Add a main menu component (from Standard component pallet) on the form, double click it
and set a menu item File, with Open, Save, Close, and Exit sub menus.
7. Add a status bar (from Win32 component pallet) on the form to ease the window resizing.
9. Save the form (File->Save As), type MainUnit in the file name edit box.
10. Create a new form to display the the picture as a child window on the main form using menu
File->New->Form.
18. Save the form using menu File->Save as, and name it as ImageUnit.
19. Save the project using menu File->Save project as , name it with ImageProcessor, so this will
be our executable file name if we compile it.
Figure 1. MainForm
Figure 2. ImageForm
After this steps, if we compile and run the executable, the child form will be shown because Delphi will
auto-create it. This child form should be displayed only after executing a file operation, so we need to
exclude the child form in auto-create: go to Project->Options->Form, point to ImageForm to select,
and press the > button, so the ImageForm will move to Available forms box, then press OK.
1. To load and display an image file, we will use ImageForm defined in ImageUnit, so click on
MainForm and click menu File->Use Unit, and select ImageUnit then press OK. Make sure
that uses ImageUnit is automatically added below the keyword implementation.
view plainprint?
1. implementation
2.
3. uses ImageUnit;
4.
5. {$R *.dfm}
2. Add ActiveX in the uses , this trick is needed to resolve TOpenPictureDiaolog bug (showing access
violation error, I find this bug on Delphi 7 running on Windows XP SP2). Now the uses section will
look like this:
view plainprint?
1. implementation
2.
3. uses ActiveX, ImageUnit;
4.
5. {$R *.dfm}
As an integrated part of the trick, add an initialization and finalization just before the end of the file
(before end.) like shown below:
view plainprint?
1. initialization
2. OleInitialize(nil);
3. finalization
4. OleUninitialize
5. end.
1. Double click the MainMenu1 component, and double click the Save item, you'll be directed to the
event handler sript:
view plainprint?
1. procedure TMainForm.Save1Click(Sender: TObject);
2. begin
3.
4. end;
1. Double click the MainMenu1 component, and double click the Close item, you'll be directed to the
event handler sript:
view plainprint?
1. procedure TMainForm.Close1Click(Sender: TObject);
2. begin
3.
4. end;
directed to the event handler sript, and add close; inside the begin-end:
view plainprint?
1. procedure TMainForm.Exit1Click(Sender: TObject);
2. begin
3. Close;
4. end;
Now you can compile and run the executable. Figure 3 show the executable viewing an image. You can
download the source code of this GUI for Delphi 7here, and for Turbo Delphi Explorer here.
Gray level histogram is a function that show how many pixels for every gray level exist in an image.
The x-axis is the gray level, and the y-axis is the number of pixels that have certain level appear on an
image.
Using image processing techniques, we can manipulate the image to equalize the histogram, so we will
have a better picture. The image and it's histogram after equalization is shown in Figure 2.
2. Create a new form, change the form name property to HistogramForm, change the Caption to
'Histogram', set the ClientHeight property to 170, set the ClientWidth property to 275, and set
the form style property to fsMDIChild.Make OnClose event handler, click Events tab on the
object inspector, double click the OnClose event handler edit box. You'll be directed to the
event handler, and change the Action variable to caFree between begin and end.
view plainprint?
1. procedure THistogramForm.FormClose(Sender: TObject;
2. var Action: TCloseAction);
3. begin
4. Action:=caFree;
5. end;
3. Go to menu Project->Options, on the Forms page, click HistogramForm to select, and press >
to move the it from auto created forms list to available forms list.
section. Add ExtCtrls in under the uses of the interface section, as we're going to use TImage in the
form class abstraction.
view plainprint?
1. uses
2. ExtCtrls, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls
, Forms, Dialogs;
3.
4. type
5. THistogramForm = class(TForm)
6. procedure FormClose(Sender: TObject; var Action: TCloseAction);
7. private
8. { Private declarations }
9. MaxCount:Integer;
10. HistogramGray:Array[0..255]of Integer;
11. HistogramRed:Array[0..255]of Integer;
12. HistogramGreen:Array[0..255]of Integer;
13. HistogramBlue:Array[0..255]of Integer;
14. public
15. { Public declarations }
16. procedure ShowHistogram(Image:TImage);
17. end;
Writing The Histogram Computation Procedure
In the implementation, write the ShowHistogram procedure as shown below:
view plainprint?
1. procedure THistogramForm.ShowHistogram(Image:TImage);
2. var
3. i,j:integer;
4. pixelPointer:PByteArray;
5. begin
6. try
7. begin
8. for i:=0 to 255 do
9. begin
10. HistogramGray[i]:=0;
11. HistogramRed[i]:=0;
12. HistogramGreen[i]:=0;
13. HistogramBlue[i]:=0;
14. end;
15. if Image.Picture.Bitmap.PixelFormat=pf8bit then
16. begin
17. for i:=0 to Image.Height-1 do
18. begin
19. pixelPointer:=Image.Picture.Bitmap.ScanLine[i];
20. for j:=0 to Image.Width-1 do
21. begin
22. Inc(HistogramGray[pixelPointer[j]]);
23. end;
24. end;
25. MaxCount:=0;
26. for i:=0 to 255 do
27. if HistogramGray[i]>MaxCount then
28. MaxCount:=HistogramGray[i];
29. end;
30. if Image.Picture.Bitmap.PixelFormat=pf24bit then
31. begin
32. for i:=0 to Image.Height-1 do
33. begin
34. pixelPointer:=Image.Picture.Bitmap.ScanLine[i];
35. for j:=0 to Image.Width-1 do
36. begin
37. Inc(HistogramBlue[pixelPointer[3*j]]);
38. Inc(HistogramGreen[pixelPointer[3*j+1]]);
39. Inc(HistogramRed[pixelPointer[3*j+2]]);
40. end;
41. end;
42. for i:=0 to 255 do
43. begin
44. if HistogramRed[i]>MaxCount then
45. MaxCount:=HistogramRed[i];
46. if HistogramGreen[i]>MaxCount then
47. MaxCount:=HistogramGreen[i];
48. if HistogramBlue[i]>MaxCount then
49. MaxCount:=HistogramBlue[i];
50. end;
51. end;
52. Canvas.MoveTo(10, 160);
53. Canvas.Pen.Color:=clBlack;
54. for i:=0 to 255 do
55. Canvas.LineTo(10+i,
56. 160-round(150*HistogramGray[i]/MaxCount));
57. Canvas.Pen.Color:=clRed;
58. Canvas.MoveTo(10, 160);
59. for i:=0 to 255 do
60. Canvas.LineTo(10+i,
61. 160-(round(150*HistogramRed[i]/MaxCount)));
62. Canvas.Pen.Color:=clGreen;
63. Canvas.MoveTo(10, 160);
64. for i:=0 to 255 do
65. Canvas.LineTo(10+i,
66. 160-(round(150*HistogramGreen[i]/MaxCount)));
67. Canvas.Pen.Color:=clBlue;
68. Canvas.MoveTo(10, 160);
69. for i:=0 to 255 do
70. Canvas.LineTo(10+i,
71. 160-(round(150*HistogramBlue[i]/MaxCount)));
72. end;
73. except
74. Free; //free the histogram form if an exception happens
75. ShowMessage('Operation is not completed');
76. end;
77. end;
Histogram Form Repainting
When the form is activated from minimized condition, we need to redraw the canvas we have drawn
on ShowHistogram procedure. Place a focus on the histogram form, go to object inspector, on the
Events tab, double click OnPaint event and we will be directed to the event handler, edit as shown
below:
view plainprint?
1. procedure THistogramForm.FormPaint(Sender: TObject);
2. var
3. i:integer;
4. begin
5. Canvas.MoveTo(10, 160);;
6. Canvas.Pen.Color:=clBlack;
7. for i:=0 to 255 do
8. Canvas.LineTo(10+i,
9. 160-round(150*HistogramGray[i]/MaxCount));
10. Canvas.Pen.Color:=clRed;
11. Canvas.MoveTo(10, 160);
12. for i:=0 to 255 do
13. Canvas.LineTo(10+i,
14. 160-(round(150*HistogramRed[i]/MaxCount)));
15. Canvas.Pen.Color:=clGreen;
16. Canvas.MoveTo(10, 160);
17. for i:=0 to 255 do
18. Canvas.LineTo(10+i,
19. 160-(round(150*HistogramGreen[i]/MaxCount)));
20. Canvas.Pen.Color:=clBlue;
21. Canvas.MoveTo(10, 160);
22. for i:=0 to 255 do
23. Canvas.LineTo(10+i,
24. 160-(round(150*HistogramBlue[i]/MaxCount)));
25. end;
Make sure that in that main unit uses HistogramUnit under the uses ofimplementation section.
Now you can save all form, compile, and run the executable. The example of executable running is
shown in figure 2.
Pixel operation is done by transforming each pixel value to new value according to a transformation
function, known as gray-scale transformation (GST) function. This function map the gray-level input
(Ki) to an new gray-level output (Ko). In general, a GST function can be expressed as:
Ko=f(Ki)
The mapping of typical GST function can presented as transformation curve, as shown in Figure 1. The
function can be linear or non-linear. In a true color image, GST function is applied to each RGB
elements. Each function for each color element can take the same form or different depends on the
application.
Brightness Modification
We can't read a book or see something clearly in a room with low light source. In real life, we can
improve brightness by exposing the object with strong light source. In image processing, it's
equivalent to white color (analogous to light source) addition. This is done by simply adding a
constant to each color element. When the constant is positive then the image become brighter and
when the constant is negative then the image will be darker.
The GST function for brightness manipulation ca be plotted as shown in figure 1. Remember that the
addition with the constant is limited to 0-255 (8bit monochrome or 24bit true color format). The
effect on the image's histogram is shown in figure 2.
Figure 2. Brightness Manipulation Effect on Image Histogram
For true color image, the modification for each color elements can be different. We can add more blue
and reduce the red element to make different color source addition (equivalent to color light source
exposure in real life).
1. Open our previous image histogram project (you can download the source code there if you
don't have it).
3. Change the name property to BrightnessForm, change the Caption property to 'Brightness'.
Set the FormStyle property to fsMDIChild. Resize the form to fit the main form (parent form).
4. On the Object Inspector, click on Events tab, and double click in the OnClose event. You'll be
directed to the event handler, and assign the Action variable with caFree
between begin and end.
view plainprint?
1. procedure TBrightnessForm.FormClose(Sender: TObject;
2. var Action: TCloseAction);
3. begin
4. Action:=caFree;
5. end;
5. Add three scroll bar components (from the standard component pallet) to the form. Change
the Name property to RedScrollBar, GreenScrollBar, and BlueScrollBar. Set the minimum and
maximum property of each scroll bar to -255 and 255.
6. Place three label components (from the standar component pallet) to the form, place the
layout to associate each label to each scroll bar. Change the Label's caption to Red, Green, and
Blue, to label the scroll bar functions (See Figure 1).
7. Add two buttons (from standard component pallet), change their caption to OK and Cancel,
and set their name to OKButton and CancelButton accordingly.
To modify the image, it's common to backup the original image, so we can do a cancel operation after
displaying the change on the original image form. To do this, we have to provide TImage object in the
form to temporarily store the image. A procedure (SetBrightness) to associate the image input to the
brightness form is also needed.
1. Edit the BrightnessForm abstraction to provide TImage object and the SetBrightness
procedure. Add ExtCtrls under uses in the Interfacesection because we're gonna use
TImage component.
view plainprint?
1. uses
2. ExtCtrls, Windows, Messages, SysUtils, Variants, Classes, Graphics, C
ontrols, Forms,Dialogs, StdCtrls
3.
4. type= class(TForm)
5. TBrightnessForm = class(TForm)
6. RedScrollBar: TScrollBar;
7. GreenScrollBar: TScrollBar;
8. BlueScrollBar: TScrollBar;
9. Label1: TLabel;
10. Label2: TLabel;
11. Label3: TLabel;
12. OKButton: TButton;
13. CancelButton: TButton;
14. procedure FormClose(Sender: TObject; var Action: TCloseAction);
15. private
16. { Private declarations }
17. TemporaryImage:TImage;
18. OriginalImage:TImage;
19. Applied:boolean;
20. public
21. { Public declarations }
22. procedure SetBrightness(Image: TImage);
23. end;
2. Double click the RedScrollBar component, the you'll be directed to its event handler, edit as
shown below
view plainprint?
1. procedure TBrightnessForm.RedScrollBarChange(Sender: TObject);
2. var
3. i,j:Integer;
4. temp:integer;
5. pixelPointer:PByteArray;
6. originalPixelPointer:PByteArray;
7. begin
8. try
9. begin
10. for i:=0 to TemporaryImage.Picture.Height-1 do
11. begin
12. pixelPointer:=TemporaryImage.Picture.Bitmap.ScanLine[i];
13. originalPixelPointer:=OriginalImage.Picture.Bitmap.ScanLine[i
];
14. for j:=0 to TemporaryImage.Picture.Width-1 do
15. begin
16. temp:=originalPixelPointer[3*j+2]+ RedScrollBar.Position;
17. if temp<0 then temp:=0;
18. if temp>255 then temp:=255;
19. pixelPointer[3*j+2]:=temp;
20. end;
21. end;
22. TemporaryImage.Refresh;
23. end;
24. except
25. begin
26. Free;
27. ShowMessage('Cannot complete the operation');
28. end;
29. end;
30. end;
2. Double click the GreenScrollBar component, the you'll be directed to its event handler, edit as
shown below
view plainprint?
1. procedure TBrightnessForm.GreenScrollBarChange(Sender: TObject);
2. var
3. i,j:Integer;
4. temp:integer;
5. pixelPointer:PByteArray;
6. originalPixelPointer:PByteArray;
7. begin
8. try
9. begin
10. for i:=0 to TemporaryImage.Picture.Height-1 do
11. begin
12. pixelPointer:=TemporaryImage.Picture.Bitmap.ScanLine[i];
13. originalPixelPointer:=OriginalImage.Picture.Bitmap.ScanLine[i
];
14. for j:=0 to TemporaryImage.Picture.Width-1 do
15. begin
16. temp:=originalPixelPointer[3*j+1]+ GreenScrollBar.Position;
2. Double click the BlueScrollBar component, the you'll be directed to its event handler, edit as
shown below
view plainprint?
1. procedure TBrightnessForm.BlueScrollBarChange(Sender: TObject);
2. var
3. i,j:Integer;
4. temp:integer;
5. pixelPointer:PByteArray;
6. originalPixelPointer:PByteArray;
7. begin
8. try
9. begin
10. for i:=0 to TemporaryImage.Picture.Height-1 do
11. begin
12. pixelPointer:=TemporaryImage.Picture.Bitmap.ScanLine[i];
13. originalPixelPointer:=OriginalImage.Picture.Bitmap.ScanLine[i
];
14. for j:=0 to TemporaryImage.Picture.Width-1 do
15. begin
16. temp:=originalPixelPointer[3*j]+ BlueScrollBar.Position;
17. if temp<0 then temp:=0;
18. if temp>255 then temp:=255;
19. pixelPointer[3*j]:=temp;
20. end;
21. end;
22. TemporaryImage.Refresh;
23. end;
24. except
25. begin
26. Free;
27. ShowMessage('Cannot complete the operation');
28. end;
29. end;
30. end;
2. Double click OKButton component, you'll be directed to its event handler, and edit it as shown
below:
view plainprint?
1. procedure TBrightnessForm.OKButtonClick(Sender: TObject);
2. begin
3. Applied:=true;
4. Close();
5. end;
2. Double click CancelButton component, you'll be directed to its event handler, and edit it as
shown below:
view plainprint?
1. procedure TBrightnessForm.OKButtonClick(Sender: TObject);
2. begin
3. Applied:=false;
4. Close();
5. end;
Don't forget to add BrightnessUnit under the uses in the MainUnit's implementation. Use menu File-
>Use Unit (Alt+F11). Now you can save, compile and run the executable. The execution look like figure
3. Here you can download the source code for Delphi 7 project , and Turbo Delphi Explorer project
source code here.
Contrast Enhancement
Contrast in an image is the difference between pixels values. Without contrast we can't see anything
because everything will be white or black, or just gray. If an image has a low contrast, it means that
different objects in the image have low luminosity difference, and and it'll be difficult to separate them
in our perception. Contrast enhancement will be helpful in increasing the visibility of an image. Figure
1 show two images with different contrast and their histogram.
Contrast enhancement can be done using various gray scale transformation (GST) formulas. The
following is one of contrast enhancement GST formula:
Po=G(Pi-C)+C
Which G is contrast gain, and C is the center for contrasting reference. At point C the pixel value is not
modified, at above C point the pixels values is increased, and below C they're decreased.
Coding Contrast Enhancement in Delphi
Designing the GUI and The Processing Algorithm
To make our contrast enhancement processing, we need to design the graphical user interface (GUI)
first. The GUI is similar with our previousbrightness modification user interface. The following steps
explains how to make it:
3. Change the name property to ContrastForm, change the Caption property to 'Contrast'. Set
the FormStyle property to fsMDIChild. Resize the form to fit the main form (parent form).
4. On the Object Inspector, click on Events tab, and double click in the OnClose event. You'll be
directed to the event handler, and assign the Action variable with caFree
between begin and end
view plainprint?
1. procedure TContrastForm.FormClose(Sender: TObject;
2. var Action: TCloseAction);
3. begin
4. Action:=caFree;
5. end;
5. Add two scroll bar components (from the standard component pallet) to the form. Change the
Name property to CenterScrollBar and ContrastScrollBar. Set the Minimum property of
CenterScrollBar to 0 and the Maximum to 255. Set the minimum property of
ContrastScrollBar to -100 and the maximum to 100. Set the position of CenterScrollBar to
127, set the position of ContrastScrollBar to 0.
6. Place two label components (from the standar component pallet) to the form, set the layout to
associate each label to each scroll bar. Change the Label's caption to 'Center' and 'Contrast'
accordingly (see Figure 1).
7. Add two buttons (from standard component pallet), change their caption to OK and Cancel,
and set their name to OKButton and CancelButton accordingly.
To modify the image, it's common to backup the original image, so we can do a cancel operation after
displaying the change on the original image form. To do this, we have to provide TImage object in the
form to temporarily store the image. A procedure (SetContrast) to associate the image input to the
brightness form is also needed.
2. Double click the CenterScrollBar component, the you'll be directed to its event handler, edit as
shown below
view plainprint?
1. procedure TContrastForm.CenterScrollbarChange(Sender: TObject);
2. var
3. i,j:Integer;
4. temp:real;
5. pixelPointer:PByteArray;
6. originalPixelPointer:PByteArray;
7. begin
8. try
9. begin
10. if TemporaryImage.Picture.Bitmap.PixelFormat=pf8bit then
11. for i:=0 to TemporaryImage.Picture.Height-1 do
12. begin
13. pixelPointer:=TemporaryImage.Picture.Bitmap.ScanLine[i];
14. originalPixelPointer:=OriginalImage.Picture.Bitmap.ScanLine[i];
15. for j:=0 to TemporaryImage.Picture.Width-1 do
16. begin
17. temp:=((originalPixelPointer[j]-CenterScrollBAr.Position)
18. *exp(ContrastScrollBar.Position/50))
19. + CenterScrollBar.Position;
20. if temp<0>255 then temp:=255;
21. pixelPointer[j]:=round(temp);
22. end;
23. end;
24. if TemporaryImage.Picture.Bitmap.PixelFormat=pf24bit then
25. for i:=0 to TemporaryImage.Picture.Height-1 do
26. begin
27. pixelPointer:=TemporaryImage.Picture.Bitmap.ScanLine[i];
28. originalPixelPointer:=OriginalImage.Picture.Bitmap.ScanLine[i];
29. for j:=0 to TemporaryImage.Picture.Width-1 do
30. begin
31. temp:=((originalPixelPointer[3*j]-CenterScrollBAr.Position)
32. *exp(ContrastScrollBar.Position/50))
33. + CenterScrollBar.Position;
34. if temp<0>255 then temp:=255;
35. pixelPointer[3*j]:=round(temp);
36. temp:=((originalPixelPointer[3*j+1]-CenterScrollBAr.Position)
37. *exp(ContrastScrollBar.Position/50))
38. + CenterScrollBar.Position;
39. if temp<0>255 then temp:=255;
40. pixelPointer[3*j+2]:=round(temp);
41. temp:=((originalPixelPointer[3*j+2]-CenterScrollBAr.Position)
42. *exp(ContrastScrollBar.Position/50))
43. + CenterScrollBar.Position;
44. if temp<0>255 then temp:=255;
45. pixelPointer[3*j+2]:=round(temp);
46. end;
47. end;
48. TemporaryImage.Refresh;
49. end;
50. except
51. begin
52. Free;
53. ShowMessage('Cannot complete the operation');
54. end;
55. end;
56. end;
In the code shown above, you can see the contrast gain is computed as
exp(ContrastScrollBar.Position/50), with this formula, when the scroll bar position is zero
(the default), the gain will be exp(0/50)=1, and at maximum the contrast gain will be
exp(100/50)=100, and at the minimum the contrast gain will be exp(-100/50)=1/100.
2. On the ContrastForm, double clicks the OKButton component, you'll be directed to its event
handler, then edit as shown below:
view plainprint?
1. procedure TContrastForm.OKButtonClick(Sender: TObject);
2. begin
3. Applied:=true;
4. Close();
5. end;
2. Double click the CancelButton component in the ContrastForm, and you'll be directed to its
event handler, edit as shown below:
view plainprint?
1. procedure TContrastForm.CancelButtonClick(Sender: TObject);
2. begin
3. Applied:=false;
4. Close();
5. end;
2. To implement the decision whether the image on the source form will be modified or reverted
to the original bitmap, edit the ContrastForm's OnClose event handler as shown below:
view plainprint?
1. procedure TContrastForm.FormClose(Sender: TObject; var Action: TClose
Action);
2. begin
3. if Applied=false then
4. TemporaryImage.Picture.Bitmap.Assign(
5. OriginalImage.Picture.Bitmap);
6. Action:=caFree;
7. end;
Calling the GUI Module from The Main Application
To show the contrast enhancement interface and to connect the active image form to the contrast GUI,
we need to add a new item in the main menu. Double click the main menu component in the main
form, and add a Contrast menu item under menu Image (Image->Contrast, see Figure 2.
Don't forget to add ContrastUnit under the uses in the MainUnit's implementation. Use menu File-
>Use Unit (Alt+F11). Now you can save, compile and run the executable. The execution look like figure
3.
The GST function is simple, the Intensity of the output Io=Imax-Ii, where Imax is the maximum
Intensity value, and Ii is the input pixel's intensity. The maximum intensity value is 255 for 8bit
monochrome or 24bit true color. For 24 bit true color, each RGB elements is operated independently.
2. Double click the main menu component, and add a menu item 'Invert' under Image menu (see
figure 1).
3. Double click on the menu item, and you'll be directed to the event handler, edit as shown
below:
view plainprint?
1. procedure TMainForm.Invert1Click(Sender: TObject);
2. var
3. i,j:integer;
4. ptr:PByteArray;
5. begin
6. try
7. ImageForm:=TImageForm(ActiveMDIChild);
8. for i:=0 to (ImageForm.Image1.Height-1) do
9. begin
10. ptr:=ImageForm.Image1.Picture.Bitmap.ScanLine[i];
11. for j:=0 to (ImageForm.Image1.Width-1) do
12. begin
13. if ImageForm.Image1.Picture.Bitmap.PixelFormat
14. =pf8bit then ptr[j]:=255-ptr[j];
15. if ImageForm.Image1.Picture.Bitmap.PixelFormat
16. =pf24bit then
17. begin
18. ptr[3*j]:=255-ptr[3*j];
19. ptr[3*j+1]:=255-ptr[3*j+1];
20. ptr[3*j+2]:=255-ptr[3*j+2];
21. end;
22. end;
23. ImageForm.Image1.Refresh;
24. end;
25. except
26. ShowMessage('Cannot complete the operation');
27. end
28. end;
4. Save all files and now you can compile and run the executable. The execution is shown in
Figure 2 and Figure 3.
I0=(Ri+Gi+Bi)/3
Io is the output intensity, Ri, Gi, and Bi are the red, green, and the blue element intensity. The formula
for more realistic result is by adding different weight for each R,G, and B element. We normally
percept green color brighter that red color, and red color brighter than blue color. That's why we
usually set the weight higher for red and higher for green.
Actually there is no absolute reference for each weight values because it depends on the display
technology that might change in the future. The above formula is standardized by NTSC (National
Television System Committee), and its usage is common in computer imaging.
2. Double click the main menu component, and add a menu item 'Convert to Gray Scale' under
Image menu (see figure 1).
3. Double click on the menu item, and you'll be directed to the event handler, edit as shown
below:
view plainprint?
1. procedure TMainForm.ConverttoGrayScale1Click(Sender: TObject);
2. var
3. i,j:integer;
4. ptr:PByteArray;
5. begin
6. try
7. ImageForm:=TImageForm(ActiveMDIChild);
8. for i:=0 to (ImageForm.Image1.Height-1) do
9. begin
10. ptr:=ImageForm.Image1.Picture.Bitmap.ScanLine[i];
11. for j:=0 to (ImageForm.Image1.Width-1) do
12. begin
13. if ImageForm.Image1.Picture.Bitmap.PixelFormat
14. =pf24bit then
15. begin
16. ptr[3*j]:=round(0.114* ptr[3*j]
17. +0.587*ptr[3*j+1] + 0.299*ptr[3*j+2]);
18. ptr[3*j+1]:=ptr[3*j];
19. ptr[3*j+2]:=ptr[3*j];
20. end;
21. end;
22. ImageForm.Image1.Refresh;
23. end;
24. except
25. ShowMessage('Cannot complete the operation');
26. end
27. end;
4. Save all files, and now you can compile/run the project. The execution looks like shown in
figure 2.
Figure 1. RGB to Gray Scale Conversion Menu
During the thresholding process, individual pixels in an image are marked as “object” pixels if their
value is greater than some threshold value (assuming an object to be brighter than the background)
and as “background” pixels otherwise. This convention is known as threshold above. Variants
include threshold below, which is opposite of threshold above; threshold inside, where a pixel is
labeled "object" if its value is between two thresholds; and threshold outside, which is the opposite of
threshold inside (Shapiro, et al 2001:83).
The most important key in the thresholding process is the threshold point. Manually, the threshold
pint can be visually judged by trial and error, adjusting the value is you don't get the desired
background-object separation.
For Automatic thresholding, many methods have been implemented in many research. You can
simply use the mean or median value, or you can analyze the histogram and find a valley for the
threshold value.
Image Format
Image thresholding process change the image to binary value, zero or one. Ideally, this binary data is
stored in the computer memory as bit format, where 1 byte memory could store 8 pixels.
Unfortunately, the modern computer hardware organization and software (compiler) technology
doesn't handle the bit operation as fast and efficient as byte operation, so it is better to use ordinary
8bit or 24bit for practical reason, although it use actually only the least significant bit to store zero or
one.
2. Create a new form, resize the form to fit the main form. Set the name property to
ThresholdForm, and set the FormStyle to fsMDIChild. Save the unit as ThresholdUnit.pas.
3. On the menu Project->Options->Forms, select ThresholdForm (in the auto created form list)
and click the > button, so the ThresholdForm will move from auto created form list to
available forms list, then press OK.
4. Add two CheckBoxes (from standard component pallet) to the form, set the name properties
to InvertCheckBox and ThresholdInsideCheckBox. Set the captions to "Invert" and
"Threshold Inside" respectively.
5. Add two ScrollBars (from standard component pallet) to the form. Set the name properties to
LowScrollBar and HighScrollBar. Set their maximum properties to 255. Set their position
properties to 127. Add two labels to address them with "low" and "high" (see figure 1).
6. Add two buttons to the form, set their name properties to OKButton and CancelButton, and
set their caption properties to OK and Cancel accordingly.
To modify the image, it's common to backup the original image, so we can do a cancel operation after
displaying the change on the original image form. To do this, we have to provide TImage object in the
form to temporarily store the image. A procedure (SetThreshold) to associate the image input to the
threshold form is also needed. To do this, edit the ThresholdForm abstraction (in the
ThresholdUnit.pas) to provide TImage (TemporaryImage and OriginalImage) object and the
SetThreshold procedure declaration. A boolean flag (Applied) is also needed to mark whether a Cancel
or OK button has been pressed. Add ExtCtrls under uses in the Interface section because use
TImage component. After we edit the ThresholdForm abstraction, the code should look like below:
view plainprint?
1. interface
2.
3. uses
4. ExtCtrls, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls
, Forms,
5. Dialogs, StdCtrls;
6.
7. type
8. TThresholdForm = class(TForm)
9. LowScrollBar: TScrollBar;
10. HighScrollBar: TScrollBar;
11. InvertCheckBox: TCheckBox;
12. ThresholdInsideCheckBox: TCheckBox;
13. Label1: TLabel;
14. Label2: TLabel;
15. OKButton: TButton;
16. CancelButton: TButton;
17. private
18. TemporaryImage:TImage;
19. OriginalImage:TImage;
20. Applied:boolean;
21. public
22. procedure SetThreshold(Image: TImage);
23. { Public declarations }
24. end;
The Implementation