Morphological filter custom kernels

I am interested in expanding the capability of the ‘Morphological filter’ filter.
In particular, I think the ‘directional restriction’ options found in Value Propagate GIMP filter, would be very useful for things like altering text weight.

I think the correct way to do this is to provide four similar checkboxes, and if they aren’t all checked, generate a kernel of the appropriate base type and radius. Then, if a given checkbox is unchecked, unset all elements to that side of the centre.
For example, here is a square kernel of radius 3 with all directions checked:

1 1 1
1 1 1
1 1 1

Here is a square kernel with Left unchecked:

0 1 1
0 1 1
0 1 1

Is this something that might be incorporated in GMIC if I made these changes?

Here is a little demo illustrating the value of this. All images are expanded 4x for clear visibility of differences.

Starting image:

GMIC Erosion (square, radius 3)

Value propagate with all checkboxes checked produces identical results, so it is not shown here. Note that Value Propagate has no radius control, it is fixed to a square, radius 3 base kernel.

Value propagate with Left and Right checkboxes checked ‘widens’ the text:

With only Right checkbox checked, a milder thickening is achieved:

The vertical equivalents, Up + Down, and just Up:

GMIC square, radius 3 dilation:

Value Propagate Left-Right only dilation:

VP Left only dilation :

VP Up-Down only dilation:

VP Down only dilation:

And here’s the original again, so you don’t have to do too much scrolling to compare:

1 Like

Interesting idea.
Why not going one step further and propose an explicit way to enter a custom kernel ?
so kernels as

[ 1 0 1 ]
[ 0 1 0 ]
[ 1 0 1 ]

could be provided as well, for instance like this :

Custom Kernel : 1,0,1;0,1,0;1,0,1

The method of parametrization you describe seems reasonable as an additional option, mainly for smaller ( <= 7x7) kernels.
The correct way to convert that parameter to an image on the stack is like this:

($5)

, assuming that the Custom Kernel was the 5th parameter, correct?

I wouldn’t want to use custom kernel most of the time myself, as one of my main motivations here is to take Value Propagate’s feature of easily controlling direction, and combine it with GMIC’s feature of easily controlling radius. But it’s an excellent place to start.

EDIT:
I’ve started coding this. My relatively basic GMIC understanding is suggesting that I need to make sure each -erode/-dilate command is called on all but the last image in the stack, specifying the last image in the stack as the mask. (For example: “-erode[0–2] [-1]”) .

I figured out how to do this in a simple, non-redundant way:
Create a new variable ‘param’ variable which holds either a radius (non-custom kernel) or image selection “[-1]” (custom kernel), and add “[0–2]” to the end of “suf” variable when a custom kernel is in use. Replace every instance of “$2” with “$param”.

However, this does seem a bit arcane. I think there might be a better way using ‘-local’… ‘-endlocal’ but am not sure (since the kernel needs to be read from by -erode / -dilate, but not modified). Any insight you have about this would be appreciated.

EDIT2: I see that you have added a ‘custom’ option to the Morphological filter, with a nice preview. This is excellent for experimenting – diagonal kernels give an interesting stylistic effect. However, could you please state clearly whether you agree with having direction-limiting options in it or not?

I’m not sure I understand exactly what you want to do.
If you add rows or columns with 0 on the structuring element (kernel), then you will simply shift your result horizontally/vertically compared to the kernel without the 0’s.
It seems to me the examples you show here are more related to the fact you can choose different horizontal/vertical sizes for the kernel. It is not easy to do for generic kernels other than rectangles, but at least I’ve updated the filter to do so.

I don’t, as I understand it, want to add rows. I want to set areas that are already inside the kernel to 0.

I don’t see that size could achieve it in all cases. For standard convolution kernels, I would expect to be able to take

0 1 0
1 1 1
0 1 0

and if I didn’t want to include the left pixel, I would be able to clear the left column

0 1 0
0 1 1
0 1 0

And so on, for the right column, upper row, and lower row. eg.

0 1 0
0 1 1
0 0 0

to include the ‘up’ and ‘right’ pixels’ but not the ‘left’ or ‘down’ pixels.

