{

   This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
}
unit im_Convolution;

{*********************************************}
{  This unit is a part of ImageE              }
{  Copyright © 2003-2004 R.Geurts             }
{  See Readme.txt for licence information     }
{*********************************************}

interface

uses
  GR32, GR32_Filters,math;

type
  // Indexes 0..8 are the convolution coefficients
  // Index 9 is the normalization constant
  TConvolutionKernel = array[0..49] of Integer;
   TColorFunc = function(Color32: TColor32): Integer;
{  // for 'type safe' versions
  TConvolutionFilter = (cfNone,
                        // Low pass filters
    cfEmbossColor,
    cfEmbossLight,
    cfEmbossMedium,
    cfEmbossDark,
    cfEdgeEnhance,
    cfBlurBartlett,
    cfBlurGaussian,
    cfAverage,
    cfBlur,
    cfBlurSoftly,
    cfBlurMore,
    cfPrewitt,
    cfTracecontour,
    cfSharpen,
    cfSharpenmore,
    cfSharpenless,
    cfUnsharpmask,
    cfEdgesStrong,
    cfEdgesWeak,
    cfEtch,
    cfLaplacianhorzvert,
    cfLaplacianomnidir,
    cfSharpendirectional,
    cfSobelpass,
    cfGlow,
    cfWaggle,
    cfPattern
      );
}



// wrapper for using KERNEL_ARRAY constant with G32_WConvolution
{procedure ApplyWConvolution(Bitmap32: TBitmap32; const Kernel: array of Integer);  }
procedure Convolution(src:tbitmap32; namef:string);
procedure ApplyConvolution(Src: TBitmap32; ray: array of integer; mx:integer);
procedure ApplyConvolution3x3(Src: TBitmap32; const Kernel: array of Integer; divisor:integer);
//procedure GetConvolutionKernel
//  (const ConvolutionFilter: TConvolutionFilter; out Kernel: TConvolutionKernel);
procedure ApplyConvolution5x5(abmp: TBitmap32; const ray: array of Integer; divisor:integer);
procedure ApplyConvolution7x7(abmp: TBitmap32; const ray: array of Integer; divisor:integer);
procedure Kuwahara5x5( aBmp : TBitmap32);


function Set255(Clr : integer) : integer;

