使用scipy.signal.convolve为何出现远小于1/9的极小正值?
均值卷积后出现极小正值的原因分析
测试代码
import numpy as np from skimage.io import imread from scipy.signal import convolve image = np.flipud(imread('conv-test.bmp').astype(np.float32)) con = convolve(image, np.ones((3, 3))/9, mode='valid') print(image.min()) print(np.logical_and(image > 0, image < 1).any()) print(np.logical_and(con > 0, con < 0.00001).any())
运行输出
0.0 False True
问题描述
原图像最小值为0,且不存在0到1之间的数值,使用3×3均值核(核值为1/9)进行valid模式卷积后,却出现了大于0且小于0.00001的正值。按理论最小正值应为1/9,这一现象如何解释?
原因解析
这种现象完全由浮点数精度限制和卷积运算的实现误差导致,具体如下:
- 浮点数无法精确表示1/9:1/9是无限循环的二进制小数,无法用
float32(或任何二进制浮点数类型)精确存储,实际存储的是近似值。当对全0像素窗口卷积时,理论结果应为0,但九个近似的1/9与0相乘后相加的过程中,浮点数运算的舍入误差会累积出极小的非零正值。 - 卷积实现的误差放大:
scipy.signal.convolve默认会根据输入尺寸自动选择计算方式(直接卷积或FFT加速)。当使用FFT完成卷积时,迭代计算过程中的浮点误差会进一步放大,导致原本应为0的结果出现微小偏移,表现为极小的正值。
验证方法
用全0图像可复现该现象:
import numpy as np from scipy.signal import convolve # 创建全0的float32图像 image = np.zeros((5, 5), dtype=np.float32) # 3×3均值核卷积 con = convolve(image, np.ones((3, 3), dtype=np.float32)/9, mode='valid') # 检查是否存在极小正值 print(np.logical_and(con > 0, con < 0.00001).any()) # 输出为True
内容的提问来源于stack exchange,提问作者Paul Jurczak
相关产品推荐
相关产品推荐

