获取图片大小而不加载图片到内存中

164

我知道你可以使用PIL以以下方式获取图像大小

from PIL import Image
im = Image.open(image_filename)
width, height = im.size

但是,我希望在不将图像加载到内存中的情况下获得图像的宽度和高度。这可行吗? 我只对图像大小进行统计,不关心图像内容。 我只想让我的处理更快。


14
我不是100%确定,但我认为.open()并不会将整个文件读入内存...(这是.load()的作用) - 换句话说,就我所知道的,使用PIL这样做已经很好了。 - Jon Clements
9
即使你认为你的函数只是读取图像头信息,文件系统预读代码仍可能加载整个图像。除非你的应用需要关注性能,否则担心性能是不生产的。 - stark
11
使用 pmap 监控进程使用的内存进行快速记忆测试后,我发现确实 PIL 没有将整个图像加载到内存中。 - Vincent Nivoliers
参见:使用 Python 获取图像尺寸 - Martin Thoma
10个回答

124
如果您不关心图像内容,PIL 可能过于繁琐。我建议解析 Python magic 模块的输出:
>>> t = magic.from_file('teste.png')
>>> t
'PNG image data, 782 x 602, 8-bit/color RGBA, non-interlaced'
>>> re.search('(\d+) x (\d+)', t).groups()
('782', '602')

这是一个围绕着libmagic的包装器,它读取尽可能少的字节以识别文件类型签名。
相关脚本版本:

https://raw.githubusercontent.com/scardine/image_size/master/get_image_size.py

[更新]

唔,不幸的是,当应用于JPEG格式时,上述代码只会返回“'JPEG image data, EXIF standard 2.21'”,没有图像尺寸! - Alex Flint

似乎JPEG文件具有抵抗魔法的能力。:-)

我可以理解为什么:为了获取JPEG文件的图像尺寸,您可能需要读取比libmagic允许的更多字节。

我卷起袖子并提供了这个未经测试的片段(从GitHub获取),它不需要第三方模块。

Look, Ma! No deps!

#-------------------------------------------------------------------------------
# Name:        get_image_size
# Purpose:     extract image dimensions given a file path using just
#              core modules
#
# Author:      Paulo Scardine (based on code from Emmanuel VAÏSSE)
#
# Created:     26/09/2013
# Copyright:   (c) Paulo Scardine 2013
# Licence:     MIT
#-------------------------------------------------------------------------------
#!/usr/bin/env python
import os
import struct

class UnknownImageFormat(Exception):
    pass

def get_image_size(file_path):
    """
    Return (width, height) for a given img file content - no external
    dependencies except the os and struct modules from core
    """
    size = os.path.getsize(file_path)

    with open(file_path) as input:
        height = -1
        width = -1
        data = input.read(25)

        if (size >= 10) and data[:6] in ('GIF87a', 'GIF89a'):
            # GIFs
            w, h = struct.unpack("<HH", data[6:10])
            width = int(w)
            height = int(h)
        elif ((size >= 24) and data.startswith('\211PNG\r\n\032\n')
              and (data[12:16] == 'IHDR')):
            # PNGs
            w, h = struct.unpack(">LL", data[16:24])
            width = int(w)
            height = int(h)
        elif (size >= 16) and data.startswith('\211PNG\r\n\032\n'):
            # older PNGs?
            w, h = struct.unpack(">LL", data[8:16])
            width = int(w)
            height = int(h)
        elif (size >= 2) and data.startswith('\377\330'):
            # JPEG
            msg = " raised while trying to decode as JPEG."
            input.seek(0)
            input.read(2)
            b = input.read(1)
            try:
                while (b and ord(b) != 0xDA):
                    while (ord(b) != 0xFF): b = input.read(1)
                    while (ord(b) == 0xFF): b = input.read(1)
                    if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
                        input.read(3)
                        h, w = struct.unpack(">HH", input.read(4))
                        break
                    else:
                        input.read(int(struct.unpack(">H", input.read(2))[0])-2)
                    b = input.read(1)
                width = int(w)
                height = int(h)
            except struct.error:
                raise UnknownImageFormat("StructError" + msg)
            except ValueError:
                raise UnknownImageFormat("ValueError" + msg)
            except Exception as e:
                raise UnknownImageFormat(e.__class__.__name__ + msg)
        else:
            raise UnknownImageFormat(
                "Sorry, don't know how to get information from this file."
            )

    return width, height