const
  // the array with all the filters...
  KERNEL_ARRAY: array [0..25] of TConvolutionKernel = (
{       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 1, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,1), } //nofilter
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0,-1,-1,-1, 0, 0,
         0, 0, 0, 1, 0, 0, 0,
         0, 0, 1, 1, 1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,1), {Emboss Color}
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0,-1, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 1, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,1), {Emboss Color}
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0,-1,-2,-1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 1, 2, 1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,1),  {Emboss Color}
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0,-1,-2,-1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 1, 2, 1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,1),  {Emboss Color}
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0,-1,-2,-1, 0, 0,
         0, 0,-2,16,-2, 0, 0,
         0, 0,-1,-2,-1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,4), {Edge Enhance Sharpen Linear}
       ( 1, 2, 3, 4, 3, 2, 1,
         2, 4, 6, 8, 6, 4, 2,
         3, 6, 9,12, 9, 6, 3,
         4, 8,12,16,12, 8, 4,
         3, 6, 9,12, 9, 6, 3,
         2, 4, 6, 8, 6, 4, 2,
         1, 2, 3, 4, 3, 2, 1,256), {Blur Bartlett}
       ( 1, 4, 8, 10, 8, 4, 1,
         4,12,25,29,25,12, 4,
         8,25,49,58,49,25, 8,
        10,29,58,67,58,29,10,
         8,25,49,58,49,25, 8,
         4,12,25,29,25,12, 4,
         1, 4, 8, 10, 8, 4, 1,999), {Blur Gaussian}
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 1, 1, 1, 0, 0,
         0, 0, 1, 1, 1, 0, 0,
         0, 0, 1, 1, 1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,9), {Average Blur}
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 1, 2, 1, 0, 0,
         0, 0, 2, 4, 2, 0, 0,
         0, 0, 1, 2, 1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,16), {Blur Linear}
{       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 1, 3, 1, 0, 0,
         0, 0, 3,16, 3, 0, 0,
         0, 0, 1, 3, 1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,1),  //Blur Softly }
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 1, 2, 1, 0, 0,
         0, 1, 4, 6, 4, 1, 0,
         0, 2, 6, 8, 6, 2, 0,
         0, 1, 4, 6, 4, 1, 0,
         0, 0, 1, 2, 1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,64),  {Blur More}
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 1, 1, 1, 0, 0,
         0, 0, 1,-2, 1, 0, 0,
         0, 0,-1,-1,-1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,1), {Edge detect linear}
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0,-6,-2,-6, 0, 0,
         0, 0,-1,32,-1, 0, 0,
         0, 0,-6,-2,-6, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,1), {Trace Contour}
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0,-1,-1,-1, 0, 0,
         0, 0,-1,16,-1, 0, 0,
         0, 0,-1,-1,-1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,8), {Sharpen Linear}
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0,-1,-1,-1, 0, 0,
         0, 0,-1,12,-1, 0, 0,
         0, 0,-1,-1,-1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,4), {Sharpen More}
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0,-1,-1,-1, 0, 0,
         0, 0,-1,24,-1, 0, 0,
         0, 0,-1,-1,-1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,16), {Sharpen Less}
       ( 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0,-1,-2,-1, 0, 0,
         0, 0,-2,16,-2, 0, 0,
         0, 0,-1,-2,-1, 0, 0,
         0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0,4), {UnSharp Mask}
     ( 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0, 1, 3, 1, 0, 0,
       0, 0, 3,-16,3, 0, 0,
       0, 0, 1, 3, 1, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,1), {Edges Strong}
     ( 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 1, 0, 0, 0,
       0, 0, 1,-4, 1, 0, 0,
       0, 0, 0, 1, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,1), {Edges Weak}
     ( 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0,-6, 2,-6, 0, 0,
       0, 0,-1,32,-1, 0, 0,
       0, 0,-6,-2,-6, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,1), {Etch}
     ( 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0, 0,-1, 0, 0, 0,
       0, 0,-1, 4,-1, 0, 0,
       0, 0, 0,-1, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,1), {Laplacian horz./vert. (Edge detect linear)}
     ( 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0,-1,-1,-1, 0, 0,
       0, 0,-1, 8,-1, 0, 0,
       0, 0,-1,-1,-1, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,1), {Laplacian omnidir. (Edge detect linear)}
     ( 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0,-3,-3,-3, 0, 0,
       0, 0, 0,16, 0, 0, 0,
       0, 0, 1, 1, 1, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,10), {Sharpen directional (Sharpen linear)}
     ( 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0, 1, 2, 1, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0,-1,-2,-1, 0, 0,
       0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0,1), {Sobel pass (Edge detect linear)}
     ( 0, 0, 0, 0, 0, 0, 0,
       0, 1, 2, 2, 2, 1, 0,
       0, 2, 0, 0, 0, 2, 0,
       0, 2, 0,-20,0, 2, 0,
       0, 2, 0, 0, 0, 2, 0,
       0, 1, 2, 2, 2, 1, 0,
       0, 0, 0, 0, 0, 0, 0,8), {Glow (Effects linear)}
     ( 0, 1, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 1,
       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, 1, 0, 0, 0, 0,3), {Waggle (Effects linear)}
     ( 0, 0, 0, 0, 0, 0, 0,
       0, 0, -4, -9, -4, 0, 0,
       0, -4, -24, -1, -24, -4, 0,
       0, -9, -1, 168, -1, -9, 0,
       0, -4, -24, -1, -24, -4, 0,
       0, 0, -4, -9, -4, 0, 0,
       0, 0, 0, 0, 0, 0, 0,1) {Pattern (Edge detect linear)}
       );

  // Filter constants, to pull from array
{    NONE = 0;
    EmbossColor= 1;
    EmbossLight= 2;
    EmbossMedium= 3;
    EmbossDark= 4;
    EdgeEnhance= 5;
    BlurBartlett= 6;
    BlurGaussian= 7;
    Average= 8;
    Blur= 9;
    BlurSoftly= 10;
    BlurMore= 11;
    Prewitt= 12;
    Tracecontour= 13;
    Sharpen= 14;
    Sharpenmore= 15;
    Sharpenless= 16;
    Unsharpmask= 17;
    EdgesStrong= 18;
    EdgesWeak= 19;
    Etch= 20;
    Laplacianhorzvert= 21;
    Laplacianomnidir= 22;
    Sharpendirectional= 23;
    Sobelpass= 24;
    Glow= 25;
    Waggle= 26;
    Pattern= 27;

}
  // use this to fill a combo box
  CONVOLUTION_FILTERNAMES: array[0..25] of string =
    (
//    'No filtering',
    'Emboss Color',
    'Emboss Light',
    'Emboss Medium',
    'Emboss Dark',
    'Edge Enhance',
    'Blur Bartlett',
    'Blur Gaussian',
    'Average',
    'Blur',
//    'Blur Softly',
    'Blur More',
    'Prewitt',
    'Trace contour',
    'Sharpen',
    'Sharpen more',
    'Sharpen less',
    'Unsharp mask',
    'Edges Strong',
    'Edges Weak',
    'Etch',
    'Laplacian horz./vert.',
    'Laplacian omnidir.',
    'Sharpen directional',
    'Sobel pass',
    'Glow',
    'Waggle',
    'Pattern'
    );

  // for EnhanceDetail procedures
  HPrewitt: array[0..8] of Integer = (-1, -1, -1,  0,  0,  0,  1,  1,  1);
  VPrewitt: array[0..8] of Integer = ( 1,  0, -1,  1,  0, -1,  1,  0, -1);

