The Shed is going Social! Join us on FaceBook and Twitter and chime in on the conversation.
|
 |
|
Dev Shed Forums
> Programming Languages - More
> Delphi Programming
|
Drawing a Image Histogram (RGB values)
Discuss Drawing a Image Histogram (RGB values) in the Delphi Programming forum on Dev Shed. Drawing a Image Histogram (RGB values) Delphi Programming forum discussing Delphi related topics including Kylix, C++ Builder, and more. Delphi is a high-performance language, originally based on the PASCAL language.
|
|
 |
|
|
|
|

Dev Shed Forums Sponsor:
|
|
|

March 13th, 2013, 03:37 PM
|
|
Registered User
|
|
Join Date: Mar 2013
Posts: 6
Time spent in forums: 1 h 37 m 32 sec
Reputation Power: 0
|
|
|
Drawing a Image Histogram (RGB values)
Hello,
I'm I have .Jpeg images and I want to draw the pixels RGB values.
At the moment I have this code to draw them in a Tchart:
type
PRGBTripleArray = ^TRGBTripleArray;
TRGBTripleArray = array[0..4095] of TRGBTriple;
procedure TForm1.Button1Click(Sender: TObject);
var
x, y, z : Integer;
R, G, B : Byte;
C : Tcolor;
serieR : TChartSeries;
serieG : TChartSeries;
serieB : TChartSeries;
serieRGB : TchartSeries;
Bitmap : TBitmap;
Pixels : PRGBTripleArray;
VR, VG, VB : array of integer;
begin
Bitmap := TBitmap.Create;
try
Bitmap.Assign(Image1.Picture.Graphic);
begin
SetLength(VR, 256);
SetLength(VG, 256);
SetLength(VB, 256);
serieR := TLineSeries.Create(nil);
serieG := TLineSeries.Create(nil);
serieB := TLineSeries.Create(nil);
for Y := 0 to Bitmap.Height - 1 do
begin
Pixels := Bitmap.ScanLine[Y];
for X := 0 to Bitmap.Width - 1 do
begin
// obtém as cores da paleta
R := pixels[x].rgbtRed;
G := pixels[x].rgbtGreen;
B := pixels[x].rgbtBlue;
C := RGB(
Pixels[X].rgbtRed,
Pixels[X].rgbtGreen,
Pixels[X].rgbtBlue
);
VR[R] := VR[R] + 1;
VG[G] := VR[G] + 1;
VB[B] := VR[B] + 1;
end;
end;
for z:= 0 to 255 do
begin
//cria grafico
serieR.AddXY(Z, VR[z], '', clRed);
serieG.AddXY(z, VG[z], '', clGreen);
serieB.AddXY(z, VB[z], '', clBlue);
end;
serieR.Title := 'RED';
serieG.Title := 'GREEN';
serieB.Title := 'BLUE';
Chart1.AddSeries(serieR);
Chart2.AddSeries(serieG);
Chart3.AddSeries(serieB);
end;
finally
bitmap.free;
end;
end;
But I keep getting wrong values, I need some suggestions to modify mt Code. I have Delphi XE3
Thanks, frutasamir.
|

March 13th, 2013, 04:05 PM
|
|
Contributing User
|
|
Join Date: Jun 2008
Posts: 257
 
Time spent in forums: 3 Days 9 m 16 sec
Reputation Power: 6
|
|
|
I don't see where you set the initial values for the VR, VG, VB array elements to zero, so VR[R] := VR[R] + 1; VG[G] := VR[G] + 1; and VB[B] := VR[B] + 1; would have unpredictable results.
You can either cycle through all values one by one setting them to 0, or you can use fillchar
FillChar(VR, SizeOf(VR), 0);
FillChar(VB, SizeOf(VB), 0);
FillChar(VG, SizeOf(VG), 0);
Last edited by majlumbo : March 13th, 2013 at 04:10 PM.
|

