Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

3x3 filters/smoothing but on array *not* bitmap

Posted on 1999-07-24
18
Medium Priority
?
346 Views
Last Modified: 2013-12-03
Hi All,

Tough one and I'm on the road for the next few days so won't have access to my compliers. Will have access to my email though so keep the solutions coming. I need the following to be very fast and very stable. All points go to whoever gives me a working routine. Because I need this quickly and of a high quality I am offering 750 points. OK, here we go:

I have an acoustic model from a 3rd Party that produces as output a file containing values. The values are then sent to a contouring routine to plot them on screen. I have the model working and the contouring working. However, the output from the model is a bit 'peeky'.

What I want is a routine that can 'smooth' or 'blur' a 2D array of values using a 3x3 matrix. This is very similar to blur/smooth 3x3 filters such as used in Paintshop Pro but to be used on a set of values rather than a bitmap. Still, very similar. (Image|User Defined Filters in Painthsop Pro).

OK, I want a routine that I can pass two arrays and two integers to:

The first array containing the values. This array will contain 601 x 601 values, but may be variable. I.e. the routine has to accept an array that has been sized dynamically in the main program. However, it will always be square i.e. 100x100 or 900x900. We will call this array ArrayPoints, and will be of type double

The second array will contain the matrix values and will always be 3x3. We will call this array ArrayMatrix and will be of type integer.

The first integer is the Division factor. We will call this MatrixDivision.

The second integer is the Bias factor. We will call this MatrixBias.

The routine will use the 3x3 ArrayMatrix and the two integer values passed in to 'scan' over the values in ArrayPoints, applying the filter in the same way as Paintshop Pro. The values in the 3x3 array will of course be set before calling the routine.

Online at http://www.netcomuk.co.uk/~iwatkins/test.zip contains three files:

1. BEFORE.TXT   -    A file containing 601 x 601 values
2. BEFORE.JPG   -    A bitmap representation of the values in the file above before adjustment
3. AFTER.JPG    -    A bitmap representation of the values in the file above after filtering

Obviously, file 3 is just made up to give you some idea what I am after.

Good luck.

Cheers

Ian
0
Comment
Question by:iwatkins
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 7
  • 3
  • +1
18 Comments
 
LVL 10

Expert Comment

by:viktornet
ID: 1390945
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1390946
Also, I think you'd find LOTS of useful stuff on this website..

http://www.efg2.com/lab/library/

Good Luck!!

..-=ViKtOr=-..
0
 
LVL 12

Expert Comment

by:rwilson032697
ID: 1390947
:o)
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 13

Expert Comment

by:Epsylon
ID: 1390948
Victor, what kind of answer is that?    :o(
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1390949
I mean ViKtor, what kind of answer is that?    :o(

0
 
LVL 10

Expert Comment

by:viktornet
ID: 1390950
I dunno Epsylon, you tell me.... ---->>> http://www.efg2.com/lab/library/Delphi/MathFunctions/Parsers.htm
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1390951
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1390952
Viktor, I think you should read the question again!!!!

AND STOP ACTING LIKE A FOOL....
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1390953
Me? Fool? Since when? I'm not the one who started this whole shitty thing on the Delphi area...

and my answer is absolutely correct... on the UDDF site, there is an example how to a specified area and smooth it out... on the other hand, the other webiste has got some great image effects, which would be helpful in the development of such software, so please back off...

Epsylon, I was just about to post an answer to that question which did some parsing and other stuff, but since you posted the link, i decided not to do it.. what's the point anyway...

..-=fOoL=-..
0
 

Author Comment

by:iwatkins
ID: 1390954
Not good enough guys.

Yes, I have had a good dig through all the stuff at efg (where does he get all the time to do this stuff?). But it all seems to be suited to images but I am *not* dealing with images.

Keep them coming.

Cheers

Ian
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1390955
well if you're not dealing with images, then I think this would be pretty fast :)

okay... I have a website, but don't remember the URL... it will teach you exactly what you want... but it actually is a C/C++ website, so if you don't understand somethin you just ask and someone including myself will tell you what exactly that is, etc... the website mainly deals with algorithms, so I think this should be the right one for you,.... anyway... please let us know what you think... and give some more details...

btw, you can extract the algorithm from the UDDF code, so you can use it on your array of bytes or whatever it is..

..-=fOoL=-..
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1390956
you can do something like this...

in order to make a SINGLE pixel (or a value at a certail col and row in that array), you need to take the average of the values surrounding that pixel you're currently on (you're looping through then remember? :))... then write that average value in the pixel you're currently on...