[更新 2019年]

请查看 Rust 实现:https://github.com/scardine/imsz


3
我还在EJEHardenberg提供的版本的注释中添加了检索通道数(不要与位深度混淆)的功能。 - Greg Kramida
3
太好了。我在 GitHub 项目中添加了位图支持。谢谢! - Mallard
2
注意:当前版本对我无效。@PauloScardine在https://github.com/scardine/image_size上有一个更新的可用版本。 - DankMasterDan
5
在MacOS上,使用Python3时,在data = input.read(25)处出现了UnicodeDecodeError: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte错误。对于图像的file,它给出了PNG image data, 720 x 857, 8-bit/color RGB, non-interlaced - mrgloom
4
看起来来自 https://raw.githubusercontent.com/scardine/image_size/master/get_image_size.py 的代码可用。 - mrgloom
显示剩余11条评论

85

正如评论所示,PIL在调用.open时不会将图像加载到内存中。查看PIL 1.1.7的文档,.open的docstring如下:

def open(fp, mode="r"):
    "Open an image file, without loading the raster data"

源代码中有一些文件操作,比如:

 ...
 prefix = fp.read(16)
 ...
 fp.seek(0)
 ...

但这些几乎不能构成阅读整个文件。实际上,.open 仅在成功时返回文件对象和文件名。此外,文档中写道:

open(file, mode=”r”)

打开并识别给定的图像文件。

这是一个惰性操作;此函数识别文件,但实际图像数据直到尝试处理数据(或调用load方法)时才从文件中读取。

深入挖掘,我们看到 .open 调用了 _open,后者是一种特定于图像格式的重载。每个 _open 的实现都可以在新的文件中找到,例如 .jpeg 文件在 JpegImagePlugin.py 中。让我们深入了解其中的一个。

在这里,事情似乎有点棘手,在其中存在一个无限循环,当找到 jpeg 标记时会被中断:

    while True:

        s = s + self.fp.read(1)
        i = i16(s)

        if i in MARKER:
            name, description, handler = MARKER[i]
            # print hex(i), name, description
            if handler is not None:
                handler(self, i)
            if i == 0xFFDA: # start of scan
                rawmode = self.mode
                if self.mode == "CMYK":
                    rawmode = "CMYK;I" # assume adobe conventions
                self.tile = [("jpeg", (0,0) + self.size, 0, (rawmode, ""))]
                # self.__offset = self.fp.tell()
                break
            s = self.fp.read(1)
        elif i == 0 or i == 65535:
            # padded marker or junk; move on
            s = "\xff"
        else:
            raise SyntaxError("no marker found")

如果文件格式不正确,它似乎可以读取整个文件。然而,如果它能够正确读取信息标记,它应该会提前退出。函数handler最终设置了self.size,这是图像的尺寸。


4
没错,但是 open 方法是否能获取到图片的大小呢?这个操作是否也是惰性的呢?如果是惰性的,它是否同时读取了图片数据? - Mark Ransom
文档链接指向 Pillow,这是 PIL 的一个分支。然而,我在网上找不到官方的文档链接。如果有人在评论中发布链接,我会更新答案。引用可以在文件 Docs/PIL.Image.html 中找到。 - Hooked
@MarkRansom 我已经尝试回答你的问题,但是为了100%确定,我们似乎需要深入研究每个图像特定的实现。只要找到头部,.jpeg格式看起来就没问题。 - Hooked
@Hooked:非常感谢您的研究。我承认您是正确的,尽管我很喜欢保罗在下面提出的相当简洁的解决方案(尽管公正地说,OP没有提到想要避免PIL依赖)。 - Alex Flint
1
@AlexFlint 没问题,研究代码总是很有趣的。我认为保罗赢得了他的赏金,他为你编写了一个不错的片段。 - Hooked
对于那些十年后来到这里的人: 这个答案适用于jpg和png格式,比cv2.imread快得多。 - gordinmitya

74

24
我进行了speed imagesize.get、magic.from_file和PIL image三个函数的比较,通过timeit获取实际图像大小。结果显示,速度imagesize.get(0.019秒)> PIL(0.104秒)>带有正则表达式的magic(0.1699秒)。 - RyanLiu
我可以确认,imagesize非常好用,对于简单地获取图像的尺寸非常高效。 - Heinrich
4
@RyanLiu,我觉得>符号的反向很令人困惑。难道时间不是“更短”吗? - Gulzar
3
@Gulzar FYI - 我认为 > 符号适用于速度(即更快 > 更慢),但是他在括号中放置了时间,这与符号不一致。 - Jonathan
请注意,imagesize不会查看图像的EXIF旋转信息,因此如果使用EXIF头旋转图像,则宽度和高度将被交换。2021年提出了一个功能请求,但作者尚未回复。 - FWDekker
在我们的图像推断databricks作业中,有一些巨大的图像使得opencv失败,例如:Caused by: org.apache.spark.api.python.PythonException: 'cv2.error: OpenCV(4.7.0) /io/opencv/modules/imgcodecs/src/loadsave.cpp:79: error: (-215:Assertion failed) pixels <= CV_IO_MAX_IMAGE_PIXELS in function 'validateInputImageSize''即使将环境变量CV_IO_MAX_IMAGE_PIXELS设置为非常大的值。现在使用该库以避免处理庞大的图像。谢谢。 - arun

15

原帖提到需要一种更快的解决方案,我对最快的解决方案很感兴趣,并试图通过真实世界的基准测试来回答这个问题。

我正在比较以下内容:

我正在对202897个大多数为JPG文件的文件运行以下代码:

"""
pip install opsdroid-get-image-size --user
pip install pymage_size
pip install imagesize
"""

import concurrent.futures
from pathlib import Path

import cv2
import numpy as np
import pandas as pd
from tqdm import tqdm
from PIL import Image
import get_image_size
import imagesize
import pymage_size

files = [str(p.resolve())
         for p in Path("/data/").glob("**/*")
         if p.suffix in {".jpg", ".jpeg", ".JPEG", ".JPG", ".png", ".PNG"}]

def get_shape_cv2(fname):
    img = cv2.imread(fname)
    return (img.shape[0], img.shape[1])

with concurrent.futures.ProcessPoolExecutor(8) as executor:
    results = list(tqdm(executor.map(get_shape_cv2, files), total=len(files)))

def get_shape_pil(fname):
    img=Image.open(fname)
    return (img.size[0], img.size[1])

with concurrent.futures.ProcessPoolExecutor(8) as executor:
    results = list(tqdm(executor.map(get_shape_pil, files), total=len(files)))

def get_shape_scardine_size(fname):
    try:
        width, height = get_image_size.get_image_size(fname)
    except get_image_size.UnknownImageFormat:
        width, height = -1, -1
    return (width, height)

with concurrent.futures.ProcessPoolExecutor(8) as executor:
    results = list(tqdm(executor.map(get_shape_scardine_size, files), total=len(files)))

def get_shape_shibukawa(fname):
    width, height = imagesize.get(fname)
    return (width, height)

with concurrent.futures.ProcessPoolExecutor(8) as executor:
    results = list(tqdm(executor.map(get_shape_shibukawa, files), total=len(files)))

def get_shape_pymage_size(fname):
    img_format = pymage_size.get_image_size(fname)
    width, height = img_format.get_dimensions()
    return (width, height)

with concurrent.futures.ProcessPoolExecutor(8) as executor:
    results = list(tqdm(executor.map(get_shape_pymage_size, files), total=len(files)))

结果:

  • cv2.imread:8m23s
  • PIL.open:2m00s
  • opsdroid/image_size:29s
  • shibukawa/imagesize_py:29s
  • kobaltcore/pymage_size:29s

因此,opsdroid、shibukawa和kobaltcore的执行速度相同。 现在对我来说更有趣的另一个点是更好地了解哪个库具有最佳的格式支持。

[编辑]因此,我前进并测试了快速库是否提供不同的结果:

# test if the libs provide the same results
def show_size_differences(fname):
    w1, h1 = get_shape_scardine_size(fname)
    w2, h2 = get_shape_pymage_size(fname)
    w3, h3 = get_shape_shibukawa(fname)
    if w1 != w2 or w2 != w3 or h1 != h2 or h2 != h3:
        print(f"scardine: {w1}x{h1}, pymage: {w2}x{h2}, shibukawa: {w3}x{h3}")

with concurrent.futures.ProcessPoolExecutor(8) as executor:
    results = list(tqdm(executor.map(show_size_differences, files), total=len(files)))

他们并没有。


但是为什么它们运行缓慢呢?如果它们只是流行库中的简单错误,怎么办? - user894319twitter
请也从scardine那里添加! - user894319twitter
1
scardine 和 opsdroid 是相同的,查看 scardine 的自述文件。 - dreamflasher

11

我经常在互联网上获取图像尺寸。当然,你不能下载图像,然后加载它来解析信息。这太费时间了。我的方法是将块馈送到图像容器中,每次测试是否可以解析图像。当我获得想要的信息时停止循环。

我提取了我的代码核心并修改它以解析本地文件。

from PIL import ImageFile

ImPar=ImageFile.Parser()
with open(r"D:\testpic\test.jpg", "rb") as f:
    ImPar=ImageFile.Parser()
    chunk = f.read(2048)
    count=2048
    while chunk != "":
        ImPar.feed(chunk)
        if ImPar.image:
            break
        chunk = f.read(2048)
        count+=2048
    print(ImPar.image.size)
    print(count)

输出:

(2240, 1488)
38912

实际文件大小为1,543,580字节,而您只读取了38,912字节来获取图像大小。希望这能帮到您。


每次 count+=2048 都不是很聪明。这是线性的... - user894319twitter

2

在Unix系统上进行快速处理的另一种方法。这取决于file输出,我不确定它是否在所有系统上都标准化了。这种方法可能不适用于生产环境代码。此外,大多数JPEG都未报告图像大小。

import subprocess, re
image_size = list(map(int, re.findall('(\d+)x(\d+)', subprocess.getoutput("file " + filename))[-1]))

返回“IndexError:列表索引超出范围” - mrgloom
当我直接运行Python文件时,这个方法对我有效。但是当我尝试将我的代码放入Docker容器中时,会抛出以下错误: “IndexError: list index out of range” 看起来以下命令无法在Docker容器中找到我的文件: “subprocess.getoutput(“file”+ filename)” - bmabir17

1

这个答案有另一个很好的解决方案,但缺少pgm格式。这个答案已经解决了pgm。我添加了bmp

代码如下:

import struct, imghdr, re, magic

def get_image_size(fname):
    '''Determine the image type of fhandle and return its size.
    from draco'''
    with open(fname, 'rb') as fhandle:
        head = fhandle.read(32)
        if len(head) != 32:
            return
        if imghdr.what(fname) == 'png':
            check = struct.unpack('>i', head[4:8])[0]
            if check != 0x0d0a1a0a:
                return
            width, height = struct.unpack('>ii', head[16:24])
        elif imghdr.what(fname) == 'gif':
            width, height = struct.unpack('<HH', head[6:10])
        elif imghdr.what(fname) == 'jpeg':
            try:
                fhandle.seek(0) # Read 0xff next
                size = 2
                ftype = 0
                while not 0xc0 <= ftype <= 0xcf:
                    fhandle.seek(size, 1)
                    byte = fhandle.read(1)
                    while ord(byte) == 0xff:
                        byte = fhandle.read(1)
                    ftype = ord(byte)
                    size = struct.unpack('>H', fhandle.read(2))[0] - 2
                # We are at a SOFn block
                fhandle.seek(1, 1)  # Skip `precision' byte.
                height, width = struct.unpack('>HH', fhandle.read(4))
            except Exception: #IGNORE:W0703
                return
        elif imghdr.what(fname) == 'pgm':
            header, width, height, maxval = re.search(
                b"(^P5\s(?:\s*#.*[\r\n])*"
                b"(\d+)\s(?:\s*#.*[\r\n])*"
                b"(\d+)\s(?:\s*#.*[\r\n])*"
                b"(\d+)\s(?:\s*#.*[\r\n]\s)*)", head).groups()
            width = int(width)
            height = int(height)
        elif imghdr.what(fname) == 'bmp':
            _, width, height, depth = re.search(
                b"((\d+)\sx\s"
                b"(\d+)\sx\s"
                b"(\d+))", str).groups()
            width = int(width)
            height = int(height)
        else:
            return
        return width, height

