Color a region of picture

Hi,

Does somebody know if this is possible and how?

1) I've a picture (let it be .jpg (or something else)
2) Read it into Delphi (shouldn't be a problem :-) )
3) The image is a map of a country and now I want to color the regions according to some values.
4) How can a color these regions?

Regards, Zif.
LVL 8
ZifNabAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

intheCommented:
hi zif
i didnt want to point to component  but i think you like the demo of this one:

http://sunsite.icm.edu.pl/delphi/ftp/d20free/hotimage.zip


or else you probably be needing something like the folowing demo(from tomes graphical)where you create a "hotspot" region with tpoints a paint method :

unit CreatePolyPolygonRgnU;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  HotSpotRgn: HRGN;     // holds the multiple polygon region

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
var
  PolyPoints: array[0..11] of TPoint;       // holds the points of the polygons
  VertexCounts: array[0..1] of Integer;     // holds the vertex counts
begin
  {define one polygon in the region}
  PolyPoints[0] := Point(68, 80);
  PolyPoints[1] := Point(76, 72);
  PolyPoints[2] := Point(87, 80);
  PolyPoints[3] := Point(86, 96);
  PolyPoints[4] := Point(100, 96);
  PolyPoints[5] := Point(100, 160);
  PolyPoints[6] := Point(68, 160);

  {define another polygon in the region}
  PolyPoints[7] := Point(173, 53);
  PolyPoints[8] := Point(184, 66);
  PolyPoints[9] := Point(184, 146);
  PolyPoints[10] := Point(160, 146);
  PolyPoints[11] := Point(160, 66);

  {indicate that the firs polygon consists of 7 points, and the second
   consists of 5 points}
  VertexCounts[0] := 7;
  VertexCounts[1] := 5;

  {create the multiple polygon region}
  HotSpotRgn := CreatePolyPolygonRgn(PolyPoints, VertexCounts, 2, WINDING);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  {invert the area defined by the multiple polygon region}
  InvertRgn(Canvas.Handle, HotSpotRgn);
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  TranslatedPt: TPoint;    // holds a form specific coordinate
begin
  {since the region is defined in logical coordinates relative to the form,
   the indicated location of the mouse click must be translated appropriately}
  TranslatedPt := Image1.ClientToScreen(Point(X,Y));
  TranslatedPt := Form1.ScreenToClient(TranslatedPt);

  {indicate if the point is within the 'hotspot' area defined by the
   multiple polygon region}
  if PtInRegion(HotSpotRgn, TranslatedPt.X, TranslatedPt.Y) then
    Caption := 'Clicked on a hotspot'
  else
    Caption := 'No hot spot clicked';
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  {delete the region}
  DeleteObject(HotSpotRgn);
end;

end.


hope that helps some
Regards Barry
0
intheCommented:
note :
for each color you'd need a seperate HRGN;
0
rarigoCommented:
You could take a look here http://www.jps.net/gfody/ too.
There's greats components there to help you work with images in pixel by pixel basis
and they're really fast and come with source code.


Tchau,
Reginaldo
0
Introduction to Web Design

Develop a strong foundation and understanding of web design by learning HTML, CSS, and additional tools to help you develop your own website.

scrapdogCommented:
you can cheat if it is 16+ bit color

just draw the borders of the region using a color that is TColor(color_of_map) + 1.  The borders won't be seen because there is barely any difference in color.  Then floodfill the center with whatever color you want.
0
ZifNabAuthor Commented:
... The problem is here :

