Python环境Pillow( PIL )图像处理工具使用解析


Posted in Python onSeptember 12, 2019

前言

由于笔者近期的研究课题与图像后处理有关,需要通过图像处理工具对图像进行变换和处理,进而生成合适的训练图像数据。该系列文章即主要记录笔者在不同的环境下进行图像处理时常用的工具和库。在 Python 环境下,对图像的处理笔者主要使用 Pillow 库,主要操作包括对图像的读取、存储和变换等。实际应用中,Pillow 中提供的 Image 模块适合对图像整体进行变换处理操作。

注:以下介绍仅包括对应模块和函数的基础用法,故而在介绍时省略了部分参数和选项,更完备的用法和介绍可参考 Pillow 的官方文档。

安装

用户可通过 pip 直接安装 Pillow,更多安装方式可以参见这里。

pip install Pillow #安装 pillow

使用

在日常应用过程中,使用最多的是 Pillow 提供的 Image 模块,其提供了包括图像存储、变换以及一系列的相关处理功能。Pillow 使用 Image 对象来表示图像对象并基于其定义图像的属性信息以及可针对其进行的操作,后续即主要介绍通过 Image 对象可进行的图像操作。在 Python 中使用时,用户首先需从 PIL 中导入对应的 Image 模块。

from PIL import Image #通过 Image 进行图像处理相关的操作

图像读取与存储

通过 Image 提供的 open 方法读取图像,其以指定的文件名为参数,返回值为对应图像的 Image 对象,后续即可针对图像对应的 Image 对象进行操作。

im = Image.open( "test.png" )  # open 方法以图像名(或图像对象)为参数,返回一个 Image 对象

通过 Image 对象的 save 方法存储图像对象,其使用存储目标文件名为参数,也可通过 format 参数指定存储文件的格式。

im.save( "test.png" )          # im 为 Image 对象,其被保存至 test.png,不指定 format 参数时,该方法通过文件后缀推测文件类型
  im.save( "test.jpg" , format="JPEG")  # 以 JPEG 格式保存 Image 对象 im 至文件 test.jpg 中

基本属性

图像对应的 Image 对象具备基本属性。用户可以通过这些属性获得图像最基本的信息,Image 对象的完整属性信息可以查看这里。

im.filename    # Image 对象 im 对应的文件/路径名
  im.mode      # Image 对象图像数据的解释方式,如灰度图为 “L”,彩色图为 “RGB”等
  im.size      # 返回图像的尺寸信息,为( width , height ) 格式的元祖

图像类型转换

不同的图像数据具有不同的图像格式,进而拥有不同的组织数据的方式。对于 RGB 图像而言,图像拥有 R、G、B 三个通道,像素数据由三个对应三通道的 8 bit 数据组成;对于黑白图像而言,其每个像素由一个 8 bit 字节表示等等。在打开图像时,open 方法会自动解析图像的格式,用户可通过 Image 对象的 mode 属性获得图像的状态。

Image 对象可通过 convert 方法进行图像类型间的转换,其使用转换的目标类型的字符串为参数,返回转换后的 Image 对象,常见的类型包括 RGB(真彩)、L(黑白)、YCbCr(视频图像)、HSV(色调饱和度亮度彩色空间)。

data = im.convert( "L" )    #获得 RGB 图像 im 的灰度图

与 numpy 数组的转换

在程序中,一般使用图像对应的 Image 对象进行图像相关的操作,针对图像数据本身的计算处理一般将 Image 对象的数据转换为 numpy 数据后进行,处理完成之后的 numpy 数据再被转换为 Image 对象进行保存。

a. 将 Image 对象转换为 numpy 数组

使用 numpy.asarray 方法( 不唯一,可参见 Array creation routines )将 Image 对象的数据转换为 numpy 数组,进而可以对其进行计算处理。转换后 numpy 数组的数据类型根据 Image 数据对象本身的数据类型推断获得,使用时也可使用 numpy.asarray 的 dtype 参数指定转换后的数据类型。

im = Image.open( "test.png" )         #打开图像 test.png ,并获得其对应的 Image 对象
  data = numpy.asarray( im )           #将 Image 对象 im 的数据转换为 numpy 数组的形式,data 即为可供运算的 numpy 数组
  data = numpy.asarray( im, dtype=np.uint8 )   #转换图像数据为 numpy 数组,并指定其类型为 np.uint8

b.将 numpy 数组转换为 Image 对象

对于 numpy 数据形式的图像数据( 通过数据处理或其他途径获得 ),可通过 Image.fromarray 方法将已有的 numpy 图像数据转换为 Image 对象。