Tests with the current ‘morphological filter’ seem to support this (albeit slightly surprisingly)
If i enter the kernel ‘0,0,0;1,1,0;0,0,0’, then areas expand only to the right. Conversely, if I enter the kernel ‘0,0,0;0,1,1;0,0,0’ then they expand only to the left. (this is strange because I would have thought adding a 1 on the right of an oddly-sized kernel would cause pixels to travel right, etc.)

So for example, expanding by 1 pixel, up, and to the right (but not down or to the left)… since directions seem to be reversed, I would expect ‘0,0,0;1,1,0;0,1,0’ to achieve the desired result.

Hopefully that illustrates my basic case. I’ll edit with further examples and larger kernel sizes. The evidence I have seen so far suggests that it is a completely generic process, that can be applied to (at least) any odd-dimensioned kernel (3x3, 3x5, 5x3, 5x5,7x7, etc…).

Also, I feel obligated to ask whether this reversal of directions is a bug. It occurs for all kernels, but of course, is only obvious for kernels that are not completely symmetric.

EDIT:
I will attempt to reiterate my idea, updated with the knowledge that GMIC (currently) effectively reverses direction in kernels.

Starting with a generic 5x5 kernel:

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

This kernel should expand areas in all directions by 1-2 pixels.

Now imagine four checkboxes:

[ ] Exclude Left
[ ] Exclude Right
[ ] Exclude Top
[ ] Exclude Bottom

The behaviour of these is as follows.

Exclude Left clears all elements to the right (remember, GMIC is reversing the directions) of the centre point.
If this is the only checkbox checked, the resulting kernel will look like:

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

And should, applied alone, have the effect of expanding areas only to the rightby 1-2 pixels.

Exclude Right is the reverse of Exclude Left. It clears elements left of the centre line, and results in a kernel like this:

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

And should, applied alone, have the effect of expanding areas only to the leftby 1-2 pixels.

You may infer from this the meaning of Exclude Top and Exclude Bottom.

Checking all the Exclude checkboxes should, of course, result in a ‘no-operation’ kernel, with a single 1 in the centre.
Checking combinations of checkboxes can result in kernels like:

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

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


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

(results of other combinations not shown, as they are effectively flips or rotations of these kernels)

(apologies for any confusion caused by reversal of directions, but as I said, this appears to be necessary with current GMIC to achieve the expected result. )

EDIT2:
So in summary, the idea is that, whether you are using Square, Circle, Octagon, or Custom kernel, that you can easily clear any combination of the Left, Right, Top, or Bottom sides of the kernel. Resulting in ‘directionally restricted’ erosions/dilations/etc.
I am not sure I understand the current code fully, but I think this would require the code to be changed from simply calling -erode / -erode_circ / -erode_oct etc in case of Square, Circle, or Octagon shape, to actually generating a mask of the appropriate shape, so that parts of it can be cleared if needed before passing to -erode / -dilate.

OK, some thoughts about this :

  • Yes, there was a bug in G’MIC 1.7.3- with the dilation/erosion algorithm for non-symmetric kernels. It has been fixed yesterday, and I’ve released a new pre-version 1.7.4-pre available from the G’MIC web page to fix this (see Release of G'MIC 1.7.4 for the current Changelog :slight_smile: ).
  • I understand what you want to do now, but that seems very specific. I think we should think about a solution that allows more generic manipulation of the kernel. I propose to let the user define its own kernel, for instance as an additional layer. So he could remove any kind of columns or values he wants without multiplying the filter controls.
  • Also, note that currently if you use the square, rectangle or octogonal kernel, you actually don’t just erode/dilate with a pre-defined 2d kernel, because these particular cases can be optimized. Square/rectangles kernels use a specific optimized algorithm in the library for such kernels. Octogonal kernels use an iterative approach (several fast iterations with a 3x3 kernel instead of a single slow iteration with a NxN kernel). So in these two cases your options wouldn’t be easily applicable.

I think letting the user define its own structuring element as an addition layer is even more powerful, and keep the number of controls in a reasonable amount.