【问题标题】:Median filter for image Python3图像Python3的中值滤波器
【发布时间】:2019-10-06 13:50:28
【问题描述】:

我想实现一个径向中值滤波器。我有以下图片(大小=(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()

我想找到一个方便的方法来解决这个问题

【问题讨论】:

  • 请分享预期的输出图像。
  • @MarkSetchell,我已经在一些生成数据上测试了脚本(我更改了我的帖子)
  • @MarkSetchell,我想改变径向平均值 (scipy-lectures.org/advanced/image_processing/auto_examples/…) 以计算径向中位数
  • 有点不清楚问题是什么,您想实现您的代码以生成与ndimage.median_filter(a, 3) 相同的数字吗?或者您是否正在尝试实现更快的代码版本?
  • @RK1, ndimage.median_filter(a, 3) 用大小 = 3 的窗口中的中值替换。我想做径向中值滤波器

标签: python image numpy image-processing


【解决方案1】:

这里的大多数答案似乎都集中在朴素中值过滤算法的性能优化上。值得注意的是,您可以在 OpenCV/scikit-image/MATLAB/等成像包中找到中值滤波器。实现更快的算法。

http://nomis80.org/ctmf.pdf

如果您要对 uint8 数据进行中值过滤,那么当您从一个邻域移动到另一个邻域时,重用直方图可以玩很多巧妙的技巧。

如果您关心速度,我会在成像包中使用中值滤波器,而不是尝试自己滚动一个。

【讨论】:

    【解决方案2】:

    我认为您想用输入图像中同一半径上像素的平均值替换图像每个圆的半径周围的所有像素。

    我建议将图像变形为笛卡尔坐标,计算平均值,然后变形回极坐标。

    我生成了一些大小合适的测试数据,如下所示:

    #!/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 度的圆弧:

    但我的时间要快 10 倍:

    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、图像、图像处理

    【讨论】:

    • 但如果图像形状为 (1105,1056) 则不起作用。问题出现在polmed = np.broadcast_to(polmed,a.shape) ,因为在上一步polmed = np.median(pol,axis=0,keepdims=True) 中,polmed 的形状等于(1,1105)。错误声明 ValueError: operands could not be broadcast together with remapped shapes [original->remapped]: (1,1105) and requested shape (1105,1056)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-01
    • 2011-10-02
    • 2016-02-13
    • 2023-03-24
    • 2016-12-09
    相关资源
    最近更新 更多