that is just an algorithm...

the difference with your situation is that you need to take the factor of that pixel... well you need to multiply by the fact and write the pixel in there... i think that's about it...

..-=ViKtOr=-..
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1390957
iwatkins, what would you like to do with the borders? Assume zero's there?
0
 
LVL 13

Accepted Solution

by:
Epsylon earned 3000 total points
ID: 1390958
Here is a demo with the function you need. It's not small but it's FAST!!! I can easily make it smaller but that will cost ya some speed.

Just put a button and 2 labels on a form. Make sure the labels have enough space to draw a 10x10 matrix.



unit Unit1;

interface

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

type
  PDoubleArray = ^TDoubleArray;
  TDoubleArray = array[0..32767] of Double;

  TMatrix = array[0..2, 0..2] of Byte;

  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  m: TMatrix = ((0,1,0),
                (1,2,1),
                (0,1,0));
  a: array[0..9, 0..9] of Double = ((0,0,0,0,0,0,0,0,0,0),
                                    (0,8,0,0,0,0,0,0,8,0),
                                    (0,0,0,0,0,0,0,0,0,0),
                                    (0,0,0,0,0,0,0,0,0,0),
                                    (0,0,0,0,0,0,0,0,0,0),
                                    (0,0,0,0,0,0,0,0,0,0),
                                    (0,0,0,0,0,0,0,0,0,0),
                                    (8,0,0,0,0,0,8,8,0,0),
                                    (0,0,0,0,0,0,0,0,0,0),
                                    (0,0,0,0,0,0,0,0,0,0));

implementation

{$R *.DFM}

procedure MyFilter(src: PDoubleArray; xres, yres: Integer;
                   matrix: TMatrix; bias, mplr: Integer);
var x, y, i, l: Integer;
    t: PDoubleArray;
    value: Double;
begin
  l := xres * yres;
  t := AllocMem(l * sizeof(Double));
// the central part
  for y := 1 to yres - 2 do
    for x := 1 to xres - 2 do
    begin
      i := y * xres + x;
      value := src[i] * matrix[1,1] +
               src[i - xres - 1] * matrix[0,0] +
               src[i - xres]     * matrix[1,0] +
               src[i - xres + 1] * matrix[2,0] +
               src[i - 1]        * matrix[0,1] +
               src[i + 1]        * matrix[2,1] +
               src[i + xres - 1] * matrix[0,2] +
               src[i + xres]     * matrix[1,2] +
               src[i + xres + 1] * matrix[2,2];
      t[i] := (value / mplr) + bias;
    end;

// the edges
  for x := 1 to xres - 2 do
  begin
    i := x;
    value := src[i] * matrix[1,1] +
             src[i - 1]        * matrix[0,1] +
             src[i + 1]        * matrix[2,1] +
             src[i + xres - 1] * matrix[0,2] +
             src[i + xres]     * matrix[1,2] +
             src[i + xres + 1] * matrix[2,2];
    t[i] := (value / mplr) + bias;
  end;

  for x := 1 to xres - 2 do
  begin
    i := (yres - 1) * xres + x;
    value := src[i] * matrix[1,1] +
             src[i - xres - 1] * matrix[0,0] +
             src[i - xres]     * matrix[1,0] +
             src[i - xres + 1] * matrix[2,0] +
             src[i - 1]        * matrix[0,1] +
             src[i + 1]        * matrix[2,1];
    t[i] := (value / mplr) + bias;
  end;

  for y := 1 to yres - 2 do
  begin
    i := y * xres;
    value := src[i] * matrix[1,1] +
             src[i - xres]     * matrix[1,0] +
             src[i - xres + 1] * matrix[2,0] +
             src[i + 1]        * matrix[2,1] +
             src[i + xres]     * matrix[1,2] +
             src[i + xres + 1] * matrix[2,2];
    t[i] := (value / mplr) + bias;
  end;

  for y := 1 to yres - 2 do
  begin
    i := y * xres + (xres - 1);
    value := src[i] * matrix[1,1] +
             src[i - xres - 1] * matrix[0,0] +
             src[i - xres]     * matrix[1,0] +
             src[i - 1]        * matrix[0,1] +
             src[i + xres - 1] * matrix[0,2] +
             src[i + xres]     * matrix[1,2];
    t[i] := (value / mplr) + bias;
  end;

