如何计算像素周围像素的平均值?
How do I calculate the average value of a pixel's surrounding pixels?
我正在尝试创建一个 5x5 均值滤波器以从图像中去除一些椒盐噪声。我将图像读入一个 numpy 数组。并尝试进行一些更改以计算像素邻居的平均值。我得到的结果很糟糕,我似乎无法弄清楚为什么我的图像结果有差距。
from PIL import Image
import numpy
image1 = 'noisy.jpg'
save1 = 'filtered.jpg'
def average(path, name):
temp=Image.open(path)
image_array = numpy.array(temp)
new_image = []
for i in range(0, len(image_array)):
new_image.append([])
n = 0
average_sum = 0
for i in range(0, len(image_array)):
for j in range(0, len(image_array[i])):
for k in range(-2, 3):
for l in range(-2, 3):
if (len(image_array) > (i + k) >= 0) and (len(image_array[i]) > (j + l) >= 0):
average_sum += image_array[i+k][j+l]
n += 1
new_image[i].append(int(round(average_sum/n)))
average_sum = 0
n = 0
x = Image.fromarray(numpy.array(new_image), 'L')
x.save(name)
print("done")
average(image1, save1)
--------------------输入图像----------------
--------------------输出图像----------------
无需为新图像创建列表,只需复制原始图像(或创建与原始图像大小相同的数组)并使用新的平均像素值更改其值。像这样
def average(path, name):
temp=Image.open(path)
image_array = numpy.array(temp)
new_image = image_array.copy()
n = 0
average_sum = 0
for i in range(0, len(image_array)):
for j in range(0, len(image_array[i])):
for k in range(-2, 3):
for l in range(-2, 3):
if (len(image_array) > (i + k) >= 0) and (len(image_array[i]) > (j + l) >= 0):
average_sum += image_array[i+k][j+l]
n += 1
new_image[i][j] = (int(round(average_sum/n)))
average_sum = 0
n = 0
x = Image.fromarray(numpy.array(new_image), 'L')
x.save(name)
print("done")
这给了我以下输出:
我只是想警告任何发现此页面的人。基本上,没有人应该 somenumpyarray[y,x]
直接一一访问像素值。每次键入类似内容时,Numpy 都必须创建 4 个新的 Python 对象(包含 RGB 值的 tuple
对象,以及每个 R/G/B 值的三个单独的 int
对象).那是因为在Python中,一切都是对象(偶数也是对象),也就是说数据不可能是"just read directly from Numpy"。必须创建实际的 Python objects,并且 Numpy 数据(例如数字)被 copied 到这些对象中,每次 尝试从 Numpy 读取内容到 Python.
这是您尝试从数组中读取的每像素 4 Python 个对象创建。对于 1080p 图像,如果您只读取一次每个像素,即 8 294 400 个对象。但是上面的代码检查了每个像素周围的 5x5(25 像素)矩阵,因此创建了 207 360 000 个对象!疯了!
此对象创建称为装箱(获取本机 Numpy 数据并 packing/boxing 它在 Python 对象数据结构中)。以及拆箱(获取 Python 数据,提取其中包含的实际值(例如数字)并将其打包到本机 Numpy 数组中)。从 Python 读取/写入 Numpy 数组中的值总是涉及装箱和拆箱,这就是为什么它 非常 慢,你应该 总是 改用原生 Numpy 方法对数据进行操作。 Numpy 不是一个通用的 "array" 让我们像对待任何随机访问 Python 列表一样对待。 Numpy 旨在使用其自己的内置函数进行向量/矩阵运算!事实上,你甚至不应该这样做 for X in some_ndarray
因为迭代会调用相同的慢速装箱过程(这种循环中的每个 X
项目都是从 Numpy 中提取并装箱的)。
无论如何...您要实现的是 5x5 "box blur",这意味着 5x5 半径正方形内所有附近像素的平均值。
因此,您应该使用本机 C++ 库,它在纯净、干净的 RAM 中执行所有操作,根本不涉及 Python。一个这样的库是 OpenCV,它接受一个 ndarray(你的图像像素),并在内部直接从 ndarray 拥有的 RAM 中读取,并直接对每个像素进行本地操作。
代码如下:
import cv2
path = "noisy.jpg"
img = cv2.imread(path)
img = cv2.blur(img, (5,5)) # This is now your box-blurred image.
1920x1080 图像中的基准:
- 您的原始代码(滥用 Numpy 数组致死并创建超过 2 亿个新的 Python 对象):87.80000 秒(这还不算)创建超过 2 亿个对象时发生的所有 RAM 滥用)
- 改用 OpenCV:0.02992 秒(快 2935 倍)
永远不要直接访问 Numpy 数组元素。这不是为了那个。
祝未来的读者好运。
编辑:顺便说一下,要回答原来的问题...要去除椒盐噪声,您应该使用 中值 过滤器而不是框模糊.
输入:
5x5 框模糊(又名 Mean/Average 模糊):
img = cv2.blur(img, (5,5))
3x3 中值模糊:
img = cv2.medianBlur(img, 3)
我正在尝试创建一个 5x5 均值滤波器以从图像中去除一些椒盐噪声。我将图像读入一个 numpy 数组。并尝试进行一些更改以计算像素邻居的平均值。我得到的结果很糟糕,我似乎无法弄清楚为什么我的图像结果有差距。
from PIL import Image
import numpy
image1 = 'noisy.jpg'
save1 = 'filtered.jpg'
def average(path, name):
temp=Image.open(path)
image_array = numpy.array(temp)
new_image = []
for i in range(0, len(image_array)):
new_image.append([])
n = 0
average_sum = 0
for i in range(0, len(image_array)):
for j in range(0, len(image_array[i])):
for k in range(-2, 3):
for l in range(-2, 3):
if (len(image_array) > (i + k) >= 0) and (len(image_array[i]) > (j + l) >= 0):
average_sum += image_array[i+k][j+l]
n += 1
new_image[i].append(int(round(average_sum/n)))
average_sum = 0
n = 0
x = Image.fromarray(numpy.array(new_image), 'L')
x.save(name)
print("done")
average(image1, save1)
--------------------输入图像----------------
--------------------输出图像----------------
无需为新图像创建列表,只需复制原始图像(或创建与原始图像大小相同的数组)并使用新的平均像素值更改其值。像这样
def average(path, name):
temp=Image.open(path)
image_array = numpy.array(temp)
new_image = image_array.copy()
n = 0
average_sum = 0
for i in range(0, len(image_array)):
for j in range(0, len(image_array[i])):
for k in range(-2, 3):
for l in range(-2, 3):
if (len(image_array) > (i + k) >= 0) and (len(image_array[i]) > (j + l) >= 0):
average_sum += image_array[i+k][j+l]
n += 1
new_image[i][j] = (int(round(average_sum/n)))
average_sum = 0
n = 0
x = Image.fromarray(numpy.array(new_image), 'L')
x.save(name)
print("done")
这给了我以下输出:
我只是想警告任何发现此页面的人。基本上,没有人应该 somenumpyarray[y,x]
直接一一访问像素值。每次键入类似内容时,Numpy 都必须创建 4 个新的 Python 对象(包含 RGB 值的 tuple
对象,以及每个 R/G/B 值的三个单独的 int
对象).那是因为在Python中,一切都是对象(偶数也是对象),也就是说数据不可能是"just read directly from Numpy"。必须创建实际的 Python objects,并且 Numpy 数据(例如数字)被 copied 到这些对象中,每次 尝试从 Numpy 读取内容到 Python.
这是您尝试从数组中读取的每像素 4 Python 个对象创建。对于 1080p 图像,如果您只读取一次每个像素,即 8 294 400 个对象。但是上面的代码检查了每个像素周围的 5x5(25 像素)矩阵,因此创建了 207 360 000 个对象!疯了!
此对象创建称为装箱(获取本机 Numpy 数据并 packing/boxing 它在 Python 对象数据结构中)。以及拆箱(获取 Python 数据,提取其中包含的实际值(例如数字)并将其打包到本机 Numpy 数组中)。从 Python 读取/写入 Numpy 数组中的值总是涉及装箱和拆箱,这就是为什么它 非常 慢,你应该 总是 改用原生 Numpy 方法对数据进行操作。 Numpy 不是一个通用的 "array" 让我们像对待任何随机访问 Python 列表一样对待。 Numpy 旨在使用其自己的内置函数进行向量/矩阵运算!事实上,你甚至不应该这样做 for X in some_ndarray
因为迭代会调用相同的慢速装箱过程(这种循环中的每个 X
项目都是从 Numpy 中提取并装箱的)。
无论如何...您要实现的是 5x5 "box blur",这意味着 5x5 半径正方形内所有附近像素的平均值。
因此,您应该使用本机 C++ 库,它在纯净、干净的 RAM 中执行所有操作,根本不涉及 Python。一个这样的库是 OpenCV,它接受一个 ndarray(你的图像像素),并在内部直接从 ndarray 拥有的 RAM 中读取,并直接对每个像素进行本地操作。
代码如下:
import cv2
path = "noisy.jpg"
img = cv2.imread(path)
img = cv2.blur(img, (5,5)) # This is now your box-blurred image.
1920x1080 图像中的基准:
- 您的原始代码(滥用 Numpy 数组致死并创建超过 2 亿个新的 Python 对象):87.80000 秒(这还不算)创建超过 2 亿个对象时发生的所有 RAM 滥用)
- 改用 OpenCV:0.02992 秒(快 2935 倍)
永远不要直接访问 Numpy 数组元素。这不是为了那个。
祝未来的读者好运。
编辑:顺便说一下,要回答原来的问题...要去除椒盐噪声,您应该使用 中值 过滤器而不是框模糊.
输入:
5x5 框模糊(又名 Mean/Average 模糊):
img = cv2.blur(img, (5,5))
3x3 中值模糊:
img = cv2.medianBlur(img, 3)