为什么我的 Python 脚本被杀死,用 Pillow 打开许多图像文件

问题描述

我有一个 python 脚本,它使用 Pillow 打开文件夹中的所有 png/jpg/jpeg 文件,将它们的一些元数据(文件名、大小、宽度、高度、像素、大小等)复制到一个新对象中并将该对象推送到名为 imageMetaData 的列表中。然后我遍历该列表以将每个图像与其他图像进行比较以尝试删除重复图像(我已经积累了大量重复图像,以至于我的 6000 张图像中至少有 1500 张可能是重复的)

使用小尺寸图像(~1500 是我成功完成的最大图像),它工作正常!但是当试图在我的文件夹上运行有 6100 个文件时它没有成功创建 imageMetaData 列表并实际打印:

zsh: killed     python3 remove-duplicates.py

我已经调查过了,似乎内存用完了。但似乎我的 RAM 应该足以容纳大约 6000 个对象的列表,其中每个对象大约有 8 个字段。

我的功能如下:

from PIL import Image
from os import listdir

mypath = 'my-path-to-folder/remove-dupes/'
initialLocation = 'my-folder-of-photos'
directoryList = listdir(mypath + initialLocation)

def loadobjects():
    myObjects = []
    if len(directoryList) > 1:
        for x in range(len(directoryList)):
            if ('jp' in directoryList[x].lower() or 'png' in directoryList[x].lower()):
                i = Image.open(mypath + initialLocation + '/' + directoryList[x])
                width,height = i.size
                pixels = i.load()
                i.close()
                myObjects.append({
                    'name': directoryList[x],'width': width,'height': height,'pixels': pixels,'size': os.stat(mypath + initialLocation + '/' + directoryList[x]).st_size,'biggest': directoryList[x],'index': x
                })
    return myObjects

正如所见,图像被打开、加载和关闭(正确?)所以我认为我没有留下任何东西。关于为什么要杀死它或可能如何获得更多关于它为什么被杀死的细节的任何想法?

解决方法

虽然看起来不太漂亮,但我确实使用了诺亚的建议,通过使用图像的高度和宽度选择 20 个像素来减少将每个图像的整个像素阵列推入我的新对象。不幸的是,即使像素数组应该相同,使用 hash(pixels) 似乎也返回了一个唯一值?在尝试删除此逻辑并使用哈希值之前,需要研究为什么会这样。

def getRandomPixels(pixels,width,height):
    randomPixels = []
    randomPixels.append(pixels[0,0])
    randomPixels.append(pixels[width - 1,height - 1])
    randomPixels.append(pixels[0,height - 1])
    randomPixels.append(pixels[width - 1,0])
    randomPixels.append(pixels[width/2,height/2])
    randomPixels.append(pixels[0,height/2])
    randomPixels.append(pixels[width/2,height - 1])
    randomPixels.append(pixels[width/4,height/4])
    randomPixels.append(pixels[0,height/4])
    randomPixels.append(pixels[width/4,height - 1])
    randomPixels.append(pixels[width/8,height/8])
    randomPixels.append(pixels[0,height/8])
    randomPixels.append(pixels[width/8,height - 1])
    randomPixels.append(pixels[width/2,height/8])
    return randomPixels

我选择这样选择像素是因为文件夹中的图像可能具有不同的尺寸,这确保了 1024 x 2048 的图片始终会通过查看相同的像素与另一张相同尺寸的图片进行比较。它还从图像中相距较远且不太可能相似的部分中进行选择,除非图片是重复的。

使用这种新方法,我能够运行 4975 张图像并在 618 秒内加载它们,然后由于我之前运行的像素阵列是 20x20 而不是高度 x 宽度,因此检查重复只需要 61 秒!谢谢诺亚!