March 13th, 2013, 04:50 PM
|
|
Registered User
|
|
Join Date: Mar 2013
Posts: 6
Time spent in forums: 1 h 37 m 32 sec
Reputation Power: 0
|
|
|
I'm not quite sure what you mean, should I initialize the VR, VG, and VB before looping through the image?
VR[R] := 0;
VG[G] := 0;
VB[B] := 0;
for Y := 0 to Bitmap.Height - 1 do
begin
Pixels := Bitmap.ScanLine[Y];
for X := 0 to Bitmap.Width - 1 do
begin
// obtém as cores da paleta
R := pixels[x].rgbtRed;
G := pixels[x].rgbtGreen;
B := pixels[x].rgbtBlue;
C := RGB(
Pixels[X].rgbtRed,
Pixels[X].rgbtGreen,
Pixels[X].rgbtBlue
);
VR[R] := VR[R] + 1;
VG[G] := VR[G] + 1;
VB[B] := VR[B] + 1;
end;
end;
How does the fillchar work?
|

March 13th, 2013, 06:05 PM
|
|
Contributing User
|
|
Join Date: Jan 2006
Location: Carlsbad, CA
|
|
|
I am not sure exactly what you are doing but it seems to me that VR, VG and VB might need to be two dimension arrays.
i.e. (look up the proper syntax please)
setLength(VR,bitmap.Height,Bitmap.Width);
Also, instead of
VR[R] := VR[R] + 1;
As you loop through the double loop, don't you need something like:
VR[Y,X] := R;
Or am I completely off the mark?
Clive
|

March 13th, 2013, 08:28 PM
|
|
Contributing User
|
|
Join Date: Jun 2008
Posts: 257
 
Time spent in forums: 3 Days 9 m 16 sec
Reputation Power: 6
|
|
Quote:
should I initialize the VR, VG, and VB before looping through the image?
VR[R] := 0;
VG[G] := 0;
VB[B] := 0; |
Almost correct. VR, VG and VB are arrays each with 256 elements, so EACH ARRAY CELL needs to be set to zero before you attempt to add 1 one to it.
either
Code:
for I := 0 to 255 do
begin
VR[I] := 0;
VG[I] := 0;
VB[I] := 0;
end;
or you can use fillchar,
Code:
fillchar(VR, sizeOf(VR), 0);
fillchar(VG, sizeOf(VG), 0);
fillchar(VB, sizeOf(VB), 0);
Both options would have to occur AFTER you set the length of the array, but BEFORE you attempt to add a value to each cell to populate your histogram.
Last edited by majlumbo : March 13th, 2013 at 08:40 PM.
|

March 15th, 2013, 04:10 AM
|
|
Registered User
|
|
Join Date: Mar 2013
Posts: 6
Time spent in forums: 1 h 37 m 32 sec
Reputation Power: 0
|
|
|
I changed it, it's now like this....should work, but still getting wrong results on Tchart.
VAR
x, y, z : Integer;
R, G, B : Byte;
C : Tcolor;
serieR : TChartSeries;
serieG : TChartSeries;
serieB : TChartSeries;
serieRGB : TchartSeries;
Bitmap : TBitmap;
Pixels : PRGBTripleArray;
VR, VG, VB : array[0..255] of integer;
begin
Bitmap := TBitmap.Create;
try
Bitmap.Assign(Image1.Picture.Graphic);
begin
//SetLength(VR, 256);
//SetLength(VG, 256);
//SetLength(VB, 256);
fillchar(VR, sizeOf(VR), 0);
fillchar(VG, sizeOf(VG), 0);
fillchar(VB, sizeOf(VB), 0);
serieR := TLineSeries.Create(nil);
serieG := TLineSeries.Create(nil);
serieB := TLineSeries.Create(nil);
for Y := 0 to Bitmap.Height - 1 do
begin
Pixels := Bitmap.ScanLine[Y];
for X := 0 to Bitmap.Width - 1 do
begin
// obtém as cores da paleta
R := pixels[x].rgbtRed;
G := pixels[x].rgbtGreen;
B := pixels[x].rgbtBlue;
VR[R] := VR[R]+1;
VG[G] := VR[G]+1;
VB[B] := VR[B]+1;
end;
end;
for z:= 0 to 255 do
begin
//cria grafico
serieR.AddXY(Z, VR[z], '', RGB(255, 0,0 ));
serieG.AddXY(z, VG[z], '', RGB(0,235,0));
serieB.AddXY(z, VB[z], '', RGB(0,0,255));
end;
serieR.Title := 'RED';
serieG.Title := 'GREEN';
serieB.Title := 'BLUE';
Chart1.AddSeries(serieR);
Chart1.AddSeries(serieG);
Chart1.AddSeries(serieB);
end;
finally
bitmap.free;
end;
end;
|

