Link to home
Start Free TrialLog in
Avatar of ZifNab
ZifNab

asked on

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.
Avatar of inthe
inthe

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
note :
for each color you'd need a seperate HRGN;
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
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.
Avatar of ZifNab

ASKER

... 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.
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
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?
Avatar of ZifNab

ASKER

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.
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!
listening..
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
Avatar of ZifNab

ASKER

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.
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

Avatar of ZifNab

ASKER

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...
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
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!
Zif?
Avatar of ZifNab

ASKER

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.
Avatar of ZifNab

ASKER

sageryd,

please answer question,

Zif
ASKER CERTIFIED SOLUTION
Avatar of sageryd
sageryd
Flag of Sweden image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial