grass
grass copied to clipboard
[Bug] r.mfilter do not process map edges
Describe the bug
I am performing neighborhood analyses with the r.mfilter module.
It is very good because of its versatility - one can define the filtering matrix as one wants.
However, it does not process the edges of the map, or at least it seems so.
For instance, if the filter matrix size is e.g. 25x25 pixels, the output shows the outer ~12 or 13 pixels of the edge with values = 0 (at least in the example I show below).
To Reproduce
-
Go to North Carolina dataset, within the PERMANENT mapset.
-
I'll work with the
roadsmajormap as input. I'll transform it into a binary map (only value 0 and 1) usingr.mapcalcand perform a neighborhood analysis with it usingr.mfilter, and a matrix I defined for the filter. This is a 125x125 matrix (with resolution = 30m, it corresponds to 3450 m of window size) with exponential decay from the central pixel, and may be found here: test_matrix.txt -
The sequence of commands might be found here (supposing the
test_matrix.txtfile is placed in the home directory):
# within nc_spm_08_grass7 dataset, mapset PERMANENT
# region
g.region raster=roadsmajor@PERMANENT -p
# binary input
r.mapcalc "roads_bin = if(isnull(roadsmajor), 0, 1)"
# m.filter
r.mfilter input=roads_bin output=roads_density_exponential_decay filter=test_matrix.txt
- The error might be seen in the output map below. The border shows approx. 1700 m (~ 57 pixels or half the size of the filtering matrix) of values = zero.

Expected behavior
It is not clear how r.mfilter deals with the null values outside the range of the input map (or outside the computational region) when the window/filter includes pixels in these areas. At the minimum, it would be good to have it documented how they are dealt with.
Ideally, it should also be possible to choose (maybe using flags) whether to propagate null values (i.e. this outer region will become NULL) or to ignore NULL values (i.e. the filter will be performed with all non-NULL values), or to use in the filter all values within the computation region only - whether null or not - but ignore the values outside the region.
In a nutshel, the suggestions are:
- Document how NULL values are used in
r.mfilter - Allow the user to decide what to do with the null values (e.g. propagate, ignore, ignore only outside the computation region)
Just as a matter of comparison, I am not sure how it works internally, but other modules for neighborhood analyses such as r.neighbors have a way to deal with that in the borders and they fill those values according to the neighborhood operation. As it is presented in the documentation for this module, "r.neighbors doesn't propagate NULLs, but computes the aggregate over the non-NULL cells in the neighborhood."
System description (please complete the following information):
- Operating System: Windows 10 Enterprise Version 10.0.19044
- GRASS GIS version:
version=7.8.6RC2
date=2021
revision=exported
build_date=2021-08-12
build_platform=x86_64-w64-mingw32
build_off_t_size=8
libgis_revision=2021-08-12T15:48:18+00:00
libgis_date=2021-08-12T15:48:18+00:00
proj=8.1.0
gdal=3.3.1
geos=3.9.1
sqlite=3.35.2
- Document how NULL values are used in
r.mfilter
PRs are always welcome!
- Allow the user to decide what to do with the null values (e.g. propagate, ignore, ignore only outside the computation region)
I think part of the problem is when you specify divisor, then it's not clear what the behavior should be on the edge because you would have different number of non-null cells, so to mimic r.neigbors behavior, you would have to modify the divisor.
PRs are always welcome!
I will be happy to do so when I understand how this works!
I think part of the problem is when you specify divisor, then it's not clear what the behavior should be on the edge because you would have different number of non-null cells, so to mimic r.neigbors behavior, you would have to modify the divisor.
Good hint, @petrasovaa! I'll test some options and come back here with conclusions or maybe more questions.
Hi, sorry about the long time to look into that.
I think part of the problem is when you specify divisor, then it's not clear what the behavior should be on the edge because you would have different number of non-null cells, so to mimic r.neigbors behavior, you would have to modify the divisor.
I checked now and what really happens is that the edges of the output map are exactly equal to the input map, regardless of the divisor (I tried 0, 1, 125, 13225, changed directly in the filter text file above). In some cases (such as the plot above), we cannot see the lines from the input map bacause of the color scale (roads in the input map have value 1, but the output map ranges from 0 to 103), but in all cases this edge is equal to the input.
I.e., there seem to be edge effects in the computation of neighborhood analysis using r.mfilter in all cases. Is there something - like another option - that I am missing and that could avoid that?
I can confirm the behavior and I consider it a bug. "Copy values from original" might be applicable to some use cases, but not all. Generating nulls is likely a better default. Wrap around is usually the other option, but I'm not sure how useful here.
However, given that there is no PR, this needs to wait for the next release. Changing milestone to 8.4.