implementation

procedure ApplyConvolution(Src: TBitmap32; ray : array of integer; mx:integer);
begin
 case mx of
 3: applyconvolution3x3(src,ray,ray[49]);
 5: applyconvolution5x5(src,ray,ray[49]);
 7: applyconvolution7x7(src,ray,ray[49]);
 end;
end;

procedure Convolution(src:tbitmap32; namef:string);
begin
 if namef='EMBOSSCOLOR' then applyconvolution(src,kernel_array[1],7);
 if namef='EDGEENHANCE' then applyconvolution(src,kernel_array[5],7);
 if namef='AVERAGE' then applyconvolution(src,kernel_array[8],7);
 if namef='BLUR' then applyconvolution(src,kernel_array[9],7);
 if namef='BLURMORE' then applyconvolution(src,kernel_array[11],7);
 if namef='PREWITT' then applyconvolution(src,kernel_array[12],7);
 if namef='TRACECOUNTOUR' then applyconvolution(src,kernel_array[13],7);
 if namef='SHARPEN' then applyconvolution(src,kernel_array[14],7);
 if namef='SHARPENMORE' then applyconvolution(src,kernel_array[15],7);
 if namef='ETCH' then applyconvolution(src,kernel_array[20],7);
 if namef='LAPLACIANOMNIDIR' then applyconvolution(src,kernel_array[22],7);
 if namef='SOBELPASS' then applyconvolution(src,kernel_array[24],7);
 if namef='EDGESTRONG' then applyconvolution(src,kernel_array[16],7);
end;

procedure ApplyConvolution3x3(Src: TBitmap32; const Kernel: array of Integer; divisor:integer);
var
  i, x, y: Integer;
  PixelArray: array[0..8] of PColor32;
  // !!!   Make next line part of PixelArray  !!!
  DstPixel: PColor32;
  C, R, G, B: Integer;
  Rc, Gc, Bc: Cardinal;
  dst:tbitmap32;
begin
//  divisor:=kernel[49];
  dst:=tbitmap32.create;

  Dst.Assign(Src);
  with Src do
    for y := 1 to Height - 2 do begin
      PixelArray[0] := PixelPtr[0, y - 1];
      PixelArray[1] := PixelPtr[1, y - 1];
      PixelArray[2] := PixelPtr[2, y - 1];
      PixelArray[3] := PixelPtr[0, y];
      PixelArray[4] := PixelPtr[1, y];
      PixelArray[5] := PixelPtr[2, y];
      PixelArray[6] := PixelPtr[0, y + 1];
      PixelArray[7] := PixelPtr[1, y + 1];
      PixelArray[8] := PixelPtr[2, y + 1];
      DstPixel := Dst.PixelPtr[1, y];
      for x := 1 to Width - 2 do begin
        R := 0;
        G := 0;
        B := 0;
        for i := 0 to 8 do begin
          C := PixelArray[i]^;
          R := R + ((C and $00FF0000) shr 16) * Kernel[i];
          G := G + ((C and $0000FF00) shr 8) * Kernel[i];
          B := B + ( C and $000000FF) * Kernel[i];
        end;
        R := R div divisor;
        G := G div divisor;
        B := B div divisor;
        if R > 255 then Rc := 255
        else if R < 0 then Rc := 0
        else Rc := R;
        if G > 255 then Gc := 255
        else if G < 0 then Gc := 0
        else Gc := G;
        if B > 255 then Bc := 255
        else if B < 0 then Bc := 0
        else Bc := B;
        DstPixel^ := $FF000000 + Rc shl 16 + Gc shl 8 + Bc;
        for i := 0 to 8 do
          Inc(PixelArray[i]);
        Inc(DstPixel);
      end;
    end;
    Src.Assign(Dst);
    Dst.Free;

