Board index » delphi » Amount of pixels in a 'freestyle' figure

Amount of pixels in a 'freestyle' figure

Hello together,
I'm an absolute beginner in programming graphical elements with Delphi. I'm
using D5 Prof. with Win98SE and have the following problem:
There's a bitmap (shown with a TImage component) of e.g. 300 Width and 200
Height. The user can draw a (closed) 'freestyle' figure with the following
routine:
procedure TForm1.ImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y:
Integer);
begin
 if not Drawing then Exit;
 Image.Canvas.Pen.Color := clFuchsia;
 if FirstTime then begin
  Image.Canvas.MoveTo(Origin.x, Origin.y);
  FirstTime := False;
 end;
 Image.Canvas.LineTo(X, Y);
end;
This works fine (with the only exception that it is flickering while the
mouse is moving). So, now I've got a closed asymetric (I hope this is an
english word) figure.
My problem is that I want count the pixels inside this figure, not the
border (lines) only the area inside!!! How can I do this??? Every try of
mine does not work. Has anybody an idea?

Thanks very much

Lars

 

Re:Amount of pixels in a 'freestyle' figure


Quote
On Tue, 1 Feb 2000 17:19:32 +0100, "Lars" <papro...@foni.net> wrote:
>This works fine (with the only exception that it is flickering while the
>mouse is moving).

I don't see any flicker on my machine--it might have something to do
with code elsewhere that you didn't show.

Quote
>So, now I've got a closed asymetric (I hope this is an english word)
>figure.

I don't understand why the figure is necessarily closed. (Unless, once
again, you've got some code in the OnMouseUp event handler that you
haven't showed us.)

Quote
>My problem is that I want count the pixels inside this figure, not the
>border (lines) only the area inside!!!

Defining the "inside" of a closed curve is tricky if the curve can
intersect itself (which it can in your code). There are at least three
different rules that people use: even-odd, non-exterior, and non-zero
winding number (see Foley et al., _Computer Graphics: Principles and
Practice_, for details).

An algorithm that works using the even-odd rule would go something
like this:

 begin
 Area := 0;
 for each scan line in the image do begin
   LineCrossing := False;
   for each pixel in the scan line, from left to right, do
     if the pixel color is "background" then begin
       if LineCrossing then
         Inc(Area) end
     else
       if the pixel color is "polygon border" then
         LineCrossing := not LineCrossing end end

You have to be careful counting the line crossings in the vicinity of
an intersection, to make sure that you count all of the crossings.

There are other ways of calculating area by breaking up the polygon
into triangles; however, because the triangles would be so small in
your case, I don't think there would be any significant advantage.

-Steve

Re:Amount of pixels in a 'freestyle' figure


Thanks for your effort.
You're right, there is some code in the OnMouseUp and OnMouseDown event.
Here it is:

procedure TForm1.ImageMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
 Drawing := True;
 FirstTime := True;
 Image.Canvas.Brush.Style := bsSolid;
 Image.Canvas.Brush.Color := clFuchsia;
 Origin.x := X;
 Origin.y := Y;
end;

procedure TForm1.ImageMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
 Image.Canvas.LineTo(Origin.x, Origin.y);
 Drawing := False;
 Origin.x := 0;
 Origin.y := 0;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
 tmpBitmap: TBitmap;
begin
 tmpBitmap := TBitmap.Create;
 try
  with tmpBitmap do begin
   Height := Image.Height;
   Width  := Image.Width;
   Canvas.Pen.Style := psClear;
   Canvas.Brush.Style := bsSolid;
   Canvas.Brush.Color := clYellow;
   Canvas.Ellipse(0, 0, Trunc(Image.Width / 2), Trunc(Image.Height / 2));
   Area := Round(PI * (Image.Width / 4) * (Image.Height / 4));
   lblAux.Caption := Format('Fl?che Ellipse: %d Pixels von %d Pixels
gesamt',
                   [Round(PI * (Image.Width / 4) * (Image.Height / 4)),
Image.Width * Image.Height]);
   imgAux.Picture.Bitmap := tmpBitmap;
  end;
 finally
  tmpBitmap.Free;
 end;
end;

Maybe the cause of the flickering is the second TImage (imgAux) on which
I've drawn an ellipse in order to see if my area calculation on the other
image works.

Lars

Re:Amount of pixels in a 'freestyle' figure


Lars:

Quote
"Lars" <papro...@foni.net> wrote in message

news:8770ik$3oq5@bornews.borland.com...

