为什么 ImageFilter.BoxBlur 会给出错误的结果?

Why does ImageFilter.BoxBlur give wrong results?

我正在尝试将 Pillow 与我生成的一些黑白测试数据一起使用,逐个像素。我想用这些数据来测试我的 one pixel box blur。我已经将灰度像素存储在这样的 3x3 行矩阵中:

 5  10   5
10  15  10
 5  10   5

使用一个像素的框模糊,我希望结果如下:

10   9  10
 9   8   9
10   9  10

但是,我调用 image.tobytes() 后的结果是一个包含九个新行的数组 (\n)。谁能指出我做错了什么?

我理解你的预期输出,但让我们先检查一下现实:

import numpy as np
from PIL import Image, ImageFilter

array = np.array([[5, 10, 5], [10, 15, 10], [5, 10, 5]]).astype(np.uint8)
img = Image.fromarray(array).filter(ImageFilter.BoxBlur(1))
print(np.array(img), '\n\n', img.tobytes())
# [[9 9 9]
#  [9 9 9]
#  [9 9 9]] 
# 
#  b'\t\t\t\t\t\t\t\t\t'

结果是一个包含所有 9 的数组 – 当将 9 转换为字节时,您会得到水平制表符的 ASCII character\t。老实说,我不明白,为什么你得到 \n 或换行符,这将 10 转换为字节,在这里!?

但是,为什么会有这样的结果呢?来自文档(我强调):

Blurs the image by setting each pixel to the average value of the pixels in a square box extending radius pixels in each direction.

因此,您的矩阵实际上看起来像这样用于计算九个(内部)像素:

 5   5  10   5   5
 5   5  10   5   5
10  10  15  10  10
 5   5  10   5   5
 5   5  10   5   5

对于九个内部像素中的每一个,我们得到:

(4 * 5 + 4 * 10 + 15) / 9 = 75 / 9 = 8.333 

看来,我们这里也有上限,而不是常见的四舍五入。

这可能是由于:

Uses an optimized implementation which runs in linear time relative to the size of the image for any radius value.

所以,可能是一些位移魔法而不是实际除法或类似的东西。

您还可以检查边框像素是否被复制,而不是镜像:

import numpy as np
from PIL import Image, ImageFilter

array = np.array([[5, 10, 5], [10, 15, 10], [5, 10, 5]]).astype(np.uint8)
img = Image.fromarray(array).filter(ImageFilter.BoxBlur(2))
print(np.array(img), '\n\n', img.tobytes())
# [[7 7 7]
#  [7 7 7]
#  [7 7 7]] 

像上面为 5x5 矩阵所做的那样设置两个可能的 7x7 矩阵,并比较结果。

底线:BoxBlur 没有按您预期的方式工作。而且,它仍然令人困惑,为什么你得到 \n,而不是 \t

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.16299-SP0
Python:        3.9.1
PyCharm:       2021.1.1
NumPy:         1.20.2
Pillow:        8.2.0
----------------------------------------