Hi there
I have a small test procedure to count how many times a color does occure within an image -> However it does not work, I think the issue is around FindColor() that I don't use correctly. Any idea where the mistake is?
procedure TForm1.Button1Click(Sender: TObject);
var
NumberOfColors: Integer;
ImageData: TImageData;
ImagingBitmap: TImagingBitmap;
Counter: Integer;
Palette: PPalette32;
ColorRecord: TColor32Rec;
ColorArray: Array of Integer;
Row, Col: Integer;
begin
NumberOfColors := 16;
SetLength(ColorArray, NumberOfColors);
ImagingBitmap := TImagingBitmap.Create;
InitImage(ImageData);
for Counter := 0 to NumberOfColors -1 do
ColorArray[Counter] := 0;
try
LoadImageFromFile('car1.png', ImageData);
ReduceColors(ImageData, NumberOfColors);
Palette := @ImageData.Palette;
//List all the colors
for Counter := 0 to NumberOfColors -1 do
Memo1.Lines.Add( IntToStr(Counter) + ':(' + IntToStr(Palette[Counter].R) + ',' +
IntToStr(Palette[Counter].G) + ',' +
IntToStr(Palette[Counter].B) + ')' );
//Count how many times a color is used
for Row := 0 to ImageData.Height -1 do begin
for Col := 0 to ImageData.Width -1 do begin
ColorRecord := GetPixel32(ImageData, Col, Row);
Counter := FindColor(Palette, NumberOfColors, ColorRecord.Color);
Inc(ColorArray[Counter]);
end;
end;
//List the counting result
for Counter := 0 to NumberOfColors -1 do
Memo2.Lines.Add( IntToStr(Counter) + ':' + IntToStr(ColorArray[Counter]) );
//Draw the image on the canvas
ImagingBitmap.AssignFromImageData(ImageData);
Form1.Canvas.Draw(0, 0, ImagingBitmap);
finally
FreeImage(ImageData);
ImagingBitmap.Free;
end;
end;
Thanks in advance,
P.
Hi, sorry for late answer.
There are two problems with your code:
1) Your setting Palette variable to point to the address of ImageData.Palette field, not to the actual
palette info. Correct way is this:
//Palette := @ImageData.Palette; wrong
Palette := ImageData.Palette; // ok
Palette := @ImageData.Palette[0]; // also ok, if ImageData.Palette <> nil
2) When you fix the palette pointer problem you'll notice you get 'Access violation' exception now. That's because
ImageData.Palette = nil. ReduceColors keeps the image in its original data format and doesn't convert it to indexed (that's because ReduceColors supports color counts up to 4096 for which there is no indexed format).
In short, you need to convert to indexed format explicitly by adding ConvertImage call after ReduceColors:
ReduceColors(ImageData, NumberOfColors);
ConvertImage(ImageData, ifIndex8); // added
Palette := ImageData.Palette;
Now the colors are counted correctly.
Thank you, works perfectly!