end;

{procedure GetConvolutionKernel
  (const ConvolutionFilter: Tconvolutionfilter; out Kernel: TConvolutionKernel);
begin
  case ConvolutionFilter of
    cfNone: Kernel := KERNEL_ARRAY[NONE];
    cfEmbossColor: Kernel := KERNEL_ARRAY[EmbossColor];
    cfEmbossLight: Kernel := KERNEL_ARRAY[EmbossLight];
    cfEmbossMedium: Kernel := KERNEL_ARRAY[EmbossMedium];
    cfEmbossDark: Kernel := KERNEL_ARRAY[EmbossDark];
    cfEdgeEnhance: Kernel := KERNEL_ARRAY[EdgeEnhance];
    cfBlurBartlett: Kernel := KERNEL_ARRAY[BlurBartlett];
    cfBlurGaussian: Kernel := KERNEL_ARRAY[BlurGaussian];
    cfAverage: Kernel := KERNEL_ARRAY[Average];
    cfBlur: Kernel := KERNEL_ARRAY[Blur];
    cfBlurSoftly: Kernel := KERNEL_ARRAY[BlurSoftly];
    cfBlurMore: Kernel := KERNEL_ARRAY[BlurMore];
    cfPrewitt: Kernel := KERNEL_ARRAY[Prewitt];
    cfTracecontour: Kernel := KERNEL_ARRAY[Tracecontour];
    cfSharpen: Kernel := KERNEL_ARRAY[Sharpen];
    cfSharpenmore: Kernel := KERNEL_ARRAY[Sharpenmore];
    cfSharpenless: Kernel := KERNEL_ARRAY[Sharpenless];
    cfUnsharpmask: Kernel := KERNEL_ARRAY[Unsharpmask];
    cfEdgesStrong: Kernel := KERNEL_ARRAY[EdgesStrong];
    cfEdgesWeak: Kernel := KERNEL_ARRAY[EdgesWeak];
    cfEtch: Kernel := KERNEL_ARRAY[Etch];
    cfLaplacianhorzvert: Kernel := KERNEL_ARRAY[Laplacianhorzvert];
    cfLaplacianomnidir: Kernel := KERNEL_ARRAY[Laplacianomnidir];
    cfSharpendirectional: Kernel := KERNEL_ARRAY[Sharpendirectional];
    cfSobelpass: Kernel := KERNEL_ARRAY[Sobelpass];
    cfGlow: Kernel := KERNEL_ARRAY[Glow];
    cfWaggle: Kernel := KERNEL_ARRAY[Waggle];
    cfPattern: Kernel := KERNEL_ARRAY[Pattern];

  end;
end;
}
function Set255(Clr : integer) : integer;
asm
  MOV  EAX,Clr  // store value in EAX register (32-bit register)
  CMP  EAX,254  // compare it to 254
  JG   @SETHI   // if greater than 254 then go set to 255 (max value)
  CMP  EAX,1    // if less than 255, compare to 1
  JL   @SETLO   // if less than 1 go set to 0 (min value)
  RET           // otherwise it doesn't change, just exit
@SETHI:         // Set value to 255
  MOV  EAX,255  // Move 255 into the EAX register
  RET           // Exit (result value is the EAX register value)
@SETLO:         // Set value to 0
  MOV  EAX,0    // Move 0 into EAX register
end;            // Result is in EAX

procedure ApplyConvolution5x5(abmp: TBitmap32; const ray: array of Integer; divisor:integer);
//procedure ConvolveI5x5(ray : array of integer; z : word; aBmp : TBitmap32);
var
  O, T,T2, C, B, B2 : PColor32Array; // Scanlines
  x, y              : integer;
  tBufr             : TBitmap32; // temp bitmap
  Red,Green,Blue    : Integer;
  z:integer;
begin
//  z:=ray[49];
  z:=divisor;

  tBufr := TBitmap32.Create;