im = Image.fromarray( data ) # data 为 numpy 数组,im 为转换获得的 Image 对象

注意,在使用 Image.fromarray 方法时可能会出现报错 raise TypeError("Cannot handle this data type") , 这是由于待转换的 numpy 数据类型可能并不符合 Image 对象所需的数据类型( 一般为 8 bit 无符号值 ),解决方法是在转换前先将 numpy 数组的数据类型转换为 np.uint8 .

im = Image.fromarray( data.astype( np.uint8 ) )  #将 numpy 数组的数据类型转换为 np.uint8 后再转换为 Image 对象

常用操作

裁剪图像——crop

可以使用 crop 方法获得图像的指定部分。crop 方法以指定 ( 左,上,右,下 ) 切割位置的元祖来定义待分割的图像部分,可以理解为定义的是切割获得的矩形的左上角和右下角位置的坐标。在 PIL 所支持的坐标系统中,坐标的( 0 , 0 ) 为图像的左上角,注意 ( 0 , 0 ) 指向的不是左上角的第一个像素,而是该像素位置前的位置,后续所有的坐标均为像素间的空隙位置,而不是指向像素。也就是说,第一个像素被 ( 0 , 0 ) 和 ( 0 , 1 ) 两个坐标左右包围。

part = im.crop( ( 0 , 0 , 100 , 100 ) ) #截取获得图像 im 左上角大小为 100 × 100 像素的矩形图像

通道处理——split / getchannel

split 方法将图像数据按通道分离,其返回值为包含各个通道分离数据的元组tuple,如对于 RGB 图像而言,其被分成 R、G、B 三个通道的数据。

R, G, B = im.split() # im 为真彩色 Image 对象,其被分为独立的 R、G、B 通道信息

getchannel 方法以图像的通道的索引或字符名字为参数,返回包含有对应通道数据的 L 类型的图像( 即为黑白模式 )。

R = im.getchannel( 0 )  # 获得 RGB 图像的第一个通道的数据,即 R 通道信息
  R = im.getchannel( "R" ) #同上

缩放图像——resize

resize 方法以缩放目标图像大小的元祖( Width, Heigth ) 为参数,通过指定的采样方法将图像缩放为指定的图像大小。其支持采样的方法包括 PIL.Image.NEAREST、PIL.Image.BILINEAR、PIL.Image.BICUBIC 等,resize 支持的全部采样方式见文档。注意,以上采样方法的全名为 PIL.Image.xxxx,但实际上由于之前已经使用 from PIL import Image 导入了 Image 这个模块名,故而后续可以直接使用 Image.xxxx 的形式调用上述方法,反之,在未导入模块名时需使用完整的名称来使用上述方法,下同。

data = im.resize( ( 100, 100 ) )             #将 im 对应的 Image 对象缩放为 100×100 的大小,默认采用 PIL.Image.NEAREST 方法
  data = im.resize( ( 100, 100 ), Image.BICUBIC )     #使用 PIL.Image.BICUBIC 方法进行采样

翻转图像——rotate/transpose

通过 rotate 方法旋转图像,rotate 方法以旋转的角度为参数,将图像顺时针中心旋转对应的度数,并返回对应的 Image 对象。注意,通过 rotate 方法进行旋转时,结果图像是中心旋转后图像在源图像大小范围内被截取的部分,其他部分为填充。如大小为宽×高 200 * 100 的图像,经过 90 度旋转后,其大小仍为 200 * 100 ,图像内容为旋转后的理论为 100 * 200 的图像与原 200 * 100 区域的重合部分,其余部分为填充。

rotate 方法可以指定 expand 参数为 1 ,此时生成的新图像为完整包含有旋转后图像内容的最小矩形大小( 空白处为填充),如上例中,图像经过 90 度旋转后,获得的新图像的大小即为 100 * 200。更多介绍见 Image.rotate.

data = im.rotate( 90 ) #将图像顺时针旋转 90 度
data = im.rotate( 90 , expand=1 ) #将图像顺时针旋转 90 度,同时保留图像的完整内容

在某些图像训练的数据生成中,将图像进行 90 度为单位的旋转、上下或左右翻转是更为常见的操作。此时可以使用 transpose 方法,transpose 以翻转方式为参数,返回经过翻转后的图像,其支持的参数如下所示。

PIL.Image.FLIP_LEFT_RIGHT  #左右翻转图像
  PIL.Image.FLIP_TOP_BOTTOM  #上下翻转图像
  PIL.Image.ROTATE_90
  PIL.Image.ROTATE_180
  PIL.Image.ROTATE_270     #顺时针旋转对应度数
  PIL.Image.TRANSPOSE     #类似于左右翻转后再逆时针旋转图像 90 度
  PIL.Image.TRANSVERSE     #类似与左右翻转后再顺时针旋转图像 90 度

