Next: , Previous: , Up: Image Processing   [Contents][Index]


Kernel Structure and Accessors

The Guile-CV procedures and methods related to kernel data structure, creating and accessing kernels.

Procedures

k-make
k-make-circular-mask
k-width
k-height
k-size
k-channel
kernel?
k-ref
k-fast-ref
k-set!
k-fast-set!
k-offset
k-fast-offset
k-display

Description

A Guile-CV kernel is represented by a list containing the following elements:

(width height kdata)

where kdata is a vector of (* width height) cells. More precisely, kdata is an srfi-4 homogeneous numeric vector of 64 bit floats, called f64vector, knowing that f64 is the C type double.

The external representation (ie. read syntax) for kdata vectors is #f64(…). As an example, the identity kernel of width 3 and height 3, initialized to 0.0 is represented by the following expression:

(3 3 #f64(0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0))

The kernel width and height can be different (kernels can be rectangular), but both width and height must be odd values.

Guile-CV provides useful accessors for kernel fields, however, if you need them all, just like for accessing image fields, your best friend is (ice-9 match), here is an example:

,use (cv)
(match kernel
  ((width height kdata)
   ... your code here ...))

Note that the (cv) module imports and re-exports, among may others, the public interface of (ice-9 match).

Guile-CV defines a few useful kernels, see kernel variables at the end of this section, that you both may want to use and reuse: it will be easier, if you need to do so, to define your own kernels reusing an existing one, see the (cv kdata) module.

Procedures

Procedure: k-make width height [values #f] [norm #f]

Returns a new kernel.

The kdata value of this new kernel is an srfi-4 homogeneous numeric vector of 64 bit floats, f64vector, composed of width by height cells.

The optional values argument can be:

#f

kdata is initialized to the ‘identity’ kernel (all zeros except the center of the kernel, initialzed to 1)

a single value

all kdata cells are initialized using that single value

a list of values

a list of width by height values, used to initialzed kdata, in the order they are given

The optional norm argument can be:

#f

in this case, kdata is not normalized

#t

unless values would be #f, kdata is normalized using (reduce + 0 values)

a single value

all kdata cells are normalized using that value, which must be a number different from 0

When both values and norm are passed - which is mandatory if you want to pass norm (since these are optional arguments, as opposed to keyword arguments) - values must precede norm on the arguments list.

As an example, here is how to define a 3 x 3 normalized mean kernel:

,use (cv)
(k-make 3 3 1 #t)
-|
$2 = (3 3 #f64(0.1111111111111111 0.1111111111111111  # # # # …))
(k-display $2)
-|

    0.11111    0.11111    0.11111
    0.11111    0.11111    0.11111
    0.11111    0.11111    0.11111
Procedure: k-make-circular-mask radius [value 1] [norm #f]

Returns a new circular mask kernel.

The kdata value of this new kernel is an srfi-4 homogeneous numeric vector of 64 bit floats, f64vector, composed of width by height cells where width and height are equal and odd values determined by the procedure.

The mandatory radius argument must be a floating point number satisfying the following predicate: (float>=? radius 0.5).

The optional norm argument can be:

#f

in this case, kdata is not normalized

#t

kdata values are normalized using (* n value), where n is the number of non zero elements of the circular kernel mask being defined.

When both value and norm are passed - which is mandatory if you want to pass norm (since these are optional arguments, as opposed to optional keyword arguments) - value must precede norm on the arguments list.

To illustrate, here are the circular kernel masks of radius 0.5, 1, 1.5 respectively:

...
(for-each (lambda (i)
            (k-display (k-make-circular-mask i)
                       #:proc float->int))
  '(0.5 1.0 1.5))
-|

  0  1  0
  1  1  1
  0  1  0


  1  1  1
  1  1  1
  1  1  1


  0  0  1  0  0
  0  1  1  1  0
  1  1  1  1  1
  0  1  1  1  0
  0  0  1  0  0

To better illustrate, let’s define a bigger circular kernel mask, transform it to an image and im-show it:

...
(match (k-make-circular-mask 49)
  ((w h kdata) (list w h 1 (list (f64vector->f32vector kdata)))))
  -|
$6 = (99 99 1 (#f32(0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 # …)))
(im-show $6 'scale)

And you should see the following image9

circular-kernel-mask-49
Procedure: k-width kernel
Procedure: k-height kernel
Procedure: k-size kernel
Procedure: k-channel kernel

Returns, respectively, the width, the height, the list of width and height or the kdata for kernel.

Procedure: kernel? kernel

Returns #t if kernel is a Guile-CV kernel.

Procedure: k-ref kernel i j
Procedure: k-fast-ref kernel i j

Returns the value stored at position i and j of the kernel.

k-fast-ref does not check the validity of its arguments: use it at your own risk.

Procedure: k-set! kernel i j value
Procedure: k-fast-set! kernel i j value

Returns nothing.

Sets the value stored at position i and j of the kernel to value.

k-fast-set! does not check the validity of its arguments: use it at your own risk.

Procedure: k-offset i j width height
Procedure: k-fast-offset i j width

Returns the kernel offset for the i and j indices, based on the width and height of the kernel.

This procedure converts the matrix indices i and j to a vector offset for a kernel of size width and height.

k-fast-offset does not check the validity of its arguments: use it at your own risk.

Procedure: k-display image [#:proc #f] [#:port (current-output-port)]

Returns nothing.

Displays the content of kernel on port, applying proc to each kernel value.

,use (cv)
(k-display %k-laplacian)
-|
    0.37500    0.25000    0.37500
    0.25000   -2.50000    0.25000
    0.37500    0.25000    0.37500

Variables

%k-identity
%k-edge0
%k-edge1
%k-sharpen
%k-mean
%k-gaussian-blur0
%k-gaussian-blur1
%k-unsharp
%k-emboss
%k-laplacian
%k-prewitt-y
%k-prewitt-x
%k-sobel-y
%k-sobel-x

Notes: (a) the following kernels are merely offered as ‘didactic’ examples, some of these were used ‘in the old days’, but in most cases, you will find and prefer to use a ‘specific’ and ‘modern’ procedure that will give (much) better results, such as, im-gaussian-blur, im-gaussian-sharp, im-sharpen (a simple sharpening procedure), im-canny (edge detection) ... and (b) in order to make these definitions easier to read, we’ve added some spaces and newlines.

Variable: %k-identity
(k-display %k-identity #:proc float->int)
-|
  0  0  0
  0  1  0
  0  0  0
Variable: %k-edge0
(k-make 3 3
        '(  1  0 -1
            0  0  0
           -1  0  1  ))
Variable: %k-edge1
(k-make 3 3
        '(  0  1  0
            1 -4  1
            0  1  0  ))
Variable: %k-sharpen
(k-make 3 3
        '( -1  -1  -1
           -1   9  -1
           -1  -1  -1  ))
Variable: %k-mean
(k-make 3 3
        '(  1  1  1
            1  1  1
            1  1  1  )
        9)
Variable: %k-gaussian-blur0
(k-make 3 3
        '(  1  2  1
            2  4  2
            1  2  1  )
        16)
Variable: %k-gaussian-blur1
(k-make 5 5
        '(  1   4   6   4  1
            4  16  24  16  4
            6  24  36  24  6
            4  16  24  16  4
            1   4   6   4  1  )
        256)
Variable: %k-unsharp
(k-make 5 5
        '(  1   4    6   4  1
            4  16   24  16  4
            6  24 -476  24  6
            4  16   24  16  4
            1   4    6   4  1  )
        -256)
Variable: %k-emboss

Also called %k-compass or %k-directional, this kind of filter is useful to enhance edges in given directions. With a 3 x 3 kernel, one normally uses filters for 0, 45, 90 and 135 degrees. The various angles are obtained ‘rotating’ the positive and negative values to ‘align’ with the various directions.

(k-make 3 3
        '(  -2  -2   0
            -2   6   0
             0   0   0  ))
Variable: %k-laplacian

This is a variation of the more traditional Laplacian kernels, that are meant to enhance edges, in this case in an isotropic fashion (non-directional). This the implementation in the Vigra code and it atributes large weights to the diagonal pixels of the kernel. Nevertheless, the total weight is zero.

(k-make 3 3
        '(  0.375   0.25  0.375
            0.25   -2.5   0.25
            0.375   0.25  0.375  ))

Prewitt filtering

Variable: %k-prewitt-y

A 3 x 3 kernel which emphasizes horizontal edges by approximating a vertical gradient.

(k-make 3 3
        '(  1   1   1
            0   0   0
           -1  -1  -1  ))
Variable: %k-prewitt-x

A 3 x 3 kernel which emphasizes vertical edges by approximating an horizontal gradient.

(k-make 3 3
        '(  1  0  -1
            1  0  -1
            1  0  -1  ))

Sobel filtering

Filtering an image using a ‘Sobel filter’ requires a three steps approach: (1) filtering the image using the ‘Sobel y filter’, (2) dito using the ‘Sobel x filter’, and (3) combining the results to obtain ‘Sobel magnitude’: (sqrt (+ (sqrt sobel-y) (sqrt sobel-x)).

Variable: %k-sobel-y
(k-make 3 3
        '(  1   2   1
            0   0   0
           -1  -2  -1  ))
Variable: %k-sobel-x
(k-make 3 3
        '(  1   0  -1
            2   0  -2
            1   0  -1  ))

Footnotes

(9)

The 'scale optional argument passed to im-show, as its name indicate, is so that kernel values will be scaled, which in this case means that 1.0 values will become 255.0 - otherwise, it would be almost impossible for a human eye to actually see the shape of the circle …


Next: Import Export, Previous: Image Structure and Accessors, Up: Image Processing   [Contents][Index]