//  CheckParams(tBufr,aBmp);
  tBufr.Assign(aBmp);

  for x := 2 to aBmp.Height - 3 do begin // Walk scanlines
    O := aBmp.ScanLine[x];     // New Target (Original)
    T2:= tBufr.ScanLine[x-2];  //old x-2  (Top)
    T := tBufr.ScanLine[x-1];  //old x-1  (Top)
    C := tBufr.ScanLine[x];    //old x    (Center)
    B := tBufr.ScanLine[x+1];  //old x+1  (Bottom)
    B2:= tBufr.ScanLine[x+2];  //old x+2  (Bottom)

  // Now do the main piece
    for y := 2 to (tBufr.Width - 3) do begin  // Walk pixels

    //NS:=0;
    //for i:=0 to 4 do

      Red := Set255(
         (
RedComponent(T2[y-2])*ray[0] + RedComponent(T2[y-1])*ray[1] + RedComponent(T2[y])*ray[2] + RedComponent(T2[y+1])*ray[3] + RedComponent(T2[y+2])*ray[4]+
RedComponent( T[y-2])*ray[5] + RedComponent( T[y-1])*ray[6] + RedComponent( T[y])*ray[7] + RedComponent( T[y+1])*ray[8] + RedComponent( T[y+2])*ray[9]+
RedComponent( C[y-2])*ray[10]+ RedComponent( C[y-1])*ray[11]+ RedComponent( C[y])*ray[12]+ RedComponent( C[y+1])*ray[13]+ RedComponent( C[y+2])*ray[14]+
RedComponent( B[y-2])*ray[15]+ RedComponent( B[y-1])*ray[16]+ RedComponent( B[y])*ray[17]+ RedComponent( B[y+1])*ray[18]+ RedComponent( B[y+2])*ray[19]+
RedComponent(B2[y-2])*ray[20]+ RedComponent(B2[y-1])*ray[21]+ RedComponent(B2[y])*ray[22]+ RedComponent(B2[y+1])*ray[23]+ RedComponent(B2[y+2])*ray[24]
          ) div z   );

      Blue := Set255(
         (
BlueComponent(T2[y-2])*ray[0] + BlueComponent(T2[y-1])*ray[1] + BlueComponent(T2[y])*ray[2] + BlueComponent(T2[y+1])*ray[3] + BlueComponent(T2[y+2])*ray[4]+
BlueComponent( T[y-2])*ray[5] + BlueComponent( T[y-1])*ray[6] + BlueComponent( T[y])*ray[7] + BlueComponent( T[y+1])*ray[8] + BlueComponent( T[y+2])*ray[9]+
BlueComponent( C[y-2])*ray[10]+ BlueComponent( C[y-1])*ray[11]+ BlueComponent( C[y])*ray[12]+ BlueComponent( C[y+1])*ray[13]+ BlueComponent( C[y+2])*ray[14]+
BlueComponent( B[y-2])*ray[15]+ BlueComponent( B[y-1])*ray[16]+ BlueComponent( B[y])*ray[17]+ BlueComponent( B[y+1])*ray[18]+ BlueComponent( B[y+2])*ray[19]+
BlueComponent(B2[y-2])*ray[20]+ BlueComponent(B2[y-1])*ray[21]+ BlueComponent(B2[y])*ray[22]+ BlueComponent(B2[y+1])*ray[23]+ BlueComponent(B2[y+2])*ray[24]
          ) div z );

      Green := Set255(
         (
GreenComponent(T2[y-2])*ray[0] + GreenComponent(T2[y-1])*ray[1] + GreenComponent(T2[y])*ray[2] + GreenComponent(T2[y+1])*ray[3] + GreenComponent(T2[y+2])*ray[4]+
GreenComponent( T[y-2])*ray[5] + GreenComponent( T[y-1])*ray[6] + GreenComponent( T[y])*ray[7] + GreenComponent( T[y+1])*ray[8] + GreenComponent( T[y+2])*ray[9]+
GreenComponent( C[y-2])*ray[10]+ GreenComponent( C[y-1])*ray[11]+ GreenComponent( C[y])*ray[12]+ GreenComponent( C[y+1])*ray[13]+ GreenComponent( C[y+2])*ray[14]+
GreenComponent( B[y-2])*ray[15]+ GreenComponent( B[y-1])*ray[16]+ GreenComponent( B[y])*ray[17]+ GreenComponent( B[y+1])*ray[18]+ GreenComponent( B[y+2])*ray[19]+
GreenComponent(B2[y-2])*ray[20]+ GreenComponent(B2[y-1])*ray[21]+ GreenComponent(B2[y])*ray[22]+ GreenComponent(B2[y+1])*ray[23]+ GreenComponent(B2[y+2])*ray[24]
          ) div z    );

      O[y]:=Color32(Red, Green, Blue);

    end;
  end;
  tBufr.Free;
end;

