首页 > 解决方案 > 图像处理:使用 dtype 'int' 和 'float32' 时图像过滤器输出的差异

问题描述

我正在尝试用不同的方法来计算 Python 中图像的窗口标准偏差。

首先,我编写了一个“朴素”的方法,它在元素上使用双循环,并使用 np.std() 返回窗口值的标准偏差。然后,我使用了这里这里建议的实现

注意:我首先将图像 dtype 转换为,int因为在第二和第三个算法中对图像值进行平方会溢出uint8,这是导入的 dtype。

使用第二种和第三种算法计算的结果显示了一些奇怪的扇形效果,这些效果在云区域中尤其明显。使用 dtype int 的标准开发

如果我将输入图像值转换为,则此效果消失float32Std 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()

标签: pythonimagenumpyopencvscipy

解决方案


推荐阅读