ImageMagick: custom rank filter? Like erode or dilate or median but a different rank, e.g. a 'percentile' filter?

假如想象 提交于 2021-01-28 05:40:38

问题


When applying a rank filter with ImageMagick such as erode or delate or median, it takes the minimum (erode) or maximum (dilate) or middle (median) value of all pixels within a certain radius or custom shape around each source pixel.

Is it also possible to take a custom rank of the surrounding pixel values? For example when using a 5x5 square, with the erode or dilate or median filters, respectively the lowest, highest, of middle value of the 25 pixels surrounding each pixel is taken. What I'm looking for is a way to take the 8th or 23rd value, for example.

Perhaps this could be expressed as a percentile, e.g. take the 20% percentile value of an arbitrary area surrounding each pixel. Which in case of a 7x7 square would be the 0.2*7*7 = the 9th value out of the total 49 in order.

The erode, dilate and median filters would correspond to the 0%, 100%, and 50% percentiles, respectively.


回答1:


I can't think of a way to do that easily in ImageMagick - other than compiling in your own "process module". The best introduction to that is by snibgo and actually for Windows - see the sortpixels.c example here


One tool that can do this simply from the command-line is libvips with its im_rank() function.

So, if you want index 8 from a sorted list of 5x5 neighbours, you could do:

vips im_rank input.png result.png 5 5 8

I did a quick test by generating a random image with ImageMagick and choosing successively greater values for index and the output images got successively brighter - but that was the sum-total of my testing. I have no reason to believe it will not work - it is an excellent library and very fast and frugal.


If you can live with Python, you can do this:

#!/usr/bin/env python3

import numpy as np
from PIL import Image
from scipy.ndimage import generic_filter
from scipy import stats

# Modal filter
def modal(P):
    """
    We receive P[0]..P[8] with the pixels in the 3x3 surrounding window
    Sort neighbours and take N'th in list
    """
    N = 3
    P.sort()
    return P[N]

# Open image and make into Numpy array
im = Image.open('image.png').convert('L')
im = np.array(im)

# Run modal filter, change filter size here
result = generic_filter(im, modal, (3, 3))

# Save result
Image.fromarray(result).save('result.png')

You can change the filter size/shape to, say 5x5 by changing this line:

result = generic_filter(im, modal, (5, 5))

And as it is, it will take the third smallest neighbour, as counting starts from 0. So, use N=0 if you want the minimum in the 3x3 neighbourhood, or N=8 if you want the maximum in a 3x3 neighbourhood.


Another option might be to use CImg which is a simple-to-use, header-only C++ library (no DLLs/libXXX.a/libXXX.so files) that can actually read and write PGM files natively without needing anything external. So you could run an ImageMagick command and cause it to write a PGM file on stdout and read that in using CImg, process it and write it out filtered again. That would probably be easier than writing an ImageMagick "process module" and you wouldn't need to build ImageMagick from source anew for every release.

Keywords: ImageMagick, vips, libvips, filter, rank, ranking, median, dilate, erode, window, 3x3, 5x5, NxN, percentile, Python, PIL, Pillow, image, image processing.



来源:https://stackoverflow.com/questions/55557873/imagemagick-custom-rank-filter-like-erode-or-dilate-or-median-but-a-different

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!