I've written a procedure
called gray_scale
that is suppose to have an input TImage component, turn the image that it contains into gray scale and then print it in the same TImage component. The issue with it is that it prints an black image. My code is below, please note that I've created a local variable called img2: TPicture
which purpose is to be like a middle stage between the input and the output of the procedure.
procedure gray(var img1: TImage);
var
i,j: Integer;
y: integer;
color: TColor;
img2: TPicture;
begin
i := 0; j := 0;
img2 := TPicture.create;
img2.Bitmap.Width:= img1.width;
img2.Bitmap.Height:= img1.height;
for i := 0 to img1.width do begin
for j := 0 to img1.height do begin
y:= trunc((255 * luminance(img1,i,j)));
color := RGBToColor(byte(y), byte(y), byte(y));
img2.Bitmap.Canvas.DrawPixel(i,j, TColorToFPColor(color));
end;
img1.Picture.Assign(img2);
end;
end;
Look at this piece of code where you have two nested loops.
for i := 0 to img1.width do begin
for j := 0 to img1.height do begin
y:= trunc((255 * luminance(img1,i,j)));
color := RGBToColor(byte(y), byte(y), byte(y));
img2.Bitmap.Canvas.DrawPixel(i,j, TColorToFPColor(color));
end;
img1.Picture.Assign(img2);
end;
After the inner loop you assign img2
to img1.Picture
which you will continue to read after a visit to the outer loop. As a result, img1
becomes empty (except for the leftmost pixel column) at the time the outer loop enters the second iteration.
Change the code as follows:
for i := 0 to img1.width do begin
for j := 0 to img1.height do begin
y:= trunc((255 * luminance(img1,i,j)));
color := RGBToColor(byte(y), byte(y), byte(y));
img2.Bitmap.Canvas.DrawPixel(i,j, TColorToFPColor(color));
end;
end;
img1.Picture.Assign(img2);
It is also misleading to name a TPicture
to img2
, especially when img1
refers to a TImage
.
Further, there are a few points you should consider in order to make your code more efficient. The most important is to scan a bitmap image one row at a time with the help of scanlines.