You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用skimage对包含NaN值的二维数组进行去噪?

如何使用skimage对包含NaN值的二维数组进行去噪?

我太懂你遇到的这个糟心问题了!之前用skimage的TV去噪处理带NaN的数组时也踩过一模一样的坑——纯有效数据时去噪效果好好的,结果一加入NaN值,整个去噪结果直接变成全NaN数组了。这其实是因为denoise_tv_chambolle本身没做缺失值处理逻辑,NaN会在迭代计算里不断传播,最后把所有值都污染了。

给你两个实用的解决思路,亲测有效:

方法一:先填充NaN值,再进行去噪

最直接的办法就是先把数组里的NaN值用合理的数值补上,再用TV去噪。填充的方式可以根据你的数据情况选:

简单邻域均值填充(适合小范围NaN)

如果你的NaN区域不大,可以用邻域内的非NaN均值来替换NaN,代码示例如下:

from skimage.restoration import denoise_tv_chambolle
import numpy as np
from scipy.ndimage import generic_filter

# 生成带NaN的测试数据(和你的代码一致)
data_random = np.random.random([100,100])*100
data_random[20:30, 50:60] = np.nan
data_random[30:40, 55:60] = np.nan
data_random[40:50, 65:75] = np.nan

# 定义邻域均值填充函数:用3x3邻域的非NaN均值替换NaN
def fill_nan_with_neighbor_mean(arr):
    valid_values = arr[~np.isnan(arr)]
    return valid_values.mean() if len(valid_values) > 0 else 0

# 对数组进行填充,mode='nearest'处理边缘情况
data_filled = generic_filter(data_random, fill_nan_with_neighbor_mean, size=3, mode='nearest')

# 现在对填充后的数组做TV去噪
data_denoised = denoise_tv_chambolle(data_filled, weight=0.1)

更精确的图像修复填充(适合大范围NaN)

如果你的NaN区域比较大,推荐用skimage的图像修复工具,比如双调和插值修复,能更自然地补全缺失区域:

from skimage.restoration import inpaint_biharmonic

# 创建NaN的掩码:True表示缺失区域
mask = np.isnan(data_random)

# 先把NaN临时替换成0(修复函数不接受NaN)
data_temp = np.where(mask, 0, data_random)

# 修复缺失区域
data_filled = inpaint_biharmonic(data_temp, mask, channel_axis=None)

# 再进行TV去噪
data_denoised = denoise_tv_chambolle(data_filled, weight=0.1)

方法二:修改TV去噪的计算逻辑(进阶版)

如果你不想填充NaN,也可以自己实现支持NaN的TV去噪逻辑,核心是在计算梯度和迭代时忽略NaN值,但这个需要对TV去噪的算法有一定了解,实现起来比较繁琐,一般情况下先用填充的方法就足够啦。

最后给你看下对应的效果对比:
原始数据:
原始随机数据,无NaN值,纹理均匀

去噪后的数据(无NaN):
去噪后的数据,纹理平滑,细节保留

带NaN值的数据:
带NaN值的数据,存在黑色缺失块

用填充+去噪的方法处理后,就能得到类似无NaN时的去噪效果,不会再出现全NaN的情况了~

备注:内容来源于stack exchange,提问作者zxdawn

火山引擎 最新活动