python - 图像处理:使用 dtype 'int' 和 'float32' 时图像过滤器输出的差异
问题描述
我正在尝试用不同的方法来计算 Python 中图像的窗口标准偏差。
首先,我编写了一个“朴素”的方法,它在元素上使用双循环,并使用 np.std() 返回窗口值的标准偏差。然后,我使用了这里和这里建议的实现
注意:我首先将图像 dtype 转换为,int
因为在第二和第三个算法中对图像值进行平方会溢出uint8
,这是导入的 dtype。
使用第二种和第三种算法计算的结果显示了一些奇怪的扇形效果,这些效果在云区域中尤其明显。使用 dtype int 的标准开发
如果我将输入图像值转换为,则此效果消失float32
:Std dev using dtype float32
我知道计算此处提出的方差的数值稳定性问题。对于第二种算法,我取方差绝对值的平方根来解决这个问题。
为什么在使用输入 dtype 时会出现这种“扇形”,int
而不是float32
,当无论如何int
转换为float
幕后执行浮点计算时?这是我正在使用的测试图像:castle.png
import numpy as np
import matplotlib.pyplot as plt
import cv2
from scipy.ndimage.filters import uniform_filter
from timeit import timeit
img = cv2.imread('castle.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY).astype(int) # CHANGE ME
# Naive double loop method
def stddev_naive(img, kernel_size):
out = np.zeros_like(img)
# Applying reflected boundary conditions for kernel padding
ext = int((kernel_size-1)/2)
x_symm = np.concatenate((img[1:1+ext, :][::-1], img, img[-ext-1:-1, :][::-1])) # Reflected boundary condition applied in x
img_bc = np.concatenate((x_symm.transpose()[1:1+ext, :][::-1], x_symm.transpose(), x_symm.transpose()[-ext-1:-1, :][::-1])).transpose() # Reflected boundary condition applied in y
for i in np.arange(img.shape[0]):
for j in np.arange(img.shape[1]):
out[i,j] = np.std(img_bc[i:i+2*ext+1, j:j+2*ext+1])
return out
# https://stackoverflow.com/a/18422519/16078850
def window_stdev(arr, radius):
c1 = uniform_filter(arr, radius*2, mode='constant', origin=-radius)
c2 = uniform_filter(arr*arr, radius*2, mode='constant', origin=-radius)
return ((c2 - c1*c1)**.5)[:-radius*2+1,:-radius*2+1]
# https://stackoverflow.com/a/36266187
def winVar(img, kernel_size):
wmean, wsqrmean = (cv2.boxFilter(x, -1, (kernel_size, kernel_size), borderType=cv2.BORDER_REFLECT) for x in (img, img**2))
return np.abs(wsqrmean - wmean*wmean)**0.5
out1 = stddev_naive(img, 11)
out2 = window_stdev(img, 5)
out3 = winVar(img, 11)
# Show outputs
fig, (ax1, ax2, ax3) = plt.subplots(1, 3)
ax1.imshow(out1, cmap='gray')
ax1.set_title('Naive method', fontsize=24)
ax2.imshow(out2, cmap='gray')
ax2.set_title('Using scipy.ndimage.uniform_filter', fontsize=24)
ax3.imshow(out3, cmap='gray')
ax3.set_title('Using cv2.boxFilter', fontsize=24)
plt.suptitle('Using dtype \'int\'', fontsize=30)
plt.show()
解决方案
推荐阅读
- http - 为什么,当在 Header Content-Disposition 中指定时:附件;Filename = hello.xls 浏览器不会作为文件加载到磁盘上吗?
- android - 如何连续执行许多 RxJava2 Flux
- c# - 我想在 C# 控制台中制作蛇游戏,移动问题
- javascript - element.getBoundingClientRect() 的替代方案
- swiftui - 嵌套 ObservableObject 中的 @Published var 仅在第二次更改后才更改。SwiftUI 错误?
- python - 尝试使用 python 发送电子邮件。不知道错误信息是什么意思
- django - 保存前更新模型字段名称
- python - cv2.fastNlMeansDenoising() 的奇怪行为
- ruby-on-rails - 如何通过关联检测has_many的变化?
- pandas - 使用多个数据框创建嵌套数据框