// the corners
  i := 0;
  value := src[i] * matrix[1,1] +
           src[i + 1]        * matrix[2,1] +
           src[i + xres]     * matrix[1,2] +
           src[i + xres + 1] * matrix[2,2];
  t[i] := (value / mplr) + bias;

  i := xres - 1;
  value := src[i] * matrix[1,1] +
           src[i - 1]        * matrix[0,1] +
           src[i + xres - 1] * matrix[0,2] +
           src[i + xres]     * matrix[1,2];
  t[i] := (value / mplr) + bias;

  i := (yres - 1) * xres;
  value := src[i] * matrix[1,1] +
           src[i - xres]     * matrix[1,0] +
           src[i - xres + 1] * matrix[2,0] +
           src[i + 1]        * matrix[2,1];
  t[i] := (value / mplr) + bias;

  i := (yres - 1) * xres + (xres - 1);
  value := src[i] * matrix[1,1] +
           src[i - xres - 1] * matrix[0,0] +
           src[i - xres]     * matrix[1,0] +
           src[i - 1]        * matrix[0,1];
  t[i] := (value / mplr) + bias;  

// copy back to original buffer
  for i := 0 to l - 1 do
    src[i] := t[i];
  FreeMem(t);
end;

procedure TForm1.Button1Click(Sender: TObject);
var x, y: Integer;
    s: String;
begin
  s := '';
  for x := 0 to 9 do
  begin
    for y := 0 to 9 do
      s := s + Format('%6.2f  ', [a[x,y]]);
    s := s + #10#13;
  end;
  Label1.Caption := s;

  MyFilter(@a, 10, 10, m, 0, 8);

  s := '';
  for x := 0 to 9 do
  begin
    for y := 0 to 9 do
      s := s + Format('%6.2f  ', [a[x,y]]);
    s := s + #10#13;
  end;
  Label2.Caption := s;
end;

end.



Regards,

Epsylon.
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1390959
Oops, I swapped the x and y of the 2 dimensional arrays by accident. Here is a correction:



unit Unit1;

interface

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

type
  PDoubleArray = ^TDoubleArray;
  TDoubleArray = array[0..32767] of Double;

  TMatrix = array[0..2, 0..2] of Byte;

  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  m: TMatrix = ((0,1,0),
                (1,2,1),
                (0,1,0));
  a: array[0..9, 0..9] of Double = ((0,0,0,0,5,0,0,0,0,0),
                                    (0,4,0,0,0,0,0,0,8,0),
                                    (0,0,0,0,0,0,0,0,0,0),
                                    (0,0,0,0,0,0,0,0,0,0),
                                    (0,0,0,0,0,0,0,0,0,0),
                                    (0,0,0,0,0,0,0,0,0,0),
                                    (8,0,0,0,0,0,0,8,0,0),
                                    (0,0,0,0,0,0,8,8,0,0),
                                    (0,0,0,0,0,0,0,0,0,0),
                                    (8,0,0,0,0,0,0,0,0,0));

implementation

{$R *.DFM}

procedure MyFilter(src: PDoubleArray; xres, yres: Integer;
                   matrix: TMatrix; bias, mplr: Integer);
var x, y, i, l: Integer;
    t: PDoubleArray;
    value: Double;
begin
  l := xres * yres;
  t := AllocMem(l * sizeof(Double));
// the central part
  for y := 1 to yres - 2 do
    for x := 1 to xres - 2 do
    begin
      i := y * xres + x;
      value := src[i] * matrix[1,1] +
               src[i - xres - 1] * matrix[0,0] +
               src[i - xres]     * matrix[0,1] +
               src[i - xres + 1] * matrix[0,2] +
               src[i - 1]        * matrix[1,0] +
               src[i + 1]        * matrix[1,2] +
               src[i + xres - 1] * matrix[2,0] +
               src[i + xres]     * matrix[2,1] +
               src[i + xres + 1] * matrix[2,2];
      t[i] := (value / mplr) + bias;
    end;

