了解本系列文章
第 1 部分:使用 Python 为数字艺术家自动化重复性任务
如果你在电脑上处理图像,你迟早会遇到损坏的文件,这会毁了你的一天。我在动画渲染中遇到了这种情况(记住,这里的最佳实践是渲染成一系列图像文件,而不是单个视频文件)。然而,动画和视觉效果并不是你看到图像损坏的唯一领域。你在其他领域也很容易遇到这种情况。也许你是一名摄影师,你拍摄了一堆包围曝光 HDRI(高动态范围成像)色调映射,并且在从相机传输文件时出现了一些故障。
问题不在于修复或替换损坏的图像需要多少精力,这通常只是重新渲染图像或将好的图像重新复制到你的计算机,而诀窍是在过程中尽早找到这些坏图像。你不知道的时间越长,当你真正遇到损坏的图像时,你将面临的麻烦就越大。
那么,你该怎么办呢?嗯,你可以浏览并在你选择的图像编辑器或查看器中一次打开一个文件,并让该程序告诉你存在问题。然而,照片图像很大,并且浏览整个集合以找到一两个坏家伙可能很烦人且耗时。虽然动画渲染通常是较小的文件,但你通常有更多的文件要浏览。就我而言,我经常制作渲染,在一个渲染中包含超过 44,000 帧。(不,这不是错别字——四万四千帧。)
解决方案?你猜对了。编写一个脚本。
与本系列之前的文章一样,你将使用 Python 进行脚本编写。第一步:获取你的文件列表。幸运的是,如果你已经阅读了本系列中的上一篇文章,你就知道这只是使用 os 模块的问题。假设你要检查的所有图像文件都位于硬盘驱动器上的单个目录中。此外,假设你将从该目录中运行此脚本。使用 Python,你可以使用以下代码获取这些文件的列表
import os
for filename in os.listdir('./'):
print(filename)
如果你愿意,你可以缩小图像列表的范围(或至少更清楚地指定它;例如,你不想将此脚本作为其中一个文件包含在内),方法是仅查找以 PNG 扩展名结尾的文件
import os
for filename in os.listdir('./'):
if filename.endswith('.png'):
print(filename)
你现在在当前工作目录中有一个 PNG 图像文件列表。现在怎么办?嗯,现在你需要弄清楚这些图像中的哪些(如果有)已损坏。在本系列之前的文章中,我们专门使用了 Python 默认附带的模块。不幸的是,在没有任何图像处理能力的情况下发现图像是否损坏是很困难的,而且 Python 2 和 Python 3 都没有提供开箱即用的方法来处理这个问题。你需要获取一个图像处理模块来查看这些文件。令人高兴的是,Python 开发社区让这变得更容易了。
事实上,你可以安装整个软件包库。你只需要知道如何获取它们。让我向你介绍 pip,这是安装 Python 软件包的推荐工具。在大多数平台上安装 Python 时,它默认安装。
注意: 我正在使用 Python 3,但如果你正在使用 Python 2,那么我在本系列中编写的几乎所有内容都可以在这两种语言变体之间转移。此外,许多 Linux 发行版更喜欢你使用他们自己的软件包管理系统,而不是使用 pip 来安装 Python 软件包。如果你愿意,可以坚持使用它。此处建议使用 pip 主要是为了在你可以在其上使用 Python 的所有平台上保持一致性。
我要推荐你安装的特定软件包称为 Pillow。它是原始 PIL(Python 图像库)的“友好分支”,可在当前 Python 3 和 Python 2 版本中使用。你只需启动终端窗口并键入 pip install Pillow 即可安装 Pillow。Python 软件包工具应该会为你处理剩下的事情。
安装 Pillow 后,你实际上需要有一种在脚本中使用它的方法。由于它已安装,你可以像对待任何 Python 附带的模块一样对待它。你使用 import
——在这种情况下,你可以使用 import PIL
。但是,要查找损坏的图像,你实际上不需要将整个 Pillow 库导入到我们的脚本中。在 Python 中,你只能导入模块的单个子组件。这是一个好的做法,因为它减少了脚本的内存占用,而且同样重要的是,它更清楚地表明了你的脚本从一开始就要做什么。此外,当你导入子组件时,一旦你进入脚本的正文,你最终需要键入的内容就会更少。这总是一个不错的奖励。
要导入模块的子组件,请在你的 import
前面加上 from
指令。在 Pillow 的情况下,你的脚本实际上只需要使用 Image 类。因此,你的导入行看起来像 from PIL import Image
。事实上,你也可以对 os 模块执行相同的操作。如果你回顾一下之前的代码,你可能会注意到你只使用了 os 模块中的 listdir 函数。因此,你可以使用 from os import listdir
而不是 import os
。这意味着当你进入你的脚本时,你不再需要键入 os.listdir
。相反,你只需要键入 listdir
,因为这就是你导入的所有内容。
将所有这些组合在一起,你的脚本现在应该看起来像这样
from os import listdir
from PIL import Image
for filename in listdir('./'):
if filename.endswith('.png'):
print(filename)
你已经加载了 Pillow 中的 Image 类,但你的脚本仍然没有对它做任何事情。现在是时候进入你的脚本的功能部分了。你将要做的是打开每个图像文件并检查它是否可读的脚本等效项。如果出现错误,那么你就找到了一个坏文件。为此,你将使用 try/except 块。简而言之,你的脚本将尝试运行一个打开文件的函数。如果该函数返回错误,也称为异常,那么你就知道该图像有问题。特别是,如果异常类型为 IOError 或 SyntaxError,那么你就知道你有一个坏图像。
执行 try/except 的语法非常简单。我在下面的代码注释中描述了它
try: # These next functions may produce an exception
# <some function>
except (IOError, SyntaxError) as e: # These are the exceptions we're looking for
# <do something... like print an intelligent error message>
在查找损坏的图像文件的情况下,你将需要测试两个函数:Image.open()
和 verify()
。如果你将它们包装在 try/except 块中,那么你的损坏图像查找脚本应该如下所示
from os import listdir
from PIL import Image
for filename in listdir('./'):
if filename.endswith('.png'):
try:
img = Image.open('./'+filename) # open the image file
img.verify() # verify that it is, in fact an image
except (IOError, SyntaxError) as e:
print('Bad file:', filename) # print out the names of corrupt files
就是这样。将此脚本保存在你的图像目录中。当你从命令行运行它时,你应该获得其中所有损坏图像文件的列表。如果没有任何内容打印出来,那么你可以假设所有这些图像文件都是好的、有效的图像。
当然,能够在任何任意目录上使用此脚本会很好。并且让脚本提示你指示它继续并为你删除那些损坏的文件会更好。好消息!你可以让脚本完全做到这一点。我们将在本系列的下一篇文章中介绍这一点。
与此同时,祝你愉快地在你图像文件夹中找出损坏的文件。
7 条评论