如何使用PIL从100张图片中获得平均图片?

Han*_*Sun 20 python image python-imaging-library

例如,我有100张分辨率相同的图片,我想将它们合并为一张图片.对于最终图片,每个像素的RGB值是该位置处的100张图片的平均值.我知道这个getdata函数可以在这种情况下工作,但是在PIL(Python图像库)中有更简单,更快捷的方法吗?

Cnr*_*nrL 39

假设您的图像都是.png文件,它们都存储在当前工作目录中.下面的python代码将执行您想要的操作.正如Ignacio所说,使用numpy和PIL是关键.在构建平均像素强度时,您只需要在整数和浮点数组之间切换时要小心一点.

import os, numpy, PIL
from PIL import Image

# Access all PNG files in directory
allfiles=os.listdir(os.getcwd())
imlist=[filename for filename in allfiles if  filename[-4:] in [".png",".PNG"]]

# Assuming all images are the same size, get dimensions of first image
w,h=Image.open(imlist[0]).size
N=len(imlist)

# Create a numpy array of floats to store the average (assume RGB images)
arr=numpy.zeros((h,w,3),numpy.float)

# Build up average pixel intensities, casting each image as an array of floats
for im in imlist:
    imarr=numpy.array(Image.open(im),dtype=numpy.float)
    arr=arr+imarr/N

# Round values in array and cast as 8-bit integer
arr=numpy.array(numpy.round(arr),dtype=numpy.uint8)

# Generate, save and preview final image
out=Image.fromarray(arr,mode="RGB")
out.save("Average.png")
out.show()
Run Code Online (Sandbox Code Playgroud)

下面的图像是使用上面的代码从一系列HD视频帧生成的.

高清视频帧的平均值

  • 多数民众赞成的形象. (17认同)

Cnr*_*nrL 12

我发现很难想象内存在这里是一个问题,但在(不太可能)的事件中,你绝对无法负担创建我的原始答案所需的浮点数组,你可以使用PIL的混合函数, @ mHurley如下:

# Alternative method using PIL blend function
avg=Image.open(imlist[0])
for i in xrange(1,N):
    img=Image.open(imlist[i])
    avg=Image.blend(avg,img,1.0/float(i+1))
avg.save("Blend.png")
avg.show()
Run Code Online (Sandbox Code Playgroud)

您可以从PIL的混合函数的定义开始派生正确的alpha值序列:

out = image1 * (1.0 - alpha) + image2 * alpha
Run Code Online (Sandbox Code Playgroud)

考虑将该函数递归地应用于数字向量(而不是图像)以获得向量的均值.对于长度为N的向量,您需要N-1个混合操作,其中N-1个不同的alpha值.

但是,直观地思考操作可能更容易.在每个步骤中,您希望avg图像包含来自早期步骤的相同比例的源图像.在混合第一和第二源图像时,alpha应为1/2以确保相等的比例.当将第三个与前两个的平均值混合时,您希望新图像由第三个图像的1/3组成,其余部分由前一个图像的平均值组成(当前平均值) , 等等.

原则上,基于混合的这个新答案应该没问题.但是我不确切知道混合功能是如何工作的.这让我担心每次迭代后像素值如何舍入.

下图是使用我原来答案中的代码从288个源图像生成的:

平均的原始答案

另一方面,通过将PIL的混合函数重复应用于相同的288个图像来生成此图像:

混合,使用Image.blend

我希望你能看到两种算法的输出明显不同.我希望这是因为在重复应用Image.blend期间累积了小的舍入误差

我强烈推荐这个替代方案的原始答案.


Kat*_*ova 7

还可以使用 numpy mean 函数进行平均。代码看起来更好,运行速度更快。

这里是 700 张嘈杂的人脸灰度图像的时序和结果的比较:

def average_img_1(imlist):
    # Assuming all images are the same size, get dimensions of first image
    w,h=Image.open(imlist[0]).size
    N=len(imlist)

    # Create a numpy array of floats to store the average (assume RGB images)
    arr=np.zeros((h,w),np.float)

    # Build up average pixel intensities, casting each image as an array of floats
    for im in imlist:
        imarr=np.array(Image.open(im),dtype=np.float)
        arr=arr+imarr/N
    out = Image.fromarray(arr)
    return out

def average_img_2(imlist):
    # Alternative method using PIL blend function
    N = len(imlist)
    avg=Image.open(imlist[0])
    for i in xrange(1,N):
        img=Image.open(imlist[i])
        avg=Image.blend(avg,img,1.0/float(i+1))
    return avg

def average_img_3(imlist):
    # Alternative method using numpy mean function
    images = np.array([np.array(Image.open(fname)) for fname in imlist])
    arr = np.array(np.mean(images, axis=(0)), dtype=np.uint8)
    out = Image.fromarray(arr)
    return out

average_img_1() 
100 loops, best of 3: 362 ms per loop

average_img_2()
100 loops, best of 3: 340 ms per loop

average_img_3()
100 loops, best of 3: 311 ms per loop
Run Code Online (Sandbox Code Playgroud)

顺便说一句,平均的结果是完全不同的。我认为第一种方法在平均过程中会丢失信息。第二个有一些文物。

average_img_1

在此处输入图片说明

average_img_2

在此处输入图片说明

average_img_3

在此处输入图片说明


Fáb*_*bio 5

如果有人对蓝图 numpy 解决方案感兴趣(我实际上正在寻找它),这里是代码:

mean_frame = np.mean(([frame for frame in frames]), axis=0)
Run Code Online (Sandbox Code Playgroud)