文章目录[隐藏]
OpenCV (CV2) 与 Pillow 图像读取机制的比较分析
1. 引言:OpenCV (CV2) 与 Pillow 图像读取机制比较分析
1.1. 背景:图像加载的普遍性任务
在计算机视觉和图像处理流程中,图像加载是基础且至关重要的一步。Python 在这些领域的广泛应用,使得 OpenCV 和 Pillow 等库成为开发者常用的工具。
1.2. OpenCV 与 Pillow 概述
- OpenCV (cv2): OpenCV (Open Source Computer Vision Library) 是一个功能全面的开源库,主要致力于计算机视觉、机器学习和实时图像处理 1。它最初由英特尔公司开发,并逐渐发展成为一个功能强大的多用途工具 1。OpenCV 在处理复杂算法和性能密集型应用方面表现出色 2。
- Pillow (PIL Fork): Pillow 是 Python Imaging Library (PIL) 的一个活跃分支,它是一个强大的通用图像处理库,擅长打开、操作和保存多种图像文件格式 1。它更适合于相对简单、轻量级的图像处理任务 2。
1.3. 核心问题:性能差异的探讨
用户观察到在 Python 中使用 cv2.imread() 读取图像时,其速度感知上慢于 Pillow.Image.open()。本报告旨在深入剖析这两种函数在图像读取方面的底层机制,解释其性能差异,并提供一个细致的理解。开发者不仅仅关心速度本身,更深层次的需求在于理解在何种情况下、为何选择其中一个库进行图像输入,而不仅仅是基于初始文件打开操作的快慢。这种对“底层逻辑”的探究,暗示了开发者可能正在为其图像处理流程进行架构决策,需要了解不同选择对后续操作的全部影响。
1.4. 报告范围
本报告将涵盖 cv2.imread() 和 Image.open() 的内部逻辑、它们的数据处理策略(包括 Pillow 的延迟加载机制)、色彩空间约定,并对性能基准测试进行严格审视。
2. OpenCV 的方法:cv2.imread() - 即时数据访问与 NumPy 集成
2.1. cv2.imread() 的核心功能
cv2.imread() 函数从指定的文件路径加载图像,并将其作为 NumPy 数组返回 4。这种直接转换为 NumPy 数组的特性是其关键特征之一,使得图像数据能够立即用于图像处理和机器学习中常见的数值运算 6。如果由于文件丢失、权限不当或格式不受支持/无效而无法读取图像,该函数将返回一个空矩阵(在 Python 中为 None,对应 C++ 中的 cv::Mat::empty() 检测) 5。
2.2. C++ 核心:cv::Mat 与性能优化
OpenCV 的核心是用 C++ 编写的,并提供了 Python 绑定 4。Python 中的 cv2.imread() 函数实际上是 C++ cv::imread 函数的一个封装 4。在 C++ 中,imread 返回一个 cv::Mat 对象,这是 OpenCV 用于存储图像和其他矩阵数据的基本数据结构 4。随后,这个 cv::Mat 对象被转换为 NumPy 数组,以便在 Python 中使用 4。这种 C++ 基础通常面向高性能,利用了优化的底层操作 2。
2.3. 数据加载策略:即时加载 (Eager Loading)
cv2.imread() 执行的是“即时加载”策略:在调用该函数时,整个图像数据(像素)会从文件中读取并解码到内存中(以 NumPy 数组的形式)4。这意味着一旦 cv2.imread() 完成,完整的图像数据就可以立即用于处理。然而,对于大文件,初始调用可能会花费更长时间,因为它涉及完整的解码过程。
2.4. 颜色通道顺序:BGR 约定
OpenCV 默认以 BGR(蓝、绿、红)顺序读取图像 1。这与许多其他图像库(如 Pillow、Matplotlib)使用的 RGB(红、绿、蓝)顺序有显著不同 1。
这种约定是 OpenCV 早期开发时选择的,可能是因为当时 BGR 格式在相机制造商和软件供应商中较为流行(例如,Windows 中的 COLORREF 值使用 0x00bbggrr 格式)11。一些资料表明,这与早期 VGA 显示控制器中使用的 INMOS 171/176 RAMDAC 芯片有关 12。CPU 的小端字节序也可能在 BGR (0xbbggrr) 的存储和读取方式中发挥了作用 11。
这一特性带来的实际影响是,如果使用期望 RGB 格式的工具显示或处理 BGR 图像,颜色会出现交换(例如,红色和蓝色颠倒)。因此,通常需要使用 cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 进行转换 1。
2.5. 加载标志:控制图像解释
cv2.imread(filename, flags) 函数接受一个可选的 flags 参数,用于控制图像的加载方式 4。关键的标志包括 4:
- cv2.IMREAD_COLOR (或 1):加载彩色图像,忽略透明度。这是默认设置。结果是一个 3 通道 BGR 图像。
- cv2.IMREAD_GRAYSCALE (或 0):以灰度模式加载图像。结果是一个单通道图像。
- cv2.IMREAD_UNCHANGED (或 -1):按原样加载图像,包括 alpha(透明度)通道(如果存在)。结果可能是一个 4 通道 BGRA 图像。
cv2.imread() 的设计(即时加载、直接 NumPy 转换、C++ 后端)优先考虑了计算机视觉中典型的高强度计算下游任务的准备就绪状态。初始加载时间是为了获得即时、优化的数据访问而预付的成本。OpenCV 的起源在于要求苛刻的计算机视觉应用。对于实时对象检测或视频分析等任务 1,将数据完全加载并以 CPU 高效的格式(NumPy 数组,它与 C 数组良好映射)存储是至关重要的。BGR 约定虽然是一个历史遗留问题,但在处理后并不会妨碍这些核心功能。这些标志位为不同的输入需求提供了必要的灵活性,而不会改变基本的即时加载策略。这与那些可能优先考虑快速打开文件(例如用于网页显示或简单编目,其中不需要立即获得完整的像素数据)的库形成了鲜明对比。
3. Pillow 的方法:Image.open() - 通过延迟加载实现灵活性
3.1. Image.open() 的核心功能
Image.open(fp, mode='r') 函数用于打开并识别给定的图像文件,但它并不会立即加载实际的光栅数据 3。该函数接受一个文件名(字符串)、pathlib.Path 对象或一个文件对象作为参数 14。文件对象必须实现 read()、seek() 和 tell() 方法,并以二进制模式打开 14。调用后,它返回一个 Image 对象 3。
3.2. “延迟加载”机制:元数据和部分访问的效率
延迟加载是 Pillow Image.open() 的核心特性 3。
- 机制解释: 当调用 Image.open() 时,Pillow 会:
- 打开文件。
- 读取文件头以识别图像格式、尺寸(维度)、颜色模式(例如 "RGB", "L")和其他元数据 3。
- 它不会将大量的像素数据读入内存 3。文件保持打开状态 14。
- 数据何时实际加载?
- 实际的图像数据仅在被明确请求时才从文件中读取 14。这通常发生在:
- 调用 Image.load() 方法时 3。此方法会读取图像数据,如果文件是由 Pillow 打开的,则会关闭文件。
- 直接访问像素数据或尝试处理图像时(例如,Image.show()、Image.save()、转换为 NumPy 数组、Image.resize() 等)3。
- 优势 3:
- 快速访问元数据: 由于只读取文件的一小部分,获取图像属性非常迅速。
- 内存效率高: 节省内存,尤其是在处理大量大图像或仅需要元数据或图像小部分区域时。
3.3. Image 对象:结构与数据处理
Image.open() 返回的 Image 对象包含元数据以及一个在需要时加载像素数据的指针或机制 15。它具有 format、size、mode 等属性 6。像素数据一旦加载,通常以 Pillow 可以操作的方式内部存储。对于绘图操作,坐标系以左上角为 (0,0) 17。
3.4. 颜色通道顺序:RGB 标准
Pillow 通常以 RGB(红、绿、蓝)顺序处理彩色图像 1。这与网页图形和许多其他成像工具中的常见约定一致。
3.5. 确保适当的资源管理
建议在 with 语句中使用 Image.open()(例如 with Image.open(...) as img:),以确保即使发生错误,图像文件也能被正确关闭 3。或者,可以显式调用 img.close(),尤其是在调用 img.load() 之后,如果需要手动管理文件 3。
Pillow 的延迟加载是一种设计选择,它有利于那些不需要立即进行完整像素操作的任务的灵活性和效率,例如批量处理图像元数据、快速预览或条件加载。如果一个程序需要快速扫描数千张图片以按大小或格式对其进行分类,那么为每张图片加载完整的像素数据将非常低效。Pillow 的方法允许这种快速的元数据提取。加载像素数据的“成本”被推迟到实际需要时才发生。这使得 Pillow 非常适合 Web 应用、脚本编写和基本的图像组织任务 2。
延迟加载机制如果未被正确理解,可能会在性能基准测试中导致“陷阱”。如果基准测试没有强制 Pillow 加载像素数据,那么对 Image.open() 进行简单的 timeit 测试将比 cv2.imread() 快得令人误解。这解释了用户最初的感知,并强调了“同类比较”的重要性。正如在 10(以及 10)中所见,一个直接比较 Image.open() 和 cv2.imdecode()(对于内存中的缓冲区,这类似于 cv2.imread())的基准测试显示 Pillow 快了几个数量级。然而,解释澄清了这是因为 Image.open() 尚未完成像素解码的“繁重工作”。一个公平的比较需要像 np.array(img_pillow) 这样的操作来强制加载数据。
4. 性能深入探讨:解析速度差异
4.1. 用户观察的核心:延迟加载 vs. 即时加载
Pillow 的 Image.open() 在初始计时中显得比 cv2.imread() 快得多的主要原因是其延迟加载策略 3。
- Image.open():最小化 I/O 操作,仅读取文件头。初始返回速度快。
- cv2.imread():完整的 I/O 操作,读取并解码所有像素数据。初始返回速度较慢,但数据已准备就绪。
4.2. 基准测试:力求“同类比较”
直接比较 Image.open() 和 cv2.imread() 的计时,而不强制 Pillow 加载像素数据,并不能公平地比较完整的图像读取能力 10。为了公平比较完整的读取性能,Pillow 需要加载数据,例如通过调用 img.load() 或将其转换为 NumPy 数组 (numpy.array(img_pil)) 10。
对现有基准测试片段的回顾揭示了复杂的情况:
- 21 (Kaggle - 读取、裁剪、调整大小): 在一个包含读取、裁剪和调整大小的组合任务中,PIL (11.5秒) 比 OpenCV (17.5秒) 更快。这表明即使在处理流程中,PIL 也能保持竞争力甚至更快。
- 9 (GitHub Gist - 多种操作):
- 加载图像:Pillow (3.758 毫秒) 明显快于 OpenCV (17.943 毫秒)。这很可能反映了 Pillow 在“加载”部分利用了延迟加载。
- 调整大小:OpenCV (5.656 毫秒) 比 Pillow (19.11 毫秒) 快。
- 保存图像:对于默认保存操作,OpenCV (37.732 毫秒) 比 Pillow (309.918 毫秒) 快得多。
- 13 & 13 (Kaggle - PyTorch DataLoader 上下文):
- Image.open() (1000个文件耗时 0.644秒) 比 cv2_imread() (1000个文件耗时 3.980秒) 快得多。关键在于,此基准测试中的 cv2_imread 函数包含了 cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 调用 13。此转换给 OpenCV 的计时增加了额外开销。
- 对于已加载图像的后续操作,如 resize 或 ToTensor,在这些代码片段中,OpenCV 通常表现出更好或相当的性能。
- 完整的 DataLoader 流程:OpenCV 有时略快(例如,一种设置下 cv2:4.036秒 vs pil:4.719秒;另一种设置下 cv2:4.303秒 vs pil:4.847秒)13。这表明当考虑整个操作链时,OpenCV 可能具有竞争力或更快。
- 20 (GitHub Issue - 保存 PNG vs. JPG):
- PNG 保存:OpenCV (50次试验耗时 6.24秒) 比 Pillow (26.21秒) 快得多。原因是 Pillow 默认的 PNG 压缩级别更高/更慢。在 Pillow 中调整 compress_level=1 使其速度几乎与 OpenCV 一样快。
- JPG 保存:Pillow (4.37秒) 比 OpenCV (8.17秒) 快。
- 10 (Stack Overflow - 从缓冲区加载): 初始的 Pillow Image.open(BytesIO(buf)) 耗时 0.1毫秒,而 OpenCV cv2.imdecode 耗时 30毫秒。回答正确地指出这是由于延迟加载,并建议使用 arr \= np.array(image, dtype=np.uint8) 进行公平的 Pillow 计时 10。
4.3. 影响加载和处理速度的因素
- 图像格式 (例如 JPEG vs. PNG):
- 解码复杂度不同。JPEG 是有损压缩,涉及离散余弦变换 (DCT);PNG 是无损压缩,使用 DEFLATE 算法。
- 如 20 所示,由于底层编解码器实现或默认参数(如压缩级别)的不同,库在不同格式间的性能(即使是保存操作)也可能存在显著差异。
- 图像分辨率/尺寸: 更大的图像自然需要更多时间来读取和解码完整的像素数据 18。如果仅需要元数据,延迟加载对于非常大的图像的优势会更加明显。19 讨论了以兆像素/秒为单位的调整大小性能,表明吞吐量是一个关键指标。
- 压缩级别: 对于像 PNG 这样的格式,保存时使用的压缩级别会影响文件大小,进而影响加载/保存时间 20。Pillow 的默认 PNG 压缩似乎更注重文件大小而非速度,但这是可配置的。
- 底层库: OpenCV 和 Pillow 都依赖其他库(例如 libjpeg, libpng, zlib)进行解码。这些后端库的效率至关重要。
- 硬件 (CPU, SIMD):
- OpenCV 通常受益于 CPU 优化,并且可以编译以支持 SIMD 指令。
- Pillow-SIMD: 这是一个启用了 SIMD 指令(SSE4, AVX2)的 Pillow 版本,可以显著加速诸如调整大小、模糊和颜色转换等操作,使其在这些方面比标准 Pillow 快得多,并能与 OpenCV 竞争 19。重采样速度可以比原始 PIL 快 12-35 倍。
- 颜色转换开销: 如果应用程序持续需要 RGB 图像,使用 cv2.imread() 通常需要额外的 cv2.cvtColor() 步骤,这会增加其有效处理时间(如果 BGR 到 RGB 的转换未包含在基准测试中,如 13 中的情况)。
4.4. 内存使用考量
- OpenCV (cv2.imread()): 将整个图像加载到 NumPy 数组中,因此调用后内存使用量与图像大小和位深度成正比。
- Pillow (Image.open()): 最初仅使用非常少的内存(用于元数据)。仅当调用 load() 或访问像素数据时,内存使用量才会增加。如果管理不当(例如,加载许多大图像而不释放),仍可能导致高内存消耗。
- 9 提供了一个表格,比较了使用 Images.jl、Pillow 和 OpenCV 应用高斯模糊时的内存估计。对于特定的高斯模糊任务,内存估计为 18.44 MiB 9。然而,9 的表格本身侧重于时间,而不是加载的内存。关于内存的 9 片段可能来自 BenchmarkTools.Trial 输出中未完全捕获的不同部分。所提供的片段中并未以比较的方式明确详述仅加载操作的直接内存使用比较,超出了即时加载与延迟加载的逻辑含义。
性能不是一个单一的概念。它取决于具体操作(初始打开、完全加载、后续处理、保存)和图像特性(格式、大小、压缩)。没有哪个库是普遍“更快”的。基准测试 9 显示了复杂的情况。由于延迟加载,Pillow 在快速打开方面表现出色。对于某些处理任务,或者当其 C++ 后端提供优势时(尤其是在数据已经是 NumPy 格式的情况下),OpenCV 可能更快。文件格式的选择(JPG vs PNG)甚至可以改变哪个库在 I/O 密集型操作(如保存)中更快 20。这意味着用户必须针对其特定流程进行基准测试才能做出最佳选择。
“生态系统”和后续操作严重影响初始图像读取的感知性能和实际性能。如果下一步是繁重的 OpenCV 特定算法,使用 cv2.imread() 读取可以避免 Pillow 到 NumPy 的转换成本。如果流程涉及 PyTorch 13、DataLoader 上下文以及来自 albumentations(通常由 OpenCV 支持)或 torchvision.transforms(通常由 Pillow 支持)的转换,则相互作用变得复杂。13/13 的基准测试表明,即使 Image.open 最初更快,当与 albumentations 结合使用时,完整的 DataLoader 循环也可能有利于 OpenCV 路径。这突出表明,应在整个工作流程的背景下考虑图像读取的“成本”。
下表旨在通过将性能分解为更细致、依赖于上下文的阶段,来直接解决用户关于“CV2 慢,Pillow 快”的观察。它将直观地展示为什么存在最初的感知(延迟加载),以及当考虑完整数据访问或特定的后续操作时情况如何变化。它将零散的基准数据综合成一个更连贯的叙述,强调没有一个库在整体上是“更快”的。
表 1:图像读取与处理性能细化比较
任务 | OpenCV (cv2.imread / cv2.imdecode) | Pillow (Image.open / Image.open + load()) | 关键影响因素 | 参考片段 |
---|---|---|---|---|
初始文件打开 (仅元数据访问) | 较慢 (执行完整解码) | 非常快 (延迟加载,仅读取头部) | 加载策略 (即时 vs. 延迟) | 10 |
完整图像加载到 NumPy 数组 (CV2: BGR, Pillow: RGB) | 初始调用完成所有工作 | Image.open + numpy.array(img) 或 img.load();第二步产生主要耗时 | 延迟加载的实际数据读取时机 | 10 |
加载 + BGR 到 RGB 转换 (针对 CV2) | cv2.imread + cv2.cvtColor (增加额外耗时) | Pillow 本身为 RGB | OpenCV 的 BGR 默认值;颜色转换的计算开销 | 13 |
调整大小 (Resize) | 通常较快,尤其对于已加载的 NumPy 数组 | 性能依赖 Pillow-SIMD;标准 Pillow 可能较慢 | 底层实现,SIMD 优化 | 9 |
保存 PNG | 默认较快 | 默认较慢 (高压缩级别);调整 compress_level 可提速 | 默认压缩参数,PNG 编码库效率 | 20 |
保存 JPG | 可能较慢 | 可能较快 | JPG 编码库效率 | 20 |
完整数据加载与处理流程 (例如 PyTorch DataLoader) | 初始加载慢,但后续结合 albumentations 可能整体更快 | 初始加载快,但后续结合 torchvision.transforms 可能因转换等因素导致整体速度差异不大或稍慢 | 整个流程中各环节的开销,库之间的兼容性和转换成本 | 13 |
5. 总结差异:cv2.imread() vs. Image.open()
5.1. 核心理念与设计
- OpenCV: 专为全面的计算机视觉和性能关键型任务而设计,通常涉及实时处理。优先考虑数据在计算高效格式(直接来自 C++ cv::Mat 的 NumPy 数组)中的即时可用性 1。
- Pillow: 一个通用的图像处理库,专注于易用性,支持多种格式和常见的图像编辑任务。采用延迟加载以提高在不需要立即获取完整像素数据的情况下的效率 1。
5.2. 关键区别表
下表提供了一个关于 cv2.imread() 和 Image.open() 最关键区别的快速并排参考。
表 2:cv2.imread() 与 Image.open() 关键特性对比
特性 | cv2.imread() (OpenCV) | Image.open() (Pillow) |
---|---|---|
主要用例 | 复杂计算机视觉、机器学习、实时处理 1 | 通用图像处理、格式转换、基本编辑 1 |
数据加载策略 | 即时加载 (Eager Loading) 4 | 延迟加载 (Lazy Loading) 3 |
输出数据类型 | NumPy 数组 4 | Pillow Image 对象 3 |
默认颜色顺序 | BGR (蓝绿红) 1 | RGB (红绿蓝) 6 |
后端实现 | C++ 核心,Python 绑定 4 | 主要是 Python 实现,依赖底层 C 库进行编解码 |
初始调用速度 (感知) | 较慢 | 非常快 |
调用后数据可用性 | 完整像素数据立即可用 | 仅元数据可用;像素数据需额外操作加载 |
初始内存使用 | 较高 (整个图像加载入内存) | 非常低 (仅元数据) |
仅元数据访问的灵活性 | 不直接支持 (总是加载完整图像) | 非常高 |
典型下游操作 | OpenCV 函数、NumPy 数值计算 | Pillow API 操作、Web 显示、简单脚本 |
5.3. 何时选择其一
OpenCV 和 Pillow 之间的选择本质上是在“预处理成本以换取即时数据就绪性”(OpenCV)与“延迟处理成本以换取初始速度和灵活性”(Pillow)之间的权衡。OpenCV 立即承担完整解码的性能开销,使其核心用户(计算机视觉算法)能够以高度优化的格式(NumPy 数组)即时获得数据。Pillow 则推迟了这一开销,如果永远不需要完整数据,或者如果正在为元数据扫描许多文件,这将是有利的。这不仅仅关乎“速度”,更关乎计算工作何时完成。
6. 结论与实践建议
6.1. 解释用户体验:“为什么”的再探讨
用户的观察——Pillow 读取图像“更快”——极有可能是由于 Pillow 的延迟加载机制。Image.open() 主要快速读取元数据,而 cv2.imread() 则执行完整的、即时的像素数据解码。
6.2. 图像输入的策略性库选择
- 选择 cv2.imread() 的情况:
- 需要立即访问作为 NumPy 数组的完整像素数据。
- 主要的下游任务涉及 OpenCV 函数或其他 NumPy 密集型数值计算。
- 在性能关键的计算机视觉流程中工作,OpenCV 的 C++ 后端和优化操作具有优势,并且初始加载时间是可以接受的权衡。
- 从一开始就倾向于一致的数据表示(NumPy 数组)。
- 选择 Pillow.Image.open() 的情况:
- 需要为许多文件快速获取图像元数据(尺寸、格式、模式)。
- 内存效率至关重要,并且可以推迟或避免完整图像数据的加载。
- 处理多种图像格式,Pillow 广泛的格式支持具有优势。
- 简单的 API 足以满足基本的图像操作(调整大小、裁剪、旋转、格式转换)。
- 应用程序涉及诸如 Web 图像服务之类的任务,其中延迟加载可以提高响应能力。
6.3. Python 中优化图像加载和处理的技巧
- 公平的基准测试: 如果比较速度,请确保强制 Pillow 加载像素数据(例如,img.load() 或 numpy.array(img)),以便与 cv2.imread() 进行公平比较。
- 颜色转换意识: 考虑到 OpenCV 的 BGR 默认值;如果需要 RGB,请使用 cv2.cvtColor(),并在与 Pillow 比较时将其计入性能考量。
- Pillow-SIMD: 对于性能关键的 Pillow 操作,考虑使用 Pillow-SIMD 以获得显著的速度提升 19。
- 文件格式和参数: 注意图像格式(JPEG vs. PNG)及其参数(例如 Pillow 中 PNG 的 compress_level 20)如何影响 I/O 速度。
- 批量处理: 处理多个图像时,请考虑加载策略如何影响整体吞吐量。
- 为任务选择合适的工具: 利用 OpenCV 在复杂视觉任务中的优势,以及 Pillow 在通用图像处理和 I/O 灵活性方面的优势。有时,组合使用可能是最佳选择(例如,使用 Pillow 进行初始加载和格式处理,然后转换为 NumPy 以便进行 OpenCV 处理)。
6.4. 最终思考:理解引导优化
对这些库底层逻辑的理解,如本报告所探讨的,使开发者能够做出明智的选择,从而最好地满足其特定应用需求和性能目标。用于图像读取的“最佳”库是依赖于上下文的,并且通常涉及在初始响应性、内存占用、数据准备就绪性以及后续处理任务的性质之间进行权衡。一个经验丰富的开发者甚至可能在同一个应用程序中策略性地同时使用这两个库。例如,一个应用程序可能使用 Pillow 快速扫描包含混合图像类型的目录,提取元数据,并选择性地仅加载某些图像。然后,这些选定的图像可能会被转换为 NumPy 数组并传递给 OpenCV 进行密集分析。这种混合方法充分利用了两个库的优点。用户最初关于简单读取操作的查询,为这种关于图像处理流程的更广泛的战略性思考打开了大门。
引用的著作
- What is the difference between OpenCV and Pillow? - Educative.io, 访问时间为 六月 11, 2025, https://www.educative.io/blog/opencv-vs-pillow
- Image Processing — OpenCV Vs PIL | GeeksforGeeks, 访问时间为 六月 11, 2025, https://www.geeksforgeeks.org/image-processing-opencv-vs-pil/
- Image.open Python Function: Syntax and Quick Tutorial - Cloudinary, 访问时间为 六月 11, 2025, https://cloudinary.com/guides/web-performance/image-open-python-function-syntax-and-quick-tutorial
- Read, Display and Write an Image using OpenCV, 访问时间为 六月 11, 2025, https://opencv.org/blog/read-display-and-write-an-image-using-opencv/
- cv2.imread() method - Python OpenCV - GeeksforGeeks, 访问时间为 六月 11, 2025, https://www.geeksforgeeks.org/python-opencv-cv2-imread-method/
- Importing Image Data into NumPy Arrays - Pluralsight, 访问时间为 六月 11, 2025, https://www.pluralsight.com/resources/blog/guides/importing-image-data-into-numpy-arrays
- Getting Started with Images - OpenCV Documentation, 访问时间为 六月 11, 2025, https://docs.opencv.org/4.x/db/deb/tutorial_display_image.html
- Reading and Displaying an image in OpenCV using C++ - GeeksforGeeks, 访问时间为 六月 11, 2025, https://www.geeksforgeeks.org/reading-and-displaying-an-image-in-opencv-using-c/
- Benchmarks of JuliaImages compared to OpenCV and PIL (Pillow) on Python - GitHub Gist, 访问时间为 六月 11, 2025, https://gist.github.com/soumitradev/62bddefbb4b3c1ee5135a2fd83ee25dd
- python 3.x - Speeding up loading of images in OpenCV vs Pillow ..., 访问时间为 六月 11, 2025, https://stackoverflow.com/questions/64442902/speeding-up-loading-of-images-in-opencv-vs-pillow
- [Discussion] Why OpenCV reads the image with BGR and not in RGB? - Reddit, 访问时间为 六月 11, 2025, https://www.reddit.com/r/opencv/comments/1jad9bm/discussion_why_opencv_reads_the_image_with_bgr/
- Why OpenCV Using BGR Colour Space Instead of RGB - Stack ..., 访问时间为 六月 11, 2025, https://stackoverflow.com/questions/14556545/why-opencv-using-bgr-colour-space-instead-of-rgb
- OpenCV vs PIL - Speed Comparisons for Pytorch User - Kaggle, 访问时间为 六月 11, 2025, https://www.kaggle.com/code/yukia18/opencv-vs-pil-speed-comparisons-for-pytorch-user
- Python PIL | Image.open() method - GeeksforGeeks, 访问时间为 六月 11, 2025, https://www.geeksforgeeks.org/python-pil-image-open-method/
- Python Pillow - Working with Images - GeeksforGeeks, 访问时间为 六月 11, 2025, https://www.geeksforgeeks.org/python-pillow-working-with-images/
- Python PIL, Image. Error after image.load() - Stack Overflow, 访问时间为 六月 11, 2025, https://stackoverflow.com/questions/9211719/python-pil-image-error-after-image-load
- ImageDraw Module - Pillow (PIL Fork) 11.2.1 documentation, 访问时间为 六月 11, 2025, https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html
- Python Image Resize With Pillow and OpenCV - Cloudinary, 访问时间为 六月 11, 2025, https://cloudinary.com/guides/bulk-image-resize/python-image-resize-with-pillow-and-opencv
- Pillow Performance, 访问时间为 六月 11, 2025, https://python-pillow.github.io/pillow-perf/
- Saving PNG images with PIL is 4 times slower than saving them with ..., 访问时间为 六月 11, 2025, https://github.com/python-pillow/Pillow/issues/5986
- Fastest way to read and process images - Kaggle, 访问时间为 六月 11, 2025, https://www.kaggle.com/code/devashishprasad/fastest-way-to-read-and-process-images