procedure ApplyConvolution7x7(abmp: TBitmap32; const ray: array of Integer; divisor:integer);
//procedure ConvolveI5x5(ray : array of integer; z : word; aBmp : TBitmap32,); mx=arraysize
var
  O, T,T2, C, B, B2,t3,b3 : PColor32Array; // Scanlines
  x, y              : integer;
  tBufr             : TBitmap32; // temp bitmap
  Red,Green,Blue    : Integer;
  z:integer;
begin
//  z:=ray[49];
  z:=divisor;
  tBufr := TBitmap32.Create;
//  CheckParams(tBufr,aBmp);
  tBufr.Assign(aBmp);
  for x := 3 to aBmp.Height - 4 do begin // Walk scanlines
    O := aBmp.ScanLine[x];     // New Target (Original)
    T3:= tBufr.ScanLine[x-3];  //old x-2  (Top)
    T2:= tBufr.ScanLine[x-2];  //old x-2  (Top)
    T := tBufr.ScanLine[x-1];  //old x-1  (Top)
    C := tBufr.ScanLine[x];    //old x    (Center)
    B := tBufr.ScanLine[x+1];  //old x+1  (Bottom)
    B2:= tBufr.ScanLine[x+2];  //old x+2  (Bottom)
    B3:= tBufr.ScanLine[x+3];  //old x+2  (Bottom)

  // Now do the main piece
    for y := 3 to (tBufr.Width - 4) do begin  // Walk pixels

    //NS:=0;
    //for i:=0 to 4 do

      Red := Set255(
         (
RedComponent(T3[y-3])*ray[0] + RedComponent(T3[y-2])*ray[1] + RedComponent(T3[y-1])*ray[2] + RedComponent(T3[y])*ray[3] + RedComponent(T3[y+1])*ray[4]+ RedComponent(T3[y+2])*ray[5] + RedComponent(T3[y+3])*ray[6]+
RedComponent(T2[y-3])*ray[7] + RedComponent(T2[y-2])*ray[8] + RedComponent(T2[y-1])*ray[9] + RedComponent(T2[y])*ray[10] + RedComponent(T2[y+1])*ray[11]+ RedComponent(T3[y+2])*ray[12] + RedComponent(T3[y+3])*ray[13]+
RedComponent( T[y-3])*ray[14]+ RedComponent( T[y-2])*ray[15]+ RedComponent( T[y-1])*ray[16]+ RedComponent( T[y])*ray[17]+ RedComponent( T[y+1])*ray[18]+ RedComponent(T3[y+2])*ray[19] + RedComponent(T3[y+3])*ray[20]+
RedComponent( C[y-3])*ray[21]+ RedComponent( C[y-2])*ray[22]+ RedComponent( C[y-1])*ray[23]+ RedComponent( C[y])*ray[24]+ RedComponent( C[y+1])*ray[25]+ RedComponent(T3[y+2])*ray[26] + RedComponent(T3[y+3])*ray[27]+
RedComponent( B[y-3])*ray[28]+ RedComponent( B[y-2])*ray[29]+ RedComponent( B[y-1])*ray[30]+ RedComponent( B[y])*ray[31]+ RedComponent( B[y+1])*ray[32]+ RedComponent(T3[y+2])*ray[33] + RedComponent(T3[y+3])*ray[34]+
RedComponent(B2[y-3])*ray[35]+ RedComponent(B2[y-2])*ray[36]+ RedComponent(B2[y-1])*ray[37]+ RedComponent(B2[y])*ray[38]+ RedComponent(B2[y+1])*ray[39]+ RedComponent(T3[y+2])*ray[40] + RedComponent(T3[y+3])*ray[41]+
RedComponent(B3[y-3])*ray[42]+ RedComponent(B3[y-2])*ray[43]+ RedComponent(B3[y-1])*ray[44]+ RedComponent(B3[y])*ray[45]+ RedComponent(B3[y+1])*ray[46]+ RedComponent(T3[y+2])*ray[47] + RedComponent(T3[y+3])*ray[48]
     ) div z   );

      Blue := Set255(
         (
Bluecomponent(T3[y-3])*ray[0] + Bluecomponent(T3[y-2])*ray[1] + Bluecomponent(T3[y-1])*ray[2] + Bluecomponent(T3[y])*ray[3] + Bluecomponent(T3[y+1])*ray[4]+ Bluecomponent(T3[y+2])*ray[5] + Bluecomponent(T3[y+3])*ray[6]+
Bluecomponent(T2[y-3])*ray[7] + Bluecomponent(T2[y-2])*ray[8] + Bluecomponent(T2[y-1])*ray[9] + Bluecomponent(T2[y])*ray[10] + Bluecomponent(T2[y+1])*ray[11]+ Bluecomponent(T3[y+2])*ray[12] + Bluecomponent(T3[y+3])*ray[13]+
Bluecomponent( T[y-3])*ray[14]+ Bluecomponent( T[y-2])*ray[15]+ Bluecomponent( T[y-1])*ray[16]+ Bluecomponent( T[y])*ray[17]+ Bluecomponent( T[y+1])*ray[18]+ Bluecomponent(T3[y+2])*ray[19] + Bluecomponent(T3[y+3])*ray[20]+
Bluecomponent( C[y-3])*ray[21]+ Bluecomponent( C[y-2])*ray[22]+ Bluecomponent( C[y-1])*ray[23]+ Bluecomponent( C[y])*ray[24]+ Bluecomponent( C[y+1])*ray[25]+ Bluecomponent(T3[y+2])*ray[26] + Bluecomponent(T3[y+3])*ray[27]+
Bluecomponent( B[y-3])*ray[28]+ Bluecomponent( B[y-2])*ray[29]+ Bluecomponent( B[y-1])*ray[30]+ Bluecomponent( B[y])*ray[31]+ Bluecomponent( B[y+1])*ray[32]+ Bluecomponent(T3[y+2])*ray[33] + Bluecomponent(T3[y+3])*ray[34]+
Bluecomponent(B2[y-3])*ray[35]+ Bluecomponent(B2[y-2])*ray[36]+ Bluecomponent(B2[y-1])*ray[37]+ Bluecomponent(B2[y])*ray[38]+ Bluecomponent(B2[y+1])*ray[39]+ Bluecomponent(T3[y+2])*ray[40] + Bluecomponent(T3[y+3])*ray[41]+
Bluecomponent(B3[y-3])*ray[42]+ Bluecomponent(B3[y-2])*ray[43]+ Bluecomponent(B3[y-1])*ray[44]+ Bluecomponent(B3[y])*ray[45]+ Bluecomponent(B3[y+1])*ray[46]+ Bluecomponent(T3[y+2])*ray[47] + Bluecomponent(T3[y+3])*ray[48]
          ) div z );

      Green := Set255(
         (
GreenComponent(T3[y-3])*ray[0] + GreenComponent(T3[y-2])*ray[1] + GreenComponent(T3[y-1])*ray[2] + GreenComponent(T3[y])*ray[3] + GreenComponent(T3[y+1])*ray[4]+ GreenComponent(T3[y+2])*ray[5] + GreenComponent(T3[y+3])*ray[6]+
GreenComponent(T2[y-3])*ray[7] + GreenComponent(T2[y-2])*ray[8] + GreenComponent(T2[y-1])*ray[9] + GreenComponent(T2[y])*ray[10] + GreenComponent(T2[y+1])*ray[11]+ GreenComponent(T3[y+2])*ray[12] + GreenComponent(T3[y+3])*ray[13]+
GreenComponent( T[y-3])*ray[14]+ GreenComponent( T[y-2])*ray[15]+ GreenComponent( T[y-1])*ray[16]+ GreenComponent( T[y])*ray[17]+ GreenComponent( T[y+1])*ray[18]+ GreenComponent(T3[y+2])*ray[19] + GreenComponent(T3[y+3])*ray[20]+
GreenComponent( C[y-3])*ray[21]+ GreenComponent( C[y-2])*ray[22]+ GreenComponent( C[y-1])*ray[23]+ GreenComponent( C[y])*ray[24]+ GreenComponent( C[y+1])*ray[25]+ GreenComponent(T3[y+2])*ray[26] + GreenComponent(T3[y+3])*ray[27]+
GreenComponent( B[y-3])*ray[28]+ GreenComponent( B[y-2])*ray[29]+ GreenComponent( B[y-1])*ray[30]+ GreenComponent( B[y])*ray[31]+ GreenComponent( B[y+1])*ray[32]+ GreenComponent(T3[y+2])*ray[33] + GreenComponent(T3[y+3])*ray[34]+
GreenComponent(B2[y-3])*ray[35]+ GreenComponent(B2[y-2])*ray[36]+ GreenComponent(B2[y-1])*ray[37]+ GreenComponent(B2[y])*ray[38]+ GreenComponent(B2[y+1])*ray[39]+ GreenComponent(T3[y+2])*ray[40] + GreenComponent(T3[y+3])*ray[41]+
GreenComponent(B3[y-3])*ray[42]+ GreenComponent(B3[y-2])*ray[43]+ GreenComponent(B3[y-1])*ray[44]+ GreenComponent(B3[y])*ray[45]+ GreenComponent(B3[y+1])*ray[46]+ GreenComponent(T3[y+2])*ray[47] + GreenComponent(T3[y+3])*ray[48]
          ) div z    );

      O[y]:=Color32(Red, Green, Blue);
    end;
    end;
  tBufr.Free;