然而,imghdr 对某些 JPEG 图像的处理效果不佳。 - martixy

0

虽然这是一个非常老的问题,但我尝试了几种方法,但对于我的大型3D Tif文件都没有用。因此,这里有一个非常简单和快速的解决方案,使用“tifffile”包中的“memmap”函数:

    import tifffile
    memmap_image = tifffile.memmap(fp)
    memmap_image.shape

我的450 GB 32位Tif图像的运行时间:10毫秒


0

我尝试了以下方法:

  1. 魔法库
  2. PIL(Python图像库)
  3. imagesize库

我发现:

  1. 使用正则表达式解析magic的字符串输出是不可靠的,因为所有文件类型的字符串输出都不同。如果您的系统接受多种或许多不同的图像类型,则必须确保正确解析字符串输出。请参见下面我的测试输出,以了解每个文件类型的字符串输出。
  2. imagesize库不太健壮。目前,它默认分析JPEG / JPEG 2000 / PNG / GIF / TIFF / SVG / Netpbm / WebP。当它尝试查找无法处理的文件的图像大小时,它会给出(-1,-1)的大小。您可以在下面的.BMP示例中看到这一点。

我的结论 - 我会选择PIL。虽然它不像imagesize库那样快速,但它更强大,可以处理更多的文件类型。我认为对于大多数用例来说,它已经足够快了。使用re解析magic输出是不可靠的,而且比PIL慢得多。

我的测试

我从硬盘中取出一张保存的图像(636 x 636),并将其保存为6种不同的文件格式(.png、.jpg、.jpeg、.tif、.tiff、.bmp)。这些图像和脚本都保存在同一个目录下。我的测试中每种文件类型的大小都在下面的文件名旁边注释了出来。

脚本:

import os
import re
import timeit
import magic
import imagesize

import time
from PIL import Image



"""
Notes:
 - all images are the same image saved as different formats
 - file extensions tested are: .png, .jpg, .jpeg, .tif, .tiff, .bmp
 - all images in this test are size 636 x 636
 - all images are in the same directory as this script

If you want to setup this similar experiment, take a single image,
save it as: png_image.png, jpg_image.jpg, jpeg_image.jpeg, tif_image.tif,
tiff_image.tiff, and bmp_image.bmp (others if you'd like),
in the same directory as this script, and run this script.
Or name the images whatever and modify the script below. You do you.
"""

NUMBER = 10000
REPEAT = 5

def regex(filename):
    name,ext = os.path.splitext(filename)
    if ext.lower() in ['.tif', '.tiff']:
        return '^(?=.*width=(\d+))(?=.*height=(\d+))'
    elif ext.lower() in ['.jpg', '.jpeg', '.png']:
        return '(\d+)\s?x\s?(\d+)'
    elif ext.lower() in ['.bmp']:
        return '(\d+)\s?x\s?(\d+)\s?x\s?\d+'
    else:
        raise Exception('Extension %s is not accounted for.' % ext.lower())

PNG_FILE = 'png_image.png' # 559 KB
JPG_FILE = 'jpg_image.jpg' # 94 KB
JPEG_FILE = 'jpeg_image.jpeg' # 94 KB
TIF_FILE = 'tif_image.tif' # 768 KB
TIFF_FILE = 'tiff_image.tiff' # 768 KB
BMP_FILE = 'bmp_image.bmp' # 1,581 KB

FILENAMES = [PNG_FILE, JPG_FILE, JPEG_FILE, TIF_FILE, TIFF_FILE, BMP_FILE]

