This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Although we haven't implemented the image processing code, we can implement file
saving function right now. To write File->Save event handler, follow this steps:
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;
2. Edit that script as shown below: view plainprint?
1. procedure TMainForm.Save1Click(Sender: TObject); 2. begin 3. try 4. begin 5. if SavePictureDialog1.Execute then 6. TImageForm(ActiveMDIChild).Image1.Picture.SaveToFile( 7. SavePictureDialog1.FileName); 8. end 9. except 10. ShowMessage('Operation is not complete'); 11. end; 12. end;
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
http://imageprocessingindelphi.blogspot.com/
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;
Calling Histogram Procedure from Main Form
To call showHistogram procedure, we need the user interface in the main form. On
the main form, double click the MainMenu component, and add menu item Image-
>Histogram (see figure 1), then double click the Histogram item, so we will be directed
to its event handler, and edit as shown below:
view plainprint?
1. procedure TMainForm.Histogram1Click(Sender: TObject); 2. begin 3. if ImageForm<>nil then 4. begin 5. ImageForm:=TImageForm(ActiveMDIChild); 6. try 7. begin 8. Application.CreateForm(THistogramForm,HistogramForm); 9. HistogramForm.ShowHistogram(ImageForm.Image1); 10. end; 11. except 12. HistogramForm.Free; 13. ShowMessage('Cannot complete the operation'); 14. end; 15. end; 16. end;
19. Applied:boolean; 20. public 21. { Public declarations } 22. procedure SetBrightness(Image: TImage); 23. end;
2. Write the SetBrightness procedure in the implementation section
view plainprint?
1. procedure TBrightnessForm.SetBrightness(Image: TImage); 2. begin 3. try 4. begin 5. TemporaryImage:=Image; 6. OriginalImage:=TImage.Create(self); 7. OriginalImage.Picture.Bitmap.Assign(Image.Picture.Bitmap); 8. end; 9. except 10. begin 11. Free; //free the brightness form 12. ShowMessage('Cannot complete the operation'); 13. end; 14. end; 15. end;
3. 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;
4. 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; 17. if temp<0 then temp:=0; 18. if temp>255 then temp:=255; 19. pixelPointer[3*j+1]:=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;
5. 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;
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.
4.4. 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.
Figure 1. Histograms of An Image Before Contrast Enhancement (upper image) and After
Contrast Enhancement (lower image)
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
10. except 11. begin 12. Free; //free the contrast form 13. ShowMessage('Cannot complete the operation'); 14. end; 15. end; 16. end;
3. 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;
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.
4. On the ContrastForm, double clicks the OKButton component, you'll be directed
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.
4.7. Color Inversion Processing in Delphi
To implement color inversion is very easy, we don't need a special form for user
interface. We can directly implement the code in the main unit.
1. Open our previous contrast enhancement project.
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;
We can code an RGB to Gray scale conversion directly in the main unit of our color
inversion project. It is easy, as easy as our color inversion project.
1. Open our previous color inversion project.
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