Median Filter For Image Python3
Solution 1:
Most of the answers here seem to center on performance optimizations of the naive median filtering algorithm. It's worth noting that the median filters you would find in imaging packages like OpenCV/scikit-image/MATLAB/etc. implement faster algorithms.
If you are median filtering uint8 data, there are a lot of clever tricks to be played with reusing histograms as you move from neighborhood to neighborhood.
I would use the median filter in an imaging package rather than trying to roll one yourself if you care about speed.
Solution 2:
I think you want to replace all pixels around the radius of each circle of the image with the mean of the pixels on that same radius in the input image.
I propose to warp the image to cartesian coordinates, calculate the mean and then warp back to polar coordinates.
I generated some test data of a decent size like this:
#!/usr/bin/env python3import cv2
from PIL import Image
from scipy import stats, ndimage, misc
import matplotlib.image as mpimg
from scipy import stats
import numpy as np
w, h = 600, 600
a = np.zeros((h,w),np.uint8)
# Generate some arcsfor s inrange(1,6):
radius = int(s*w/14)
centre = (int(w/2), int(w/2))
axes = (radius, radius)
angle = 360
startAngle = 0
endAngle = 72*s
cv2.ellipse(a, centre, axes, angle, startAngle, endAngle, 255, 2)
That gives this:
Image.fromarray(a.astype(np.uint8)).save('start.png')
deforig(a):
b = a.copy().flatten()
y,x = np.indices((a.shape))
center = [len(x)//2, len(y)//2]
r = np.hypot(x-center[0],y-center[1])
r = r.astype(np.int) # integer part of radii (bin size = 1)
set_r = set(r.flatten()) # get the list of r without duplication
max_r = max(set_r) # determine the maximum r
median_r = np.array([0.]*len(r.flatten())) # array of median I for each rfor j in set_r:
result = np.where(r.flatten() == j)
median_r[result[0]] = np.median(b[result[0]])
return median_r
defme(a):
h, w = a.shape
centre = (int(h/2), int(w/2))
maxRad = np.sqrt(((h/2.0)**2.0)+((w/2.0)**2.0))
pol = cv2.warpPolar(a.astype(np.float), a.shape, centre, maxRad, flags=cv2.WARP_POLAR_LINEAR+cv2.WARP_FILL_OUTLIERS)
polmed = np.median(pol,axis=0,keepdims=True)
polmed = np.broadcast_to(polmed,a.shape)
res = cv2.warpPolar(polmed, a.shape, centre, maxRad, cv2.WARP_INVERSE_MAP)
return res.astype(np.uint8)
a_med = orig(a).reshape(a.shape)
Image.fromarray(a_med.astype(np.uint8)).save('result.png')
r = me(a)
Image.fromarray(r).save('result-me.png')
The result is the same as yours, i.e. it removes all arcs less than 180 degrees and fills all arcs over 180 degrees:
But the timing for mine is 10x faster:
In [58]: %timeit a_med = orig(a).reshape(a.shape)
287 ms ± 17.3 ms per loop (mean ± std. dev. of7 runs, 1loopeach)
In [59]: %timeit r = me(a)
29.9 ms ± 107 µs per loop (mean ± std. dev. of7 runs, 10 loops each)
In case you are having difficulty imagining what I get after warpPolar()
, it looks like this. Then I use np.mean()
to take the mean down the columns, i.e. axis=0
:
Keywords: Python, radial mean, radial median, cartesian coordinates, polar coordinates, rectangular, warpPolar, linearPolar, OpenCV, image, image processing
Post a Comment for "Median Filter For Image Python3"