now = time.time()
for filename in FILENAMES:
    print('#' * 36)
    print((" Testing %s" % filename).center(36, "#"))
    print('#' * 36)

    print('# ' + 'magic library'.center(32) + ' #')
    print('  ', 'output:', magic.from_file(filename))
    print('  ', "Size:", re.findall(regex(filename), magic.from_file(filename))[-1])
    print('  ', "Regex used:", regex(filename))
    
    print('# ' + 'PIL library'.center(32) + ' #')
    image = Image.open(filename)
    print('  ', image)
    print('  ', "Size:", image.size)
    print('  ', "Regex used:", 'None')

    print('# ' + 'imagesize library'.center(32) + ' #')
    image = imagesize.get(filename)
    print('  ', "Size:", image)
    print('  ', "Regex used:", 'None')

    print('-' * 30 + '\n')

print("#################################end#######################################\n")

start = time.time()
for filename in FILENAMES:
    print((" Testing %s " % filename).center(36, "#"))
    
    # magic library
    magic_timer = timeit.Timer(
        stmt="width, height = re.findall(pattern, magic.from_file(filename))[-1]",
        setup="import magic; import re; filename='" + filename + "'; pattern=r'" + regex(filename) + "';",
    )

    magic_timeit = magic_timer.timeit(number=NUMBER)
    magic_repeat = magic_timer.repeat(repeat=REPEAT, number=NUMBER)
    print('magic'.ljust(12) + ":", "%.15f," % magic_timeit, "%s repeat avg. : %.15f" % (REPEAT, sum(magic_repeat) / REPEAT))

    # PIL library
    pillow_timer = timeit.Timer(
        stmt="width, height = Image.open(filename).size;",
        setup="from PIL import Image; filename='" + filename + "';",
    )

    pillow_timeit = pillow_timer.timeit(number=NUMBER)
    pillow_repeat = pillow_timer.repeat(repeat=REPEAT, number=NUMBER)
    print('PIL'.ljust(12) + ":", "%.15f," % pillow_timeit, "%s repeat avg. : %.15f" % (REPEAT, sum(pillow_repeat) / REPEAT))


    # imagesize library
    imagesize_timer = timeit.Timer(
        stmt="width, height = imagesize.get(filename);",
        setup="import imagesize; filename='" + filename + "';",
    )

    imagesize_timeit = imagesize_timer.timeit(number=NUMBER)
    imagesize_repeat = imagesize_timer.repeat(repeat=REPEAT, number=NUMBER)
    print('imagesize'.ljust(12) + ":", "%.15f," % imagesize_timeit, "%s repeat avg. : %.15f" % (REPEAT, sum(imagesize_repeat) / REPEAT))

stop = time.time()
mins, secs = divmod(stop - start, 60)
print('\nTest time: %d minutes %d seconds' % (mins, secs)) 

print("\n#################################end#######################################\n")

输出:

####################################
####### Testing png_image.png#######
####################################
#          magic library           #
   output: PNG image data, 636 x 636, 8-bit/color RGB, non-interlaced
   Size: ('636', '636')
   Regex used: (\d+)\s?x\s?(\d+)
#           PIL library            #
   <PIL.PngImagePlugin.PngImageFile image mode=RGB size=636x636 at 0x1EBDE962710>
   Size: (636, 636)
   Regex used: None
#        imagesize library         #
   Size: (636, 636)
   Regex used: None
------------------------------

####################################
####### Testing jpg_image.jpg#######
####################################
#          magic library           #
   output: JPEG image data, JFIF standard 1.01, resolution (DPI), density 96x96, segment length 16, baseline, precision 8, 636x636, frames 3
   Size: ('636', '636')
   Regex used: (\d+)\s?x\s?(\d+)
#           PIL library            #
   <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=636x636 at 0x1EBDF3E1810>
   Size: (636, 636)
   Regex used: None
#        imagesize library         #
   Size: (636, 636)
   Regex used: None
------------------------------

####################################
###### Testing jpeg_image.jpeg######
####################################
#          magic library           #
   output: JPEG image data, JFIF standard 1.01, resolution (DPI), density 96x96, segment length 16, baseline, precision 8, 636x636, frames 3
   Size: ('636', '636')
   Regex used: (\d+)\s?x\s?(\d+)
#           PIL library            #
   <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=636x636 at 0x1EBDF3E3010>
   Size: (636, 636)
   Regex used: None
#        imagesize library         #
   Size: (636, 636)
   Regex used: None