Quote
> Hello together,
> I'm an absolute beginner in programming graphical elements with Delphi.
I'm
> using D5 Prof. with Win98SE and have the following problem:
> There's a bitmap (shown with a TImage component) of e.g. 300 Width and 200
> Height. The user can draw a (closed) 'freestyle' figure with the following
...
> This works fine (with the only exception that it is flickering while the
> mouse is moving). So, now I've got a closed asymetric (I hope this is an
> english word) figure.

Avoid flicker in several ways.  Draw on an in-memory bitmap and then display
it in a TImage that is the same size as the TBitmap.  Also, I've noticed I
seem to see less flicker with a TImage when it's on a TPanel -- I don't know
why.  (see code below)

Quote
> My problem is that I want count the pixels inside this figure, not the
> border (lines) only the area inside!!! How can I do this???

The code below counts the number of pixels drawn in the specified color
as you're drawing them!

(I'm not sure I understand exactly what you're trying to count.)

unit ScreenDrawAndCount;

interface

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

type
  TFormDrawAndCount = class(TForm)
    Panel1: TPanel;
    LabelCount: TLabel;
    Image: TImage;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ImageMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure ImageMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure ImageMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    Drawing:  BOOLEAN;
    Bitmap :  TBitmap;
    PROCEDURE UpdateImageAndCount;
  public
    { Public declarations }
  end;

var
  FormDrawAndCount: TFormDrawAndCount;

implementation
{$R *.DFM}

TYPE
  TRGBTripleArray = ARRAY[WORD] OF TRGBTriple;
  pRGBTripleArray = ^TRGBTripleArray;

CONST
  DrawingColor:  TColor = clFuchsia;

PROCEDURE TFormDrawAndCount.UpdateImageAndCount;
  VAR
    BValue      :  BYTE;
    count       :  INTEGER;
    GValue      :  BYTE;
    i           :  INTEGER;
    j           :  INTEGER;
    row         :  pRGBTripleArray;
    RValue      :  BYTE;
BEGIN
  // Update Image
  Image.Picture.Graphic := Bitmap;

  // Update Count
  Count := 0;

  // Avoid calling these redundantly inside loops below
  RValue := GetRValue(DrawingColor);
  GValue := GetGValue(DrawingColor);
  BValue := GetBValue(DrawingColor);

  FOR j := 0 TO Bitmap.Height-1 DO
  BEGIN
    row := Bitmap.Scanline[j];
    FOR i := 0 TO Bitmap.Width-1 DO
    BEGIN
      // Each pixel here is a TRGBTriple with fields rgbtRed, rgbtGreen and
rgbtBlue
      WITH row[i] DO
      BEGIN
        IF         (rgbtRed  = RValue) AND (rgbtGreen = GValue) AND
(rgbtBlue = BValue)
        THEN INC(count)
      END
    END
  END;

  LabelCount.Caption := 'Pixels Drawn = ' + IntToStr(Count)
END {UpdateImageAndCount};

procedure TFormDrawAndCount.FormCreate(Sender: TObject);
begin
  // Work with in-memory bitmap the same size as the TImage
  Bitmap := TBitmap.Create;
  Bitmap.Width := Image.Width;
  Bitmap.Height := Image.Height;
  Bitmap.PixelFormat := pf24bit;
  Drawing := FALSE;
  UpdateImageAndCount;
end;

procedure TFormDrawAndCount.FormDestroy(Sender: TObject);
begin
  Bitmap.Free
end;

procedure TFormDrawAndCount.ImageMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  Bitmap.Canvas.Pen.Color := DrawingColor;
  Bitmap.Canvas.MoveTo(X,Y);
  Drawing := TRUE
end;

procedure TFormDrawAndCount.ImageMouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
begin
  IF   Drawing
  THEN BEGIN
    Bitmap.Canvas.LineTo(X,Y);
    UpdateImageAndCount
  END
end;

procedure TFormDrawAndCount.ImageMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  Drawing := FALSE
end;

end.

Best Wishes,
--
efg

Earl F. Glynn     E-Mail:  EarlGl...@att.net
Overland Park, KS  USA

efg's Computer Lab:  http://www.efg2.com/Lab

Re:Amount of pixels in a 'freestyle' figure


"Earl F. Glynn" <EarlGl...@att.net> wrote in message
news:8776bb$jo1@bornews.borland.com...

Quote
> Lars:
> The code below counts the number of pixels drawn in the specified color
> as you're drawing them!

I understand your queston better once I saw Steve's reply.  If you have a
closed, convex polygon, you can use the technique in this Lab Report to
compute area:
http://www.efg2.com/Lab/Graphics/PolygonArea.htm

--
efg

Earl F. Glynn     E-Mail:  EarlGl...@att.net
Overland Park, KS  USA

efg's Computer Lab:  http://www.efg2.com/Lab

Other Threads