I've stumbled across this, with my specific situation being anomalous singleton pixels in my constructed classification layer. Based on pointers in the (older) answers and comments here, plus How to apply a Majority filter in GRASS GIS?, here's what worked for me with a combo of GRASS and Raster calculator in QGIS.
Starting point is my (noisy) classification layer (a small subset). The 2nd image highlights the anomalous singletons in black.
A simple run of the QGIS/GDAL
sieve algorithm, with 8-connectedness and threshold of 2, seems promising, but does some strange remappings, e.g. the pixel circled in red. The problem is the GDAL sieve maps removed pixels to the biggest neighbouring polygon, which may not be the most frequent neighbour. Here it's one pixel, but in a land cover/vegetation classification this happens too often.
A majority filter gives a better remapping of the singletons, but unfortunately also remaps pixels that were on actual polygon boundaries, 2 examples again circled in red:
The solution is then to combine the original raster plus the majority-filtered one on the singletons only. Here is the output:
The steps to do this are as follows, the original raster called
aci_class_interspersion using grass
r.neighbors method=interspersion, size=3. This will have value 101 for pixels which are singletons (and down to 1 for pixels all of whose neighbours are the same).
aci_class_neighborsmode using grass
r.neighbors method=mode, size=3. This majority filter smooths out the raster by replacing each cell with the mode of the cells around it.
Finally, combine to get the desired output by creating a raster in the Raster Calculator with expression
If using grass natively rather than from withing QGIS, one could use the the
r.neighbors method=interspersion output as a location mask in the
method=mode invocation directly, but from QGIS it would require mucking around with conditionals and no-data values and the above was faster than figuring it out.)
Editing to add: With some further tinkering, the simple majority filter using grass
r.neighbors can be overly aggressive, especially for singletons that end up having multiple neighbouring polygons with 2-3 adjacent pixels. For that step, using the SAGA
Raster filter / Majority filter with a threshold of ~50% (4+ neighbours to change a pixel) is a more conservative option. Still good to incorporate its changes only on singletons as above.