>>> from env_helper import info; info()
页面更新时间: 2022-04-13 22:21:30
运行环境:
    Linux发行版本: Debian GNU/Linux 11 (bullseye)
    操作系统内核: Linux-5.10.0-13-amd64-x86_64-with-glibc2.31
    Python版本: 3.9.2

1.6. python数字图像处理(6):图像的批量处理

有些时候,我们不仅要对一张图片进行处理,可能还会对一批图片处理。这时候,我们可以通过循环来执行处理,也可以调用程序自带的图片集合来处理。

图片集合函数为:

skimage.io.ImageCollection(load_pattern,load_func=None)

这个函数是放在io模块内的,带两个参数,第一个参数load_pattern, 表示图片组的路径,可以是一个str字符串。第二个参数load_func是一个回调函数,我们对图片进行批量处理就可以通过这个回调函数实现。回调函数默认为imread(),即默认这个函数是批量读取图片。

先看一个例子:

>>> import skimage.io as io
>>> from skimage import data_dir
>>> str=data_dir + '/*.png'
>>> coll = io.ImageCollection(str)
>>> print(len(coll))
30

显示结果为 30 , 说明系统自带了 30 张 PNG 的示例图片, 这些图片都读取了出来,放在图片集合coll里。 如果我们想显示其中一张图片,则可以使用索引:

>>> io.imshow(coll[10])
<matplotlib.image.AxesImage at 0x7fd6b4264af0>
_images/sec06_batch_4_1.png

如果一个文件夹里,我们既存放了一些jpg格式的图片,又存放了一些png格式的图片,现在想把它们全部读取出来,该怎么做呢?

>>> import skimage.io as io
>>> from skimage import data_dir
>>> str=data_dir+'/*.jpg:'+data_dir+'/*.png'
>>> coll = io.ImageCollection(str)
>>> print(len(coll))
33

注意这个地方 data_dir+'/*.jpg:'+data_dir+'/*.png' ,是两个字符串合在一起的。 第一个是 data_dir+'/*.jpg:' , 第二个是 data_dir+'/*.png' 。 合在一起后,中间用冒号来隔开,这样就可以把文件夹下的jpg和png格式的图片都读取出来。 如果还想读取存放在其它地方的图片,也可以一并加进去,只是中间同样用冒号来隔开。

io.ImageCollection() 这个函数省略第二个参数,就是批量读取。 如果我们不是想批量读取,而是其它批量操作,如批量转换为灰度图,那又该怎么做呢?

那就需要先定义一个函数,然后将这个函数作为第二个参数,如:

>>> from skimage import data_dir,io,color
>>>
>>> def convert_gray(f):
>>>     rgb=io.imread(f)
>>>     return color.rgb2gray(rgb)
>>>
>>> str=data_dir+'/*.png'
>>> coll = io.ImageCollection(str,load_func=convert_gray)
>>> io.imshow(coll[10])
<ipython-input-38-a8e6ce5584f0>:5: FutureWarning: The behavior of rgb2gray will change in scikit-image 0.19. Currently, rgb2gray allows 2D grayscale image to be passed as inputs and leaves them unmodified as outputs. Starting from version 0.19, 2D arrays will be treated as 1D images with 3 channels.
  return color.rgb2gray(rgb)
<matplotlib.image.AxesImage at 0x7fd6b41ca4c0>
_images/sec06_batch_8_2.png

1.6.1. 读取视频文件

这种批量操作对视频处理是极其有用的,因为视频就是一系列的图片组合。

首先使用 iamgeio 模块来读取磁盘中的视频文件:

>>> import imageio
>>> vid = imageio.get_reader('vtest.avi',  'ffmpeg')
>>> type(vid)
imageio.plugins.ffmpeg.FfmpegFormat.Reader

下面看一下用 skimage 来读取:

>>> def vidread_step(f, step):
>>>     vid = imageio.get_reader(f)
>>>     seq = [v for v in vid.iter_data()]
>>>     return seq[::step]
>>>
>>> ic = io.ImageCollection('vtest.avi', load_func=vidread_step, step=30)[0]

这段代码的意思,就是将这个视频中每隔 30 帧的图片读取出来,放在图片集合中。

>>> import matplotlib.pyplot as plt
>>> plt.imshow(ic[0])
<matplotlib.image.AxesImage at 0x7fd6b419ac40>
_images/sec06_batch_14_1.png
>>> plt.imshow(ic[20])
<matplotlib.image.AxesImage at 0x7fd6b4103190>
_images/sec06_batch_15_1.png

得到图片集合以后,我们还可以将这些图片连接起来,构成一个维度更高的数组,连接图片的函数为:

>>> joined = io.concatenate_images(ic)

带一个参数,就是以上的图片集合,如:

>>> from skimage import data_dir,io,color
>>>
>>> coll = io.ImageCollection('*.png')
>>> # mat=io.concatenate_images(coll)

使用 concatenate_images() 函数的前提是读取的这些图片尺寸必须一致,否则会出错。

我们看看图片连接前后的维度变化:

>>> print(len(ic))      #连接的图片数量
>>> print(ic[0].shape)   #连接前的图片尺寸,所有的都一样
>>>
>>>
>>> mat=io.concatenate_images(joined)
>>> print(mat.shape)  #连接后的数组尺寸
27
(576, 768, 3)
(27, 576, 768, 3)

可以看到,将2个3维数组,连接成了一个4维数组

如果我们对图片进行批量操作后,想把操作后的结果保存起来,也是可以办到的。

例:把系统自带的所有png示例图片,全部转换成256*256的jpg格式灰度图,并进行保存:

改变图片的大小,我们可以使用 tranform 模块的 resize() 函数。

>>> from skimage import data_dir,io,transform,color
>>> import numpy as np
>>>
>>> def convert_gray(f):
>>>     rgb=io.imread(f)    #依次读取rgb图片
>>>     gray=color.rgb2gray(rgb)   #将rgb图片转换成灰度图
>>>     dst=transform.resize(gray,(256,256))  #将灰度图片大小转换为256*256
>>>     return dst
>>>
>>> str='*.png'
>>> coll = io.ImageCollection(str,load_func=convert_gray)
>>> for i in range(len(coll)):
>>>     io.imsave( 'xx_' + np.str(i)+'.jpg',coll[i])  #循环保存图片
WARNING:root:Lossy conversion from float64 to uint8. Range [0, 1]. Convert image to uint8 prior to saving to suppress this warning.
<ipython-input-46-1ef0039276b4>:6: FutureWarning: Non RGB image conversion is now deprecated. For RGBA images, please use rgb2gray(rgba2rgb(rgb)) instead. In version 0.19, a ValueError will be raised if input image last dimension length is not 3.
  gray=color.rgb2gray(rgb)   #将rgb图片转换成灰度图
WARNING:root:Lossy conversion from float64 to uint8. Range [0, 1]. Convert image to uint8 prior to saving to suppress this warning.
WARNING:root:Lossy conversion from float64 to uint8. Range [0, 1]. Convert image to uint8 prior to saving to suppress this warning.
WARNING:root:Lossy conversion from float64 to uint8. Range [0, 1]. Convert image to uint8 prior to saving to suppress this warning.
WARNING:root:Lossy conversion from float64 to uint8. Range [0, 1]. Convert image to uint8 prior to saving to suppress this warning.

同样的方式,我们把开始读取的视频文件保留成单独的图片:

>>> coll = io.ImageCollection('vtest.avi', load_func=vidread_step, step=30)[0]
>>> for i in range(len(coll)):
>>>     io.imsave( 'xx_' + np.str(i)+'.jpg',coll[i])  #循环保存图片