可以直接使用上述参数对图像进行变换,transpose 方法返回变换后的完整图像( 由于是 90 度倍数的变换,也不存在空白区域 )。

data = im.transpose( Image.FLIP_LEFT_RIGHT ) #获得 im 图像经过左右旋转后的数据

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中异常重试的解决方案详解
May 05 Python
Python多进程与服务器并发原理及用法实例分析
Aug 21 Python
详解Django的model查询操作与查询性能优化
Oct 16 Python
Python3 jupyter notebook 服务器搭建过程
Nov 30 Python
Django admin禁用编辑链接和添加删除操作详解
Nov 15 Python
Python pandas库中的isnull()详解
Dec 26 Python
Python统计文本词汇出现次数的实例代码
Feb 27 Python
python+selenium+chrome批量文件下载并自动创建文件夹实例
Apr 27 Python
Python调用REST API接口的几种方式汇总
Oct 19 Python
pytorch 移动端部署之helloworld的使用
Oct 30 Python
Python爬虫基础讲解之请求
May 13 Python
python自动化操作之动态验证码、滑动验证码的降噪和识别
Aug 30 Python
Python列表删除元素del、pop()和remove()的区别小结
Sep 11 #Python
python conda操作方法
Sep 11 #Python
多版本python的pip 升级后, pip2 pip3 与python版本失配解决方法
Sep 11 #Python
浅谈Django+Gunicorn+Nginx部署之路
Sep 11 #Python
初次部署django+gunicorn+nginx的方法步骤
Sep 11 #Python
python 如何将数据写入本地txt文本文件的实现方法
Sep 11 #Python
学习Django知识点分享
Sep 11 #Python
You might like
一个简单的php实现的MySQL数据浏览器
2007/03/11 PHP
MySQL连接数超过限制的解决方法
2011/07/17 PHP
2个比较经典的PHP加密解密函数分享
2014/07/01 PHP
变量在 PHP7 内部的实现(二)
2015/12/21 PHP
php文件包含的几种方式总结
2019/09/19 PHP
js 解决“options为空或不是对象”
2008/12/22 Javascript
使用CSS样式position:fixed水平滚动的方法
2014/02/19 Javascript
教你如何自定义百度分享插件以及bshare分享插件的分享按钮
2014/06/20 Javascript
javascript中一些util方法汇总
2015/06/10 Javascript
浅谈关于JavaScript API设计的一些建议和准则
2015/06/24 Javascript
Bootstrap面板(Panels)的简单实现代码
2017/03/17 Javascript
十大热门的JavaScript框架和库
2017/03/21 Javascript
vue2.0父子组件间通信的实现方法
2017/04/19 Javascript
jQuery+PHP+Mysql实现抽奖程序
2020/04/12 jQuery
p5.js入门教程之平滑过渡(Easing)
2018/03/16 Javascript
vue路由守卫及路由守卫无限循环问题详析
2019/09/05 Javascript
.netcore+vue 实现压缩文件下载功能
2020/09/24 Javascript
微信小程序实现自定义底部导航
2020/11/18 Javascript
python daemon守护进程实现
2016/08/27 Python
Pycharm设置去除显示的波浪线方法
2018/10/28 Python
解决Python3下map函数的显示问题
2019/12/04 Python
在flask中使用python-dotenv+flask-cli自定义命令(推荐)
2020/01/05 Python
python定义类self用法实例解析
2020/01/22 Python
Win10下配置tensorflow-gpu的详细教程(无VS2015/2017)
2020/07/14 Python
python安装cx_Oracle和wxPython的方法
2020/09/14 Python
python制作微博图片爬取工具
2021/01/16 Python
New Balance美国官网:运动鞋和健身服装
2017/04/11 全球购物
八年级上册语文教学计划
2015/01/22 职场文书
营业员岗位职责范本
2015/04/14 职场文书
2015民办小学年度工作总结
2015/05/26 职场文书
听课评课活动心得体会
2016/01/15 职场文书
2016优秀青年志愿者事迹材料
2016/02/25 职场文书
检讨书之工作不认真
2019/08/14 职场文书
fastdfs+nginx集群搭建的实现
2021/03/31 Servers
Python激活Anaconda环境变量的详细步骤
2021/06/08 Python
PostgreSQL之连接失败的问题及解决
2023/05/08 PostgreSQL