首页Python【Python计算生态】I...

【Python计算生态】Imageio——读写各种图像数据

Python受欢迎的原因之一就是其计算生态丰富,据不完全统计,Python 目前为止有约13万+的第三方库。

本系列将会陆续整理分享一些有趣、有用的第三方库。

文章配套代码获取有以下两种途径:
  • 通过百度网盘获取:
链接:https://pan.baidu.com/s/1FSGLd7aI_UQlCQuovVHc_Q?pwd=mnsj 提取码:mnsj
  • 前往GitHub获取
https://github.com/returu/Python_Ecosystem





01
简介

imageio 是一个功能强大的 Python 第三方库,主要用于读写各种图像数据,它提供了简单易用的接口,支持多种常见的图像和视频格式,包括 PNG、JPEG、BMP、TIFF、GIF 等图像格式,以及 MP4、AVI 等视频格式。
直接使用pip安装:
pip install imageio
Imageio 依赖于 Numpy 和 Pillow。对于某些格式,imageio 还需要额外的库:
  • imageio-ffmpeg(用于处理视频文件);
  • pyav(用于处理视频文件);
  • tifffile(用于处理 TIFF 文件);
  • itk 或 SimpleITK(用于 ITK 插件);
  • astropy(用于 FITS 插件);
  • imageio-flif(用于处理 FLIF 图像文件)。
GitHub页面:
https://github.com/imageio/imageio

02
使用

Imageio 的核心 API主要为以下几个函数:


imread()  # 用于读取
imwrite() # 用于写入
imiter()  # 用于迭代图像序列(动画/视频/OME-TIFF/...)
improps() # 用于获取标准化的元数据
immeta()  # 用于获取特定于格式的元数据
imopen()  # 用于高级用法

以下是一些Imageio 使用示例:

  • 1、读取元数据:

ImageIO 区分两种类型的元数据:特定于格式的元数据和标准化的元数据。

特定于格式的元数据以 Python 字典的形式出现,旨在暴露图像中包含的所有元数据:


import imageio.v3 as iio

metadata = iio.immeta("./data/example.jpg")
print(metadata)  
# 输出:{'jfif': 257, 'jfif_version': (1, 1), 'dpi': (96, 96), 'jfif_unit': 1, 'jfif_density': (96, 96), 'mode': 'RGB', 'shape': (478, 299)}
print(metadata["mode"])
# 输出:"RGB"

另一方面,标准化的元数据以 ImageProperties 数据类的形式出现,旨在以标准化的名称和格式独立于底层容器或插件,暴露一组精选的元数据:


import imageio.v3 as iio

props = iio.improps("./data/example.jpg")
print(props)
# 输出:ImageProperties(shape=(299, 478, 3), dtype=dtype('uint8'), n_images=None, is_batch=False, spacing=None)
print(props.shape)
# 输出:(300, 451, 3)


  • 2、处理图像:

使用 imageio.imread 函数读取图像,该函数返回一个包含图像数据的 NumPy 数组。
使用 imageio.imwrite 函数写入图像,需要提供文件名和包含图像数据的 NumPy 数组。
可以使用 Matplotlib 来显示图像。

import imageio.v3 as iio

image = iio.imread('./data/example.jpg')  # 读取图像

print(type(image))
# 输出:<class 'numpy.ndarray'>

print(image.shape)
# 输出:(299, 478, 3)

# 写入图像,并转换为 PNG 格式
iio.imwrite('./data/example.png', image)

# 结合 matplotlib 显示图像
import matplotlib.pyplot as plt
plt.imshow(image)
plt.axis('off')  # 隐藏坐标轴
plt.show()

如果图像是 GIF 格式,需要设置index 参数用于指定要读取的帧的索引。当 index 设置为 None 时,意味着读取 GIF 动画的所有帧。如果指定一个具体的整数索引,比如 index = 2,则只会读取 GIF 动画中的第 3 帧(索引从 0 开始计数):


import imageio.v3 as iio

# index=None 表示:读取文件中的所有图像,并沿第一轴堆叠
frames = iio.imread("./data/example.gif", index=None)
# ndarray 的形状为 
print(frames.shape)  # (num_frames, height, width, channel)
# 输出:(38, 230, 434, 3)
另外,Imageio 还可以从高级来源读取数据:
从文件名、文件对象中读取数据;
读取文件夹中的所有图像;
从剪贴板或屏幕抓取图像;
从网络摄像头抓取帧,需要安装 ffmpeg 后端。
  • 3、处理视频:

读取或迭代视频中的帧(需要安装 pyav 后端)。

可以通过设置index参数读取单个帧:


import imageio.v3 as iio
import matplotlib.pyplot as plt

# 打开视频文件,读取单个帧(第一帧)
first_frame = iio.imread("./data/example.mp4",index=0)
# 形状
print(first_frame.shape) 
# 输出:(480, 480, 3)

# 显示第一帧
plt.imshow(first_frame)
plt.axis('off')
plt.show()

也可以批量读取所有帧,需要注意的是,如果视频过大会占用大量内存:


# 批量读取所有帧
# 警告:大视频会占用大量内存(RAM)
frames = iio.imread("./data/example.mp4")
print(frames.shape)

为了避免批量读取占用大量内存,可以使用imiter()方法来迭代大视频:


# 迭代大视频
for frame in iio.imiter("./data/example.mp4"):
    print(frame.shape, frame.dtype) # 输出每一帧的形状和类型
# 输出:(480, 480, 3) uint8
#      (480, 480, 3) uint8
#      (480, 480, 3) uint8
#      ......

以下是一些处理视频的示例代码:

  • 读取视频的每一帧,并将它们保存到本地:


import imageio.v3 as iio
import os

# 视频文件路径
video_path = "./data/example.mp4"

# 保存帧的文件夹路径
output_folder = "./data/frames"

# 迭代视频的每一帧
for i, frame in enumerate(iio.imiter(video_path, plugin="pyav")):
    # 生成每一帧的保存文件名,例如 frame_0001.jpg
    frame_filename = os.path.join(output_folder, f"frame_{i:04d}.jpg")
    # 保存当前帧
    iio.imwrite(frame_filename, frame)
    print(f"保存帧 {i} 到 {frame_filename}")


  • 将短片转换为灰度视频(需要安装 ffmpeg 后端)


import imageio.v3 as iio
import numpy as np

# 读取视频(它会加载到内存中)
# 注意:会打开两次图像。
metadata = iio.immeta("./data/example.mp4")
frames = iio.imread("./data/example.mp4", index=None)

# 手动将视频转换为灰度
gray_frames = np.dot(frames, [0.2989, 0.5870, 0.1140])
gray_frames = np.round(gray_frames).astype(np.uint8)
gray_frames_as_rgb = np.stack([gray_frames] * 3, axis=-1)

# 写入视频
iio.imwrite("./data/example_gray.mp4", gray_frames_as_rgb, fps=metadata["fps"])


  • 读取本地文件夹中的所有图片,并将它们写入一个视频文件中:


# 导入 imageio 库的 v2 版本,用于读取图像和创建视频写入器
import imageio.v2 as iio
import os

# 定义图片文件夹路径
image_folder = './data/imgs'

# 获取文件夹中所有图片文件的路径
# 所有图像必须具有相同的大小
image_files = [os.path.join(image_folder, f) for f in os.listdir(image_folder)][:3]


output_video = './data/imgs/output_video.mp4'
# 使用 iio.get_writer 创建一个视频写入器对象
w = iio.get_writer(output_video, 
                   format='FFMPEG',  # 指定使用 FFMPEG 作为视频编码的后端
                   mode='I',  # 表示只写入关键帧
                   fps=1, # 设置视频的帧率为 1 帧每秒,即每秒显示一张图片
                   codec='h264'# 指定使用 H.264 视频编码格式,这是一种广泛使用的高效编码标准
                   output_params=['-pix_fmt''yuv420p'], # 传递给 FFMPEG 的额外参数,指定像素格式为 yuv420p
                   pixelformat='yuv420p'# 指定视频的像素格式为 yuv420p

# 将图片写入视频
for image_file in image_files:
    try:
        # 使用 iio.imread 函数读取当前图片文件,将其转换为图像数据
        img = iio.imread(image_file)
        # 使用视频写入器的 append_data 方法将读取的图像数据添加到视频中
        w.append_data(img)
    except Exception as e:
        print(f"处理 {image_file} 时出现错误: {e}")

# 关闭视频写入器
w.close()

print(f"视频已保存为 {output_video}")


更多内容可以前往官方文档查看:

https://imageio.readthedocs.io/en/stable/

本篇文章来源于微信公众号: 码农设计师

RELATED ARTICLES

欢迎留下您的宝贵建议

Please enter your comment!
Please enter your name here

- Advertisment -

Most Popular

Recent Comments