One class of image digital filters is described by a rectangular matrix of real coefficients called kernel convoluted in a sliding window of image pixels. Usually the kernel is square 




K

k
l




{\displaystyle K_{kl}}

, where k, l are in the range -R,-R+1,..,R-1,R. W=2R+1 is the kernel width. The filter determines the new value of a monochromatic image pixel Pij as a convolution of the image pixels in the window centered in i, j and the kernel values:







P

i
j


=


∑

k
=
−
R


R



∑

l
=
−
R


R



P

i
+
k
 
j
+
l



K

k
l





{\displaystyle P_{ij}=\displaystyle \sum _{k=-R}^{R}\sum _{l=-R}^{R}P_{i+k\ j+l}K_{kl}}




Color images are usually split into the channels which are filtered independently. A color model can be changed as well, i.e. filtration is performed not necessarily in RGB. Common kernels sizes are 3x3 and 5x5. The complexity of filtrating grows quadratically (O(n2)) with the kernel width.

Task: Write a generic convolution 3x3 kernel filter. Optionally show some end user filters that use this generic one.

(You can use, to test the functions below, these input and output solutions.)

INCLUDE "H6:LOADPPM5.ACT"
 
DEFINE HISTSIZE="256"
 
PROC PutBigPixel(INT x,y BYTE col)
  IF x>=0 AND x<=79 AND y>=0 AND y<=47 THEN
    y==LSH 2
    col==RSH 4
    IF col<0 THEN col=0
    ELSEIF col>15 THEN col=15 FI
    Color=col
    Plot(x,y)
    DrawTo(x,y+3)
  FI
RETURN
 
PROC DrawImage(GrayImage POINTER image INT x,y)
  INT i,j
  BYTE c
 
  FOR j=0 TO image.gh-1
  DO
    FOR i=0 TO image.gw-1
    DO
      c=GetGrayPixel(image,i,j)
      PutBigPixel(x+i,y+j,c)
    OD
  OD
RETURN
 
INT FUNC Clamp(INT x,min,max)
  IF x<min THEN
    RETURN (min)
  ELSEIF x>max THEN
    RETURN (max)
  FI
RETURN (x)
 
PROC Convolution3x3(GrayImage POINTER src,dst
  INT ARRAY kernel INT divisor)
  INT x,y,i,j,ii,jj,index,sum
  BYTE c
 
  FOR j=0 TO src.gh-1
  DO
    FOR i=0 TO src.gw-1
    DO
      sum=0 index=0
      FOR jj=-1 TO 1
      DO
        y=Clamp(j+jj,0,src.gh-1)
        FOR ii=-1 TO 1
        DO
          x=Clamp(i+ii,0,src.gw-1)
          c=GetGrayPixel(src,x,y)
          sum==+c*kernel(index)
          index==+1
        OD
      OD
      c=Clamp(sum/divisor,0,255)
      SetGrayPixel(dst,i,j,c)
    OD
  OD
RETURN
 
PROC Main()
  BYTE CH=$02FC ;Internal hardware value for last key pressed
  BYTE ARRAY dataIn(900),dataOut(900)
  GrayImage in,out
  INT ARRAY sharpenKernel=[
    65535 65535 65535
    65535     9 65535
    65535 65535 65535]
  INT size=[30],x,y,sharpenDivisor=[1]
 
  Put(125) PutE() ;clear the screen
 
  InitGrayImage(in,size,size,dataIn) 
  InitGrayImage(out,size,size,dataOut) 
  PrintE("Loading source image...")
  LoadPPM5(in,"H6:LENA30G.PPM")
  PrintE("Convolution...")
  Convolution3x3(in,out,sharpenKernel,sharpenDivisor)
 
  Graphics(9)
  x=(40-size)/2
  y=(48-size)/2
  DrawImage(in,x,y)
  DrawImage(out,x+40,y)
 
  DO UNTIL CH#$FF OD
  CH=$FF
RETURN