// the edges
  for x := 1 to xres - 2 do
  begin
    i := x;
    value := src[i] * matrix[1,1] +
             src[i - 1]        * matrix[1,0] +
             src[i + 1]        * matrix[1,2] +
             src[i + xres - 1] * matrix[2,0] +
             src[i + xres]     * matrix[2,1] +
             src[i + xres + 1] * matrix[2,2];
    t[i] := (value / mplr) + bias;
  end;

  for x := 1 to xres - 2 do
  begin
    i := (yres - 1) * xres + x;
    value := src[i] * matrix[1,1] +
             src[i - xres - 1] * matrix[0,0] +
             src[i - xres]     * matrix[0,1] +
             src[i - xres + 1] * matrix[0,2] +
             src[i - 1]        * matrix[1,0] +
             src[i + 1]        * matrix[1,2];
    t[i] := (value / mplr) + bias;
  end;

  for y := 1 to yres - 2 do
  begin
    i := y * xres;
    value := src[i] * matrix[1,1] +
             src[i - xres]     * matrix[0,1] +
             src[i - xres + 1] * matrix[0,2] +
             src[i + 1]        * matrix[1,2] +
             src[i + xres]     * matrix[2,1] +
             src[i + xres + 1] * matrix[2,2];
    t[i] := (value / mplr) + bias;
  end;

  for y := 1 to yres - 2 do
  begin
    i := y * xres + (xres - 1);
    value := src[i] * matrix[1,1] +
             src[i - xres - 1] * matrix[0,0] +
             src[i - xres]     * matrix[0,1] +
             src[i - 1]        * matrix[1,0] +
             src[i + xres - 1] * matrix[2,0] +
             src[i + xres]     * matrix[2,1];
    t[i] := (value / mplr) + bias;
  end;

// the corners
  i := 0;
  value := src[i] * matrix[1,1] +
           src[i + 1]        * matrix[1,2] +
           src[i + xres]     * matrix[2,1] +
           src[i + xres + 1] * matrix[2,2];
  t[i] := (value / mplr) + bias;

  i := xres - 1;
  value := src[i] * matrix[1,1] +
           src[i - 1]        * matrix[1,0] +
           src[i + xres - 1] * matrix[2,0] +
           src[i + xres]     * matrix[2,1];
  t[i] := (value / mplr) + bias;

  i := (yres - 1) * xres;
  value := src[i] * matrix[1,1] +
           src[i - xres]     * matrix[0,1] +
           src[i - xres + 1] * matrix[0,2] +
           src[i + 1]        * matrix[1,2];
  t[i] := (value / mplr) + bias;

  i := (yres - 1) * xres + (xres - 1);
  value := src[i] * matrix[1,1] +
           src[i - xres - 1] * matrix[0,0] +
           src[i - xres]     * matrix[0,1] +
           src[i - 1]        * matrix[1,0];
  t[i] := (value / mplr) + bias;  

// copy back to original buffer
  for i := 0 to l - 1 do
    src[i] := t[i];
  FreeMem(t);
end;

procedure TForm1.Button1Click(Sender: TObject);
var x, y: Integer;
    s: String;
begin
  s := '';
  for y := 0 to 9 do
  begin
    for x := 0 to 9 do
      s := s + Format('%6.2f  ', [a[y,x]]);
    s := s + #10#13;
  end;
  Label1.Caption := s;

  MyFilter(@a, 10, 10, m, 0, 8);

  s := '';
  for y := 0 to 9 do
  begin
    for x := 0 to 9 do
      s := s + Format('%6.2f  ', [a[y,x]]);
    s := s + #10#13;
  end;
  Label2.Caption := s;
end;

end.
0
 

Author Comment

by:iwatkins
ID: 1390960
Epsylon,

Nice one, works perfectly on the 10x10 array supplied. I will award you the points now as it works, but I have yet to test it on my 601x601 array. Even so, it appears to be very, very fast.

Anyway, thanks for your effort on this one.

I will let you know how I get on with the rest of the project.

Cheers

Ian
0
 

Author Comment

by:iwatkins
ID: 1390961
Hi All and especially Epsylon,

Working well with a 601x601 array (361201 float values). It is actually taking longer to read in the values from file and back to file than it is to run the 'blur'.

In fact, I have just finished testing and the best 'blur' seems to be by making running the routine 5 times, i.e. 5 passes. This executes in under two seconds on my 450 Mhz.

For anybody else wanting to run this routine, best results are with:

Bias = 0
Divisor = 9

Matrix =
1,1,1
1,1,1
1,1,1
       
Very happy with it.

Cheers
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1390962
Hi, I tested it with a 1000x1000 array and it was ready within a second (450MHz too)     :o)

CPU's are fast these days!!!

....but never fast enough   :o)

Cheers,

Eps.
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…
Suggested Courses

721 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question