How to tell PJSR the convolution kernel size

cpuetz

Well-known member
Hi all,

although my script of calling common convolution matrices is working, I have a question:

If I call i.e.

image.convolve([  0,0,1,0,0,
                            0,0,0,0,0,
                            0,0,2,0,0,
                            0,0,0,2,0,
                            1,0,1,0,0 ]);

the parameter is a one-dimensional array, which is "meant" to be a 5x5 kernel size.
How does the convolve function "know" about this - or do I have to tell it by a property or method ?

 
Hi Christoph,

image.convolve() and other similar functions (all functions that take a 2D kernel in the form of an Array) know the kernel dimensions automatically.

A kernel filter in PCL/PJSR is always:

- A square matrix, so the size is just sqrt(n) where n is the length of the array.

- A square matrix whose size is an odd integer > 1. In other words, there must be a central element.

So you must specify an Array whose length is the square of an odd integer >= 3.
 
Thanks for your answer Juan,

in this context I have 2 similar questions :

1. How about other kernels (i.e. [7x3], although rarely used) ?
2. Are there some functions implemented in order to 'combine' matrices, i.e.
    the Sobel Operators

H = [-1, -2, -1,
      0, 0, 0,
      1, 2, 1]
and V = [ -1, 0, 1,
              -2, 0, 2,
              -1, 0, 1 ]

that must be (if I understand correctly) computed separately and then combined as I = sqrt(H*H+V*V).
I know, that this could be done 'per Pixel' with a script, but another solution might be faster.

Sorry, but I like convolution matrices (if nights are cloudy ;-)).




 
Hi Christoph,

1. How about other kernels (i.e. [7x3], although rarely used) ?

You can't. Kernel-based convolution always works with square kernels of odd size on PCL/PJSR. You can set unused kernel elements to zero. In some contexts --which are rare, as you have pointed out--, this may not be equivalent to a non-square filter. For convolution/correlation purposes, setting a filter element to zero effectively discards it from the computed result.

Note however that you can convolve two images, where one of the images replaces the kernel filter. In this case there are no size constraints.

2. Are there some functions implemented in order to 'combine' matrices, i.e.
    the Sobel Operators

A couple years ago I wrote a small script for computation of image gradients. After a brief search on the Internet, I have updated and improved it with several filters that yield more accurate results than the classical Sobel operator. You have the script below, which I think will answer most of your questions. Hope it will be useful.

Code:
/*
 * Gradient computation via separable convolutions
 *
 * [1] Dirk-Jan Kroon, 2009, Numerical Optimization of Kernel Based Image Derivatives.
 */

#include <pjsr/ImageOp.jsh>

// Classical Sobel operator
var Derivative_Sobel = new Matrix( +1, +2, +1,
                                    0,  0,  0,
                                   -1, -2, -1 );

// Scharr operator (referenced in [1])
var Derivative_Scharr = new Matrix( +3, +10, +3,
                                     0,   0,  0,
                                    -3, -10, -3 );

// Kroon's optimized 3x3 filter [1]
var Derivative_Kroon_3x3 = new Matrix( +17, +61, +17,
                                         0,   0,   0,
                                       -17, -61, -17 );

// Kroon's optimized 5x5 filter [1]
var Derivative_Kroon_5x5 = new Matrix(
   [+0.0007, +0.0052, +0.0370, +0.0052, +0.0007,
    +0.0037, +0.1187, +0.2589, +0.1187, +0.0037,
     0,       0,       0,       0,       0,
    -0.0037, -0.1187, -0.2589, -0.1187, -0.0037,
    -0.0007, -0.0052, -0.0370, -0.0052, -0.0007], 5, 5 );

var Derivative_Filter = Derivative_Kroon_5x5;

function main()
{
   var window = ImageWindow.activeWindow;
   if ( window.isNull )
      throw new Error( "There is no active image." );

   var view = window.currentView;
   var img = view.image;

   // Working images
   var Ix = new Image;
   img.clonePixelData( Ix );
   var Iy = new Image;
   img.clonePixelData( Iy );

   // Derivative in the X direction
   Ix.convolve( Derivative_Filter );
   // Ix = Ix^2
   Ix.apply( Ix, ImageOp_Mul );
                  
   // Derivative in the Y direction
   Iy.convolve( Derivative_Filter.transpose() );
   // Iy = Iy^2
   Iy.apply( Iy, ImageOp_Mul );

   // Ix = Ix^2 + Iy^2
   Ix.apply( Iy, ImageOp_Add );

   // Ix = (Ix^2 + Iy^2)^0.5
   Ix.apply( 0.5, ImageOp_Pow );

   view.beginProcess();
   img.apply( Ix, ImageOp_Mov );
   img.rescale();
   view.endProcess();
}

main();

One of the possible applications of gradients is detection of star edges. For example, apply the above script to a deep sky image and you'll see what I'm talking about. Once we have all star edges well isolated, building a star mask is easy. I use a similar technique in the StarMask tool.

Have fun!
 
1.- You must fill with 0s
(To the date, I think that there is no way to implement a nx1 or 1xn kernel [unidimentional], much more commonly used than a a non square one)

2.-Take a look at the Matrix class in the PCL. At the bottom are some definitions of functions to operate matrices.

PD: If you want that "I" to be the modulus of the gradient, you cannot multiply the kernels, add them and then take the square, to get a "master" kernel that will be convoluted to the image. The convolution is a linear operation, while the square operation is not a linear function. This must be implemented with images directly. Take Gx = H*Im (where * is convolution), Gy = V*Im, and then I = sqrt(Gx.Gx+Gy.Gy). The latter should be done pixel by pixel, or using the Apply() function (see Image.h)
PD2: PJSR works in a similar way to the PCL... now look at Image and Matrix for their methods, etc.
 
Thanks Carlos and Juan !!!

PI is real fun, indeed. You can learn so much about image processing, if you try to write your script for yourself.
8)
 
Back
Top