March 15th, 2013, 08:14 AM
|
|
Contributing User
|
|
Join Date: Jun 2008
Posts: 257
 
Time spent in forums: 3 Days 9 m 16 sec
Reputation Power: 6
|
|
Quote: | Originally Posted by Frutasamir
//SetLength(VR, 256);
//SetLength(VG, 256);
//SetLength(VB, 256);
|
Why did you comment out setting the array size?
I said that setting the cell values to zero had to happen AFTER setting the length. Now you aren't setting the length of the array at all.
as far as setting the color of your series, you are setting all your Red series to just Red, Green to just Green and Blue to just blue. If instead you want to show the shade of each color, then this may possibly do it (untested...)
Code:
serieR.AddXY(Z, VR[z], '', RGB(z,0,0));
serieG.AddXY(z, VG[z], '', RGB(0,z,0));
serieB.AddXY(z, VB[z], '', RGB(0,0,z));
You may also have a possible memory leak in your code:
Code:
serieR := TLineSeries.Create(nil);
serieG := TLineSeries.Create(nil);
serieB := TLineSeries.Create(nil);
passing nil as a parameter to your line series' Create method tells the compiler that you are managing the lifetime of these objects. Much like you do with your bitmap (you create it and at the end of the procedure you free it.)
If you already have code in your application that frees SerieR, SerieG and SerieB, such as in your applications OnDestroy or your form's OnClose your OK, but if not, you need to either add it or pass in the object that you want to take responsibility to free your series.
Code:
SerieX := TLineSeries.Create(Chart1);//Chart1 will free your series when it itself is freed
Last edited by majlumbo : March 15th, 2013 at 11:55 AM.
|

March 17th, 2013, 01:27 PM
|
|
Contributing User
|
|
Join Date: Jan 2006
Location: Carlsbad, CA
|
|
Code:
// obtém as cores da paleta
R := pixels[x].rgbtRed;
G := pixels[x].rgbtGreen;
B := pixels[x].rgbtBlue;
I believe that the above code does not guarantee that all possible array indexes of R,G,B will be visited. So the code below will not apply to every position in the arrays.
Code:
VR[R] := VR[R]+1;
VG[G] := VR[G]+1;
VB[B ] := VR[B ]+1;
As long as that is your intention, that is fine.
It will ensure that every unvisited VR[index] position in your z loop will be:
serieR.AddXY(Z, 0, '', RGB(255, 0,0 ));
While every visited position with a rgbtRed of 0 will be:
serieR.AddXY(Z, 1, '', RGB(255, 0,0 ));
Clive
|