I don't draw the borders of the regions! They are already one the picture! What I'm thinking of is that I use a sort of Floodfill. I give the centre op the region the the function and this one colors the region... (but the region isn't drawn, it's already on the map...

Zif.
0
sagerydCommented:
If I understood the Q right this should be quite simple. If you have the color of the region and if the region is the same color all over, then you could just put in in a loop to compare the pixels colors one by one with the known color. I think there's a function called something like GetPixelColor() or similar.

regards,

Johan
0
JaymolCommented:
I think that sageryd means...

  Image1.Canvas.Pixels[x, y]

which returns or sets (depending on how you use it) the color of a particular pixel.

I don't think this is what you're after though.  I think you're asking for a floodfill routine.  Am I right?
0
ZifNabAuthor Commented:
Well, .... yes, I'm looking for a floodfill routine....

But, I could make a floodfill routine out of this proposition... However, not that easy I guess...

Are there are other solutions?

Regards, Tom.
0
JaymolCommented:
Why not take the regions as different images and then you could place them all together and be able to change the colour of an individual part without worrying about the others or flooding or anything like that!
0
IndefreiCommented:
listening..
0
sagerydCommented:
procedure TForm1.FillRegion(ColorToFill, NewColor: TColor);
var
  X, Y: integer;
begin
  Image.Canvas.Brush.Color := ColorToFill;
  for Y := 1 to Image.Height do begin
    for X := 1 to Image.Width do begin
      if Image.Canvas.Pixels[X, Y] = ColorToFill then begin
        Image.Canvas.Pixels[X, Y] := NewColor;
        //Application.ProcessMessages;
      end;
    end;
  end;
end;

This works if the color is the same all over the area to be filled...

//johan
0
ZifNabAuthor Commented:
sageryd,

yes, this should work... thought of it also, but for this I should calculate all rectangles. Image is made of lot's of regions, thus lot of figuring out. Since I'm lazy, I would rewrite your function by which it only has to use one coördinate.

Jaymol,

this isn't that easy, This is lot's of work... Look at it like this. The image displays a map (eg America). I then have to cut-out all the states (and perhaps their different regions too).... not that good solution.

Zif.
0
sagerydCommented:
Zif...I think I've got a solution here.... :)

procedure TForm1.FillRegion(ColorToFill: TColor; Clrs: array of TColor);
var
  X, Y, C, A: integer;
begin
  C := 0;
  A := 0;
  Image.Canvas.Brush.Color := ColorToFill;
  for Y := 0 to Image.Height do begin
    for X := 0 to Image.Width do begin
      if Image.Canvas.Pixels[X, Y] = ColorToFill then begin
        if C = 1 then C := 0 else C := 1;
        Image.Canvas.Brush.Color := Clrs[C];
        Image.Canvas.FloodFill(X, Y, Image.Canvas.Pixels[X, Y], fsSurface);
        Inc(A);
      end;
    end;
  end;
  Image.Canvas.Brush.Color := clRed;
  Image.Canvas.TextOut(0, 0, 'Amount of fields colored: ' + IntToStr(A));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Button1.Enabled := False;
  FillRegion(clGreen, [clTeal, clYellow]);
  Button1.Caption := 'Done!';
end;


What do you think?


cheers,

Johan

0
ZifNabAuthor Commented:
Johan, sorry to reject your answer, but there is something I don't understand. Look at the picture as a map :

Everything has got the color white, only the regions are drawn as black lines.

Let us say that I want to fill region of Ohio with color red and region Washington with color green.

How does your function know which region to fill?

..... mmm.... I should have a look at this FloodFill.... this seems to be the one I need.... Does it also works on images? And not just on rectangles etc drawn on the Canvas...
0
sagerydCommented:
Well if you draw on the Canvas of an image it works, yes...

Well if you specify a coordinate within Washington or Ohio there should be no problem, otherwise I believe it's impossible. How could the procedure know by itself which region is Washington?

If you don't just need different color of all the states and you don't care which region gets which color, then it's already almost built, just add more colors to the existing array input of the procudere and remove this line:

if C = 1 then C := 0 else C := 1;

regards,

Johan
0
sagerydCommented:
Correction:

If you don't care which regions get which colors in the input array of the procedure, just add more colors to the array and remove the line above!
0
sagerydCommented:
Zif?
0
ZifNabAuthor Commented:
oops, sorry... I'm on vacation...

thanks for your help. It seems that floodfill works on bitmaps files and not on other formats.

Regards, Tom.
0
ZifNabAuthor Commented:
sageryd,

please answer question,

Zif
0
sagerydCommented:
Thanx!
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
sagerydCommented:
;)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.