![](/img/trans.png)
[英]Replace all elements of Numpy array greater than threshold with average of X adjacent values
[英]Python - How to replace None values in a numpy array with the median of adjacent elements
我已经基于numba
写了这样的东西(即使它是用于掩码数组,但我很快将它改编为 NaN )。
正如 Ami Tavory 所说,您也可以使用一些 numpy 技巧来做到这一点,但我发现如果您自己编写循环然后对其进行优化,它会更清晰(如果没有内置)。 我选择 numba 是因为尽管它在某些方面受到限制,但它非常适合加速此类for
循环。
import numba as nb
import numpy as np
@nb.njit
def median_filter_2d(array, filtersize):
x = array.shape[0]
y = array.shape[1]
filter_half = filtersize // 2
# Create an empty result
res = np.zeros_like(array)
# Loop through each pixel
for i in range(x):
for j in range(y):
# If it's not NaN just let it stay
if not np.isnan(array[i, j]):
res[i, j] = array[i, j]
else:
# We don't want to go outside the image:
start_x = max(0, i - filter_half)
end_x = min(x, i + filter_half+1)
start_y = max(0, j - filter_half)
end_y = min(x, j + filter_half+1)
# If you want to use nanmedian uncomment this line and comment everything else following
#res[i, j] = np.nanmedian(array[start_x:end_x, start_y:end_y])
# Create a temporary array.
tmp = np.zeros(filtersize*filtersize)
counter = 0 # Counter because we want to know how many not-NaNs are present.
# Get all adjacent pixel that are not NaN and insert them
for ii in range(start_x, end_x):
for jj in range(start_y, end_y):
if not np.isnan(array[ii, jj]):
tmp[counter] = array[ii, jj]
counter += 1
# Either do it with np.median but it will be slower
#res[i, j] = np.median(tmp[0:counter])
# or use some custom median-function
res[i, j] = numba_median_insertionsortbased(tmp[0:counter])
return res
辅助中值函数只是一个基于插入排序的排序,然后返回中间元素或两个中间元素的平均值。
@nb.njit
def numba_median_insertionsortbased(items):
# Insertion sort
for i in range(1, len(items)):
j = i
while j > 0 and items[j] < items[j-1]:
items[j], items[j-1] = items[j-1], items[j]
j -= 1
# Median is the middle element (odd length) or the mean of the two middle elements (even length)
if items.size % 2 == 0:
return 0.5 * (items[(items.size // 2)-1] + items[(items.size // 2)])
else:
return items[(items.size // 2)]
如果您不想使用numba
或不能使用,您可以删除@nb.njit
行并在纯 python 中使用它。 它会慢很多,但它仍然可以工作。
对于 80x80 A
我使用 numba 进行计时:
1000 个循环,最好的 3 个:每个循环 1.63 毫秒(自定义中位数)
100 个循环,最好的 3 个:每个循环 4.88 毫秒(numpy 中值)
但是对于大型过滤器,numpy 中值会快一点,因为它们(希望)比插入排序具有更先进的方法。 但是对于您的数组,元素将在临时数组中排序,因此基于插入排序的中位数显然最适合。 对于真实图像,它可能会比 numpy 中值慢。
和纯蟒蛇:
1 个循环,3 个最佳:每个循环 406 毫秒(自定义中位数)
1 个循环,最好的 3 个:每个循环 707 毫秒(没有内部循环和临时数组的 numpy nanmedian)
1 个循环,最好的 3 个:每个循环 832 毫秒(临时数组的 numpy 中位数)
顺便说一句:我总是觉得令人惊讶的是,即使没有 numba 的自定义中位数也比小 1D 输入的 numpy 中位数更快(好吧,它们已经排序,因此它是插入排序的最佳情况 :-) ):
%timeit numba_median_insertionsortbased(np.arange(9)) # without the @nb.njit
10000 loops, best of 3: 21.7 µs per loop
%timeit np.median(np.arange(9))
10000 loops, best of 3: 123 µs per loop
并且这些更快的解决方案可以通过 numba 加速:
%timeit numba_median_insertionsortbased(np.arange(9)) # WITH the @nb.njit
100000 loops, best of 3: 8.93 µs per loop
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.