------------------------------

####################################
####### Testing tif_image.tif#######
####################################
#          magic library           #
   output: TIFF image data, little-endian, direntries=16, height=636, bps=63732, compression=LZW, PhotometricIntepretation=RGB, width=636
   Size: ('636', '636')
   Regex used: ^(?=.*width=(\d+))(?=.*height=(\d+))
#           PIL library            #
   <PIL.TiffImagePlugin.TiffImageFile image mode=RGBA size=636x636 at 0x1EBDF3E1810>
   Size: (636, 636)
   Regex used: None
#        imagesize library         #
   Size: (636, 636)
   Regex used: None
------------------------------

####################################
###### Testing tiff_image.tiff######
####################################
#          magic library           #
   output: TIFF image data, little-endian, direntries=16, height=636, bps=63732, compression=LZW, PhotometricIntepretation=RGB, width=636
   Size: ('636', '636')
   Regex used: ^(?=.*width=(\d+))(?=.*height=(\d+))
#           PIL library            #
   <PIL.TiffImagePlugin.TiffImageFile image mode=RGBA size=636x636 at 0x1EBDF3E3160>
   Size: (636, 636)
   Regex used: None
#        imagesize library         #
   Size: (636, 636)
   Regex used: None
------------------------------

####################################
####### Testing bmp_image.bmp#######
####################################
#          magic library           #
   output: PC bitmap, Windows 3.x format, 636 x 636 x 32
   Size: ('636', '636')
   Regex used: (\d+)\s?x\s?(\d+)\s?x\s?\d+
#           PIL library            #
   <PIL.BmpImagePlugin.BmpImageFile image mode=RGB size=636x636 at 0x1EBDF3E31F0>
   Size: (636, 636)
   Regex used: None
#        imagesize library         #
   Size: (-1, -1)
   Regex used: None
------------------------------

#################################end#######################################

每个库/方法的时间比较。我将timeit设置为10,000次,并重复5次。参考资料,运行时间为7分46秒。
###### Testing png_image.png #######
magic       : 9.280310999951325 , 5 repeat avg. : 8.674063340038993
PIL         : 1.069168900023215 , 5 repeat avg. : 1.100983139988966
imagesize   : 0.676764299976639 , 5 repeat avg. : 0.658798480057158
###### Testing jpg_image.jpg #######
magic       : 7.006248699966818 , 5 repeat avg. : 6.803474060003646
PIL         : 1.295019199955277 , 5 repeat avg. : 1.230920840008184
imagesize   : 0.709322200040333 , 5 repeat avg. : 0.706342480005696
##### Testing jpeg_image.jpeg ######
magic       : 6.531979499966837 , 5 repeat avg. : 6.501230620010756
PIL         : 1.263985900091939 , 5 repeat avg. : 1.263613799982704
imagesize   : 0.666680400026962 , 5 repeat avg. : 0.701455319998786
###### Testing tif_image.tif #######
magic       : 11.265482199960388, 5 repeat avg. : 11.423775779991411
PIL         : 3.702962300041690 , 5 repeat avg. : 3.857250300026499
imagesize   : 0.764358000014909 , 5 repeat avg. : 0.750753180007450
##### Testing tiff_image.tiff ######
magic       : 11.288321400061250, 5 repeat avg. : 11.339019200019539
PIL         : 4.116472600027919 , 5 repeat avg. : 3.834464759984985
imagesize   : 0.753993199905381 , 5 repeat avg. : 0.758465819992125
###### Testing bmp_image.bmp #######
magic       : 16.124460300081410, 5 repeat avg. : 16.291060140007176
PIL         : 0.919579099980183 , 5 repeat avg. : 0.928753740014508
imagesize   : 0.649574000039138 , 5 repeat avg. : 0.654250180022791

Test time: 7 minutes 46 seconds

#################################end#######################################

注意:我不是时间方面的专家,如果我的时间安排方法似乎无效,请指出。


0

跳过直接访问EXIF数据并存储整数。

from PIL import Image
img_x = Image.open(image_filename)._getexif()[40962]
img_y = Image.open(image_filename)._getexif()[40963]

请参阅此页面了解EXIF标签。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接