如何在Java中实现中值滤波器?

1 投票
2 回答
1658 浏览
提问于 2025-04-18 10:01

我在Python中有一个中值滤波器的代码,现在需要把它转换成Java代码,作为我项目的一部分。问题是,我对这个代码是怎么工作的完全不懂。

def medfilt (x, k):
    """Apply a length-k median filter to a 1D array x.
    Boundaries are extended by repeating endpoints.
    """
    assert k % 2 == 1, "Median filter length must be odd."
    assert x.ndim == 1, "Input must be one-dimensional."
    k2 = (k - 1) // 2
    y = np.zeros ((len (x), k), dtype=x.dtype)
    y[:,k2] = x
    for i in range (k2):
        j = k2 - i
        y[j:,i] = x[:-j]
        y[:j,i] = x[0]
        y[:-j,-(i+1)] = x[j:]
        y[-j:,-(i+1)] = x[-1]fi
    return np.median (y, axis=1)

如果有人能帮忙或者提供一些资源,我会非常感激!谢谢。

补充说明:我现在明白这个算法在做什么了,但不太确定怎么把范围的部分最好地转换成Java代码:

for i in range (k2):
        j = k2 - i
        y[j:,i] = x[:-j]
        y[:j,i] = x[0]
        y[:-j,-(i+1)] = x[j:]
        y[-j:,-(i+1)] = x[-1]fi

2 个回答

0

这个中值滤波器挺有意思的,不过我得承认我想不出它有什么用处。这里的向量化处理从性能上看似乎并没有太大好处,所以其实可以在循环里直接找到中值。

为了看看这个循环在干什么,我们假设k=7。那么k2就是3,循环会执行三次(执行两次就足够展示发生了什么):

i = 0
j = 3
# fill in row 0
# shift the x vector right by three and fill the beginning with the first element
y[3:,0] = x[:-3]
y[:3,0] = x[0] 
# fill in the last row (-1), i.e. row 6
# shift the x vector left by 3 and fill the end by the last element   
y[:-3,-1] = x[3:]
y[-3:,-1] = x[-1]

i = 1
j = 2
# fill in row 1
# shift the x vector right by 2 and fill the beginning with the first element
y[2:,0] = x[:-2]
y[:2,0] = x[0] 
# fill in the second last row (-2), i.e. row 5
# shift the x vector left by 2 and fill the end by the last element   
y[:-2,-1] = x[2:]
y[-2:,-1] = x[-1]

...

我想告诉原代码的作者,for循环并不算贵,Python的重点在于可读性。用两个循环会更容易理解,而且这个算法可以通过其他方式变得更快。)

无论如何,我们想要的数组是:

x0 x0 x0 x0 x1 x2 x3 ...          x(n-4)
x0 x0 x0 x1 x2 x3 ...             x(n-3)
x0 x0 x1 x2 x3 ...                x(n-2)
x0 x1 x2 x3 ...                   x(n-1)
x1 x2 x3 ...               x(n-1) x(n-1)
x2 x3 x4 ...        x(n-1) x(n-1) x(n-1)
x3 x4 x5 ... x(n-1) x(n-1) x(n-1) x(n-1)

而结果向量是这些值的中值。

在我看来,这个算法无论用什么语言都有很大的改进空间。其实,先计算数组再找中值并不是很有用。直接在每个循环中创建一个向量y会更好。

(顺便说一下,这段代码可以用很多种方式写得更清晰,比如:

n = len(x)
k2 = k / 2
y = np.empty(n + 2 * k2)
m = np.empty(k)
for i in range(k):
    y[:i] = x[0]
    y[i, i:n+i] = x
    y[n+i:] = x[-1]
    m[i] = median(y[k2:-k2])
return m

但那是另一个话题。)

在这种情况下,只需计算完整向量x的可用中值就足够了(这会给出x - (k-1)/2个样本)。然后可以单独计算不同的边缘填充,也就是:

median( x0 x0 x1 x2 x3 x4 x5)
median( x0 x0 x0 x1 x2 x3 x4)
median( x0 x0 x0 x0 x1 x2 x3) = x0
median( x0 x0 x0 x0 x0 x1 x2) = x0
median( x0 x0 x0 x0 x0 x0 x1) = x0

median( x(n-6) x(n-5) x(n-2) x(n-3) x(n-2) x(n-1) x(n-1) )
median( x(n-5) x(n-4) x(n-3) x(n-2) x(n-1) x(n-1) x(n-1) )
median( x(n-4) x(n-3) x(n-2) x(n-1) x(n-1) x(n-1) x(n-1) ) = x(n-1)
median( x(n-3) x(n-2) x(n-1) x(n-1) x(n-1) x(n-1) x(n-1) ) = x(n-1)
median( x(n-2) x(n-1) x(n-1) x(n-1) x(n-1) x(n-1) x(n-1) ) = x(n-1)

所以,实际上你可以通过简单地取一个向量的中值来获取这个算法提供的所有信息:

x0 x0 x0 x0 x1 x2 ... x(n-2) x(n-1) x(n-1) x(n-1) x(n-1)

每个端点的填充量是(k-1)/2,对于k点中值滤波器来说。看起来这个算法有点傻,或者我可能漏掉了什么。

1

这段内容看起来是在调用numpy这个库的方法。关于中位数这个方法的具体用法,可以参考这里:http://docs.scipy.org/doc/numpy/reference/generated/numpy.median.html。如果你想更深入地了解如何使用numpy,可以看看这个链接:http://docs.scipy.org/doc/numpy/

我所知道的“中位数滤波器”是用在信号处理中的,用来减少噪声。这个例子似乎是在处理某种科学数据集,不过仅凭这一段代码我不太确定。你可以从维基百科的这篇文章开始了解一下,中位数滤波器的相关信息。而且scipy库里也有这样的一个方法。这看起来只是中位数滤波器的一种特殊实现方式。

撰写回答