【问题标题】:numpy masked smoothing algorithmnumpy 蒙面平滑算法
【发布时间】:2018-08-01 17:36:29
【问题描述】:

我有一个基本应用内核的平滑算法:

 [0 1 0;
  1 4 1;
  0 1 0]/8

到一个矩阵(图像),然后校正边缘和角落,相当于将内核设置为

 [0 1 0;
  0 5 1;
  0 1 0]/8

对于左边缘,并且

 [0 0 0; 
  0 6 1; 
  0 1 0]/8

用于左上角。

我现在的目标是应用仅适用于该图像的蒙版部分的平滑处理。例如(参考下图),如果我有一个磁盘的方形图像,磁盘的值为 128+-10(+-10 是噪声效果),背景为黑色(值为 0) ,无限次应用的法线平滑算法应该给出具有恒定像素强度的正方形图像。对于蒙版平滑算法,我想对磁盘进行蒙版,以便无限次应用的算法应该在 128 和黑色 (0) 背景处给出一个均匀的磁盘。换句话说,只有磁盘被平滑了。

我要避免的主要事情是背景“渗入”磁盘,使磁盘的边缘变得模糊。我也愿意将平滑算法更改为不同的算法(例如,平均 3x3 像素),以实现更有效的方法。

(嘈杂原创)

(正常平滑后)

(蒙面平滑后)

这是我的正常平滑代码:

def SmoothImage(Matrix,N=1):
    '''Smooths a Matrix with kernel [0 1 0; 1 4 1; 0 1 0]/8'''
    A=Matrix.copy()
    for i in range(N):
        s=A.shape[0]-1
        B=A*4.0
        B[-s:,:]+=A[:s,:]
        B[0,:]+=A[0,:]
        B[:,-s:]+=A[:,:s]
        B[:,0]+=A[:,0]

        B[:s,:]+=A[-s:,:]
        B[-1,:]+=A[-1,:]
        B[:,:s]+=A[:,-s:]
        B[:,-1]+=A[:,-1]
        B*=1/8
        A=B
    return A

【问题讨论】:

    标签: python algorithm numpy


    【解决方案1】:

    这是一种使用线性卷积和一些技巧来保持干净边缘的方法。诡计基本上是通过与逆掩码卷积来计算边缘损失的质量,并将其添加到原始结果中:

    import numpy as np
    from scipy.signal import convolve2d
    
    kernel = np.add.outer(*2*(np.arange(3) % 2,))**2 / 8
    
    def perfect_edges(orig, n_iter=1, thresh=20):
        mask = orig <= thresh
        corrector = convolve2d(mask, kernel, 'same')
        result = orig.copy()
        result[mask] = 0
        for j in range(n_iter):
            result = result * corrector + convolve2d(result, kernel, 'same')
            result[mask] = 0
        result = np.round(result).astype(np.uint8)
        result[mask] = orig[mask]
        return result
    
    picture = (np.add.outer(*2*(np.arange(-6, 7)**2,)) < 30).view(np.uint8) * 118
    picture += np.random.randint(0, 21, picture.shape, dtype=np.uint8)
    
    print(picture)
    print()
    print(perfect_edges(picture, 200))
    

    示例运行:

    [[ 15   0   4  10  17  13  20  12  14   1   5  16  19]
     [  1   6   9  14 132 132 129 128 135   1   5  11   5]
     [ 13  16   6 126 118 118 134 120 130 138   2   6  10]
     [ 16   3 129 129 128 129 125 134 131 132 127  18   8]
     [ 10 120 132 125 128 120 133 137 125 120 124 129   7]
     [ 10 137 119 120 119 118 137 135 135 126 118 128   0]
     [ 17 134 138 133 134 121 124 119 134 138 133 129   2]
     [  3 134 136 132 119 124 123 133 126 121 126 122  19]
     [  3 123 130 123 125 125 128 119 119 129 119 127   6]
     [  5   0 119 118 125 122 135 135 126 133 136   7   3]
     [ 11   1  13 124 121 118 136 137 127 137   2  19  15]
     [  6   7  15  19 132 132 130 125 130   9  18   9  12]
     [ 16  20   0  14   9  10   1   6   5  17  16   0   3]]
    
    [[ 15   0   4  10  17  13  20  12  14   1   5  16  19]
     [  1   6   9  14 128 128 128 128 128   1   5  11   5]
     [ 13  16   6 128 128 128 128 128 128 128   2   6  10]
     [ 16   3 128 128 128 128 128 128 128 128 128  18   8]
     [ 10 128 128 128 128 128 128 128 128 128 128 128   7]
     [ 10 128 128 128 128 128 128 128 128 128 128 128   0]
     [ 17 128 128 128 128 128 128 128 128 128 128 128   2]
     [  3 128 128 128 128 128 128 128 128 128 128 128  19]
     [  3 128 128 128 128 128 128 128 128 128 128 128   6]
     [  5   0 128 128 128 128 128 128 128 128 128   7   3]
     [ 11   1  13 128 128 128 128 128 128 128   2  19  15]
     [  6   7  15  19 128 128 128 128 128   9  18   9  12]
     [ 16  20   0  14   9  10   1   6   5  17  16   0   3]]
    

    【讨论】:

    • 这很好用。我只是在想:在卷积之后,result[mask]=orig[mask] 会不会更加健壮?似乎这样我们可以在面具内部平滑并保持外部相同。
    • @Miguel 目前掩码由orig == 0 定义,因此没有区别。如果“外部区域”不为零,那么您将得到一个点 - 但是该算法在这种情况下将不再起作用,因为外部会渗入内部。也就是说,我们也可以对其进行修改以处理这种情况。让我知道您是否需要该功能,我会再看看。
    • 对于我的目标,零就足够了,但我认为拥有“一般背景”会很棒。
    • @Miguel 我已经修改了函数。不是很深。我只是在开始时将外部设置为零,最后返回其原始值。
    【解决方案2】:

    scipy.ndimage.convolve() 是你想要的。用掩码做卷积,用图像和掩码调用convolve(),然后做除法:

    import numpy as np
    from scipy import ndimage
    
    img = np.random.rand(100, 100)
    
    X, Y = np.mgrid[0:100, 0:100]
    
    mask = (((X - 50)**2 + (Y - 50)**2)**0.5 < 30).astype(np.int8)
    
    img[mask == 0] = 0
    
    kernel = np.array([
        [0, 1, 0],
        [1, 4, 1],
        [0, 1, 0]])
    
    neighbour_count = ndimage.convolve(mask, kernel, mode="constant")
    m = neighbour_count > 0
    
    for i in range(10):
        img = ndimage.convolve(img, kernel, mode="constant")
        img[m] /= neighbour_count[m]
        img[mask == 0] = 0
    
    pl.imshow(img)
    

    输出:

    【讨论】:

    • 我认为您的边缘处理不等同于 OP 所做的。例如,如果一个邻居被屏蔽,他们会使用中心权重 5/8 和三个邻居,每个 1/8,而如果我没记错的话,你的方法会给出 4/7 和 1/7。
    猜你喜欢
    • 2012-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多