我想实现一个径向中值滤波器。我有以下图片(size =(Nx,Ny))
我想导出每个像素的半径。对于每个半径,请计算中间值,并将其放到新矩阵中,以替换所有具有相同半径的像素。我找到了Image Smoothing Using Median Filter,但是速度不够快。而且我创建了自己的脚本,不幸的是,它也不是很快。我在一些常规数据上进行了测试:
import cv2
from PIL import Image
from scipy import stats, ndimage, misc
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.image as mpimg
from scipy import stats
a = np.array([[0.,0.,0.,0.,0.],[0.,5.,1.,9.,0.],[0.,10.,2.,10.,0.],[0.,9.,1.,5.,0.],[0.,0.,0.,0.,0.]])
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 r
for j in set_r:
result = np.where(r.flatten() == j)
median_r[result[0]] = np.median(b[result[0]])
a_med = median_r.reshape(a.shape)
am_med = ndimage.median_filter(a, 3)
plt.figure(figsize=(16, 5))
plt.subplot(141)
plt.imshow(a, interpolation='nearest')
plt.axis('off')
plt.title('Original image', fontsize=20)
plt.subplot(142)
plt.imshow(am_med, interpolation='nearest', vmin=0, vmax=5)
plt.axis('off')
plt.title('Median filter', fontsize=20)
plt.subplot(143)
plt.imshow(a_med, interpolation='nearest')
plt.axis('off')
plt.title('Own median', fontsize=20)
plt.subplots_adjust(wspace=0.02, hspace=0.02, top=0.9, bottom=0, left=0,
right=1)
plt.show()
我想找到一种解决此问题的简便方法
答案 0 :(得分:1)
我想您要用输入图像中相同半径上的像素均值替换图像每个圆周围的所有像素。
我建议将图像扭曲到笛卡尔坐标,计算平均值,然后扭曲回到极坐标。
我生成了一些像这样的大小的测试数据:
#!/usr/bin/env python3
import 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 arcs
for s in range(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)
这给出了这一点:
Image.fromarray(a.astype(np.uint8)).save('start.png')
def orig(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 r
for j in set_r:
result = np.where(r.flatten() == j)
median_r[result[0]] = np.median(b[result[0]])
return median_r
def me(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')
结果与您的结果相同,即,它会删除所有小于180度的弧并填充所有超过180度的弧:
但是我的时机快了十倍:
In [58]: %timeit a_med = orig(a).reshape(a.shape)
287 ms ± 17.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [59]: %timeit r = me(a)
29.9 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
如果您很难想象warpPolar()
之后我会得到什么,它看起来像这样。然后,我使用np.mean()
来计算均值,即axis=0
:
关键字:Python,径向平均值,径向中值,笛卡尔坐标,极坐标,矩形,warpPolar,linearPolar,OpenCV,图像,图像处理
答案 1 :(得分:0)
这里的大多数答案似乎都集中在朴素的中值滤波算法的性能优化上。值得注意的是,您会在成像包(如OpenCV / scikit-image / MATLAB / etc)中找到中值滤波器。实现更快的算法。
如果您正在对uint8数据进行中值滤波,那么当您从一个邻域移动到另一个邻域时,有很多巧妙的技巧可以重用直方图。
如果要关心速度,我会在成像包中使用中值滤波器,而不是尝试自己滚动。