我正在努力研究一种高效的numpy解决方案,以便在第四维度上执行一系列彩色图像的运行平均值。目录中的一组彩色图像在循环中读取,我想在3的子集中进行平均。如果目录中有n = 5个彩色图像,我想平均[1,2,3],[2,3,4],[3,4,5],[4,5,1]和[ 5,1,2]因此写出5个输出平均图像。
from os import listdir
from os.path import isfile, join
import numpy as np
import cv2
from matplotlib import pyplot as plt
mypath = 'C:/path/to/5_image/dir'
onlyfiles = [f for f in listdir(mypath) if isfile(join(mypath, f))]
img = np.empty(len(onlyfiles), dtype=object)
temp = np.zeros((960, 1280, 3, 3), dtype='uint8')
temp_avg = np.zeros((960, 1280, 3), dtype='uint8')
for n in range(0, len(onlyfiles)):
img[n] = cv2.imread(join(mypath, onlyfiles[n]))
for n in range(0, len(img)):
if (n+2) < len(img)-1:
temp[:, :, :, 0] = img[n]
temp[:, :, :, 1] = img[n + 1]
temp[:, :, :, 2] = img[n + 2]
temp_avg = np.mean(temp,axis=3)
plt.imshow(temp_avg)
plt.show()
else:
break
这个脚本绝不是完整或优雅的。我遇到的问题是在绘制平均图像时,颜色空间看起来像是扭曲的,看起来像CMKY。我不考虑最后两个移动窗口[4,5,1]和[5,1,2]。批评和建议表示欢迎。
答案 0 :(得分:2)
为了在图像的像素(或多个图像)上执行本地操作(例如运行平均值),convolution with a kernel通常是一种很好的方法。
以下是如何在您的情况下完成此操作。
我使用以下内容生成10个包含随机噪声的图像:
for i in range(10):
an_img = np.random.randint(0, 256, (960,1280,3))
cv2.imwrite("img_"+str(i)+".png", an_img)
这是我加载图像的方式:
# Get target file names
mypath = os.getcwd() # or whatever path you like
fnames = [f for f in listdir(mypath) if f.endswith('.png')]
# Create an array to hold all the images
first_img = cv2.imread(join(mypath, fnames[0]))
y,x,c = first_img.shape
all_imgs = np.empty((len(fnames),y,x,c), dtype=np.uint8)
# Load all the images
for i,fname in enumerate(fnames):
all_imgs[i,...] = cv2.imread(join(mypath, fnames[i]))
一些注意事项:
我使用f.endswith('.png')
来更具体地说明我如何生成文件名列表,允许其他文件在同一目录中而不会造成问题。
我将所有图片放在一个4D uint8 array
形状(image,y,x,c)
而不是您正在使用的object
数组中。这对于采用下面的卷积方法是必要的。
我使用第一个图像来获取图像的尺寸,这使得代码更加通用。
这就是全部。
from scipy.ndimage import uniform_filter
done = uniform_filter(all_imgs, size=(3,0,0,0), origin=-1, mode='wrap')
一些注意事项:
我正在使用scipy.ndimage
,因为它很容易将其卷积滤镜应用于具有多个维度的图像(在您的情况下为4)。对于cv2
,我只知道cv2.filter2D
,据我所知,它没有这个功能。但是,我对cv2
不太熟悉,所以我可能错了(如果有人在评论中对我进行了更正,则会进行编辑)。
size
kwarg指定要在数组的每个维度上使用的内核的大小。通过使用(3,0,0,0)
,我确保只使用第一个维度(=不同的图像)进行平均。
默认情况下,运行窗口(或更确切地说是kernel
)用于计算其中心像素的值。为了更加贴近您的代码,我使用origin=-1
,因此内核计算其中心左侧的像素值。
默认情况下,边缘情况(本例中为最后两个图像)由padding
处理并带有反射。您的问题表明您想要的是再次使用第一批图像。这是使用mode='wrap'
。
默认情况下,过滤器返回与输入相同dtype的结果,此处为np.uint8
。这可能是可取的,但是你的示例代码会生成浮点数,所以也许你希望过滤器返回浮点数,你可以通过简单地改变输入的dtype来做,即done = uniform_filter(all_imgs.astype(np.float), size...
。
绘制平均值时扭曲的色彩空间;我不能重现那个。您的方法似乎为我的随机噪声示例图像生成了正确的输出(在我对您的问题的评论中指出的问题的更正之后)。也许您可以尝试plt.imshow(temp_avg, interpolation='none')
以避免imshow
插值中出现的可能的伪像?