end;


procedure Kuwahara5x5( aBmp : TBitmap32);
Var
  O, T,T2,C,B,B2  : PColor32Array; // Scanlines
  NS,i,j,k,n      : integer;
  x, y            : integer;
  tBufr           : TBitmap32; // temp bitmap
  Red,Green,Blue  : Integer;

  Region1         : array of Double;
  Region2         : array of Double;
  Region3         : array of Double;
  Region4         : array of Double;

  Mean            : array[1..4] of Extended;
  StdDev          : array[1..4] of Extended;

  minStdDev       : Extended;
  ColorFunc       : TColorFunc;

  Color           : array [0..3] of integer;
  step            : integer;
  c1,c2           : integer;
Begin

tBufr := TBitmap32.Create;
Try

 // CheckParams(tBufr,aBmp);
  tBufr.Assign(aBmp);


  for x := 2 to aBmp.Height - 3 do
  begin
    O := aBmp.ScanLine[x];     // New Target (Original)

    T2:= tBufr.ScanLine[x-2];  //old x-2  (Top)
    T := tBufr.ScanLine[x-1];  //old x-1  (Top)
    C := tBufr.ScanLine[x];    //old x    (Center)
    B := tBufr.ScanLine[x+1];  //old x+1  (Bottom)
    B2:= tBufr.ScanLine[x+2];  //old x+2  (Bottom)


    //Now slide the region 5x5
    for y := 2 to (tBufr.Width - 3) do
     begin


          //fill regions array
          SetLength(Region1,6);
          SetLength(Region2,6);
          SetLength(Region3,6);
          SetLength(Region4,6);


             begin
                        c1:=1;
                        c2:=3;
             end;

          for step:=c1 to c2 do
          begin
             case step of
               0 : ColorFunc:=Intensity;
               1 : ColorFunc:=RedComponent;
               2 : ColorFunc:=GreenComponent;
               3 : ColorFunc:=BlueComponent;
             end;

             for i:=0 to 2 do
               for j:=0 to 1 do
                begin
                   k:=j*3+i;
                   case j of
                     0 : Region1[k]:=ColorFunc(T[y-i]);
                     1 : Region1[k]:=ColorFunc(T2[y-i]);
                   end;
                end;

             for i:=0 to 2 do
               for j:=0 to 1 do
                begin
                   k:=j*3+i;
                   case j of
                     0 : Region4[k]:=ColorFunc(B[y+i]);
                     1 : Region4[k]:=ColorFunc(B2[y+i]);
                   end;
                end;

             for i:=0 to 1 do
               for j:=0 to 2 do
                begin
                   k:=j*2+i;
                   case j of
                     0 : Region2[k]:=ColorFunc(C[y+i]);
                     1 : Region2[k]:=ColorFunc(T[y+i]);
                     2 : Region2[k]:=ColorFunc(T2[y+i]);
                   end;
                end;

             for i:=0 to 1 do
               for j:=0 to 2 do
                begin
                   k:=j*2+i;
                   case j of
                     0 : Region3[k]:=ColorFunc(C[y-i]);
                     1 : Region3[k]:=ColorFunc(B[y-i]);
                     2 : Region3[k]:=ColorFunc(B2[y-i]);
                   end;
                end;

             MeanAndStdDev(Region1, Mean[1], StdDev[1]);
             MeanAndStdDev(Region2, Mean[2], StdDev[2]);
             MeanAndStdDev(Region3, Mean[3], StdDev[3]);
             MeanAndStdDev(Region4, Mean[4], StdDev[4]);

             minStdDev:=StdDev[1];
             n:=1;
             for i:=2 to 4 do
              if StdDev[i]<minStdDev then
               begin
                 minStdDev:=StdDev[i];
                 n:=i;
               end;

             Color[step]:=Round(Mean[n]);

          end;//step

             O[y]:=Color32(Color[1],Color[2],Color[3]);

    end;//y
  end;//x

finally
 tBufr.Free;
end;

end;




end.
