如何在Python中仅读取图像的宽度和高度,而不读取数据?
如何在Python中仅读取图像的宽度和高度,而不读取数据?
问题的出现原因:
在处理图像时,有时只需要获取图像的宽度和高度,而不需要读取整个图像数据。然而,常用的图像处理库(如PIL)通常会读取整个图像数据,这在处理大型图像时可能会导致性能问题。因此,需要一种方法来仅读取图像的宽度和高度,而不读取整个图像数据。
解决方法:
可以使用一个名为"imagesize"的Python包来解决这个问题。该包可以在PyPI上找到,并且可以通过pip安装。使用该包的get函数可以轻松地获取图像的宽度和高度。
以下是使用"imagesize"包的示例代码:
import imagesize width, height = imagesize.get("test.png") print(width, height)
这将打印出图像的宽度和高度。
"imagesize"包非常高效,可以快速地获取图像的尺寸。根据进行的比较测试,它的速度要快于其他常用的图像处理库,如PIL和magic。
然而,需要注意的是,"imagesize"包不会考虑图像的EXIF旋转信息。如果图像使用EXIF头信息进行了旋转,那么图像的宽度和高度可能会被交换。目前,有一个关于这个问题的功能请求,但作者尚未给出答复。
通过使用"imagesize"包,我们可以轻松地获取图像的宽度和高度,而无需读取整个图像数据。这对于处理大型图像或只关心图像尺寸的情况非常有用。该包的使用非常简单,可以通过pip进行安装,并且具有良好的性能。然而,需要注意的是,它不会考虑图像的EXIF旋转信息。
问题的出现原因是PIL在调用.open方法时并没有将整个图像加载到内存中。根据PIL 1.1.7的文档,.open方法的文档字符串中写道:“打开一个图像文件,但不加载光栅数据”。实际上,.open方法只是返回一个文件对象和文件名。此外,文档还指出:“打开(file,mode=”r“)是一个惰性操作;该函数识别文件,但实际的图像数据直到尝试处理数据(或调用load方法)时才从文件中读取”。
解决方法是查看.open方法调用了_overload,这是一个特定于图像格式的重载方法。可以在新文件中找到每个_overload的实现,例如.jpeg文件在JpegImagePlugin.py中。在这个文件中有一个无限循环,当找到jpeg标记时会跳出循环。在循环中,通过调用handler方法设置了self.size,这是图像的尺寸。
但是,open方法是否获取了图像的尺寸,或者这也是一个惰性操作?如果是惰性操作,它是否同时读取图像数据?
Pillow是PIL的一个分支,但我在网上找不到官方文档链接。如果有人将其作为评论发表,我会更新答案。这段引用可以在文件Docs/PIL.Image.html中找到。
为了确保100%的准确性,我们需要深入研究每个特定于图像的实现。.jpeg格式看起来还不错,只要找到了头部。
对于晚来10年的人来说,这个答案对于jpg和png格式都是正确的,比cv2.imread要快得多。
问题的出现原因是PIL的.open方法并不会读取整个图像文件,而只是识别文件。解决方法是通过查看特定于图像格式的实现来获取图像的尺寸。
如何在Python中仅读取图像的宽度和高度,而不读取数据?
有时候我们只需要获取图像的宽度和高度,而不需要读取整个图像的内容。在这种情况下,使用Python Imaging Library(PIL)可能会显得过于复杂。下面我们将介绍一个解决方法。
解决方法:
一种解决方法是使用python magic模块来解析图像文件的输出。这个模块是对libmagic的封装,它通过读取尽可能少的字节来确定文件类型。
具体操作如下:
import magic import re t = magic.from_file('teste.png') print(t) print(re.search('(\d+) x (\d+)', t).groups())
上述代码将输出图像的宽度和高度。
如果上述方法对于JPEG文件无效,我们可以尝试读取更多的字节来获取图像的尺寸。下面是一个使用Python的核心模块编写的示例代码,它可以获取图像文件的宽度和高度,而无需任何第三方模块。
import os import struct class UnknownImageFormat(Exception): pass def get_image_size(file_path): 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'): w, h = struct.unpack("= 24) and data.startswith('\211PNG\r\n\032\n') and (data[12:16] == 'IHDR')): 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'): w, h = struct.unpack(">LL", data[8:16]) width = int(w) height = int(h) elif (size >= 2) and data.startswith('\377\330'): 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
上述代码将返回图像的宽度和高度。
这个解决方法没有使用PIL,因此不需要安装任何额外的依赖库。它适用于大多数环境,并且比PIL更加轻量级。
希望这个解决方法对你有帮助!如果你有其他更好的解决方法,欢迎分享。