March 17th, 2013, 05:11 PM
|
|
Registered User
|
|
Join Date: Mar 2013
Posts: 6
Time spent in forums: 1 h 37 m 32 sec
Reputation Power: 0
|
|
|
Thank you for the suggestions, So now I have the code like this:
type
PRGBTripleArray = ^TRGBTripleArray;
TRGBTripleArray = array[0..20000] of TRGBTriple;
procedure TForm1.Button1Click(Sender: TObject);
var
x, y, z : Integer;
R, G, B : Byte;
C : Tcolor;
serieR : TChartSeries;
serieG : TChartSeries;
serieB : TChartSeries;
serieRGB : TchartSeries;
Bitmap : TBitmap;
Pixels : PRGBTripleArray;
VR, VG, VB : array of integer; //Can I do something like: array [0..255] of Integer????
begin
SetLength(VR, 255);
SetLength(VG, 255);
setLength(VB, 255);
Bitmap := TBitmap.Create;
try
Bitmap.Assign(Image1.Picture.Graphic);
begin
//fillchar(VR, sizeOf(VR), 0); (if I include them in the code, it will give an error and won't work)
//fillchar(VG, sizeOf(VG), 0);
//fillchar(VB, sizeOf(VB), 0);
//serieR := TLineSeries.Create(nil);
//serieG := TLineSeries.Create(nil);
//serieB := TLineSeries.Create(nil);
SerieR := TLineSeries.Create(Chart1);
SerieG := TLineSeries.Create(Chart1);
SerieB := TLineSeries.Create(Chart1);
for Y := 0 to Bitmap.Height - 1 do
begin
Pixels := Bitmap.ScanLine[Y];
for X := 0 to Bitmap.Width - 1 do
begin
// obtém as cores da paleta
R := pixels[x].rgbtRed;
G := pixels[x].rgbtGreen;
B := pixels[x].rgbtBlue;
VR[R] := VR[R]+1;
VG[G] := VR[G]+1;
VB[B] := VR[B]+1;
end;
end;
for z:= 0 to 255 do
begin
//cria grafico
serieR.AddXY(Z, VR[z], '', RGB(z,0,0)); // It changes its color intensity, very cool.
serieG.AddXY(z, VG[z], '', RGB(0,z,0));
serieB.AddXY(z, VB[z], '', RGB(0,0,z));
end;
serieR.Title := 'RED';
serieG.Title := 'GREEN';
serieB.Title := 'BLUE';
Chart1.AddSeries(serieR);
Chart1.AddSeries(serieG);
Chart1.AddSeries(serieB);
end;
finally
bitmap.free;
end;
end;
It just reads small images, and still not giving logical results....
|

March 17th, 2013, 10:34 PM
|
|
Contributing User
|
|
Join Date: Jan 2006
Location: Carlsbad, CA
|
|
|
Because I am probably not sure exactly what you are trying to do all I am saying may not be of value.
1. You certainly can use the old fixed array construct as you never change the size of the array. But you do need to initialize each slot.
2. Are you making sure that the bitmap is being set to 32 (is it pf32?) I don't have Delphi available on my iPad.
What is illogical (inaccurate) in your results?
Clive
|

March 18th, 2013, 08:09 AM
|
|
Contributing User
|
|
Join Date: Jun 2008
Posts: 257
 
Time spent in forums: 3 Days 9 m 16 sec
Reputation Power: 6
|
|
Quote: | Originally Posted by Frutasamir
VR, VG, VB : array of integer; //Can I do something like: array [0..255] of Integer????
|
Yes, if you do
Code:
VR array [0..255] of integer;
VG array [0..255] of integer;
VB array [0..255] of integer;
then you don't have to do the setlength...
Quote: | Originally Posted by Frutasamir
fillchar(VR, sizeOf(VR), 0); (if I include them in the code, it will give an error and won't work)
|
if this gives an error (although you didn't mention what the error is), then the fall back is to do a loop, setting each cell value to zero.
Code:
for I := 0 to 255 do
begin
VR[I] := 0;
VG[I] := 0;
VB[I] := 0;
end;
again, setting the values must be done before you attempt to add 1 to an array cell value. If you declare the array with dimensions, you don't have to worry about doing it after setting the array length as mentioned above.
And to reiterate Clive's point
Quote:
Are you making sure that the bitmap is being set to 32 (is it pf32?), |
After you assign the bitmap to the image set the pixelformat
Code:
Bitmap := TBitmap.Create;
try
Bitmap.Assign(Image1.Picture.Graphic);
Image1.PixelFormat := pf32bit;//I think this is what you need to do
...
Last edited by majlumbo : March 18th, 2013 at 08:17 AM.
|
Developer Shed Advertisers and Affiliates
| Thread Tools |
Search this Thread |
|
|
|
| Display Modes |
Rate This Thread |
Linear Mode
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|
|