• numpy模块可以用于图像的变换。接下来,我们来点恶搞的东西。 话不多说,先来看小姐姐。 下面来看看转换像素之后的照片。 只需要简单的几行代码就可以实现了,下面我们来看看吧。 首先来看看几个导入的包...

    numpy模块可以用于图像的变换。接下来,我们来点恶搞的东西。

    话不多说,先来看诱人的水果图。PS:之前的小姐姐图删了,那个小姐姐不乐意了。
    在这里插入图片描述

    下面来看看转换像素之后的照片。
    在这里插入图片描述
    额,变换之后,瞬间就褪下了诱人的外表,变得恐怖了。

    只需要简单的几行代码就可以实现了,下面我们来看看吧。
    首先来看看几个导入的包。

    from PIL import Image
    import numpy as np
    

    先用Image()的open()方法打开图片,再转为numpy数组。

    image = np.array(Image.open('meinv.jpeg'))
    

    然后,来看看image对象是什么东西。
    在这里插入图片描述
    显然,是个三维数组。数组里面存的是什么?像素。
    在这里插入图片描述
    然后,最关键的一步来了——进行像素的反转。

    b = [255, 255, 255] - image
    

    直接进行数组的减法运算。PS:不懂[255, 255, 255]的自行百度三原色。
    最后,保存新的美图。

    new_image = Image.fromarray(b.astype('uint8'))
    new_image.save('new_meinv.jpeg')
    
    展开全文
  • 这些Python库提供了一种简单直观的方法来转换图像并理解底层数据。 今天的世界充满了数据,图像是这些数据的重要组成部分。但是,在使用它们之前,必须...Python是这些图像处理任务的绝佳选择,因为它作为一种科学...

    这些Python库提供了一种简单直观的方法来转换图像并理解底层数据。

    今天的世界充满了数据,图像是这些数据的重要组成部分。但是,在使用它们之前,必须对这些数字图像进行处理 - 分析和操作,以提高其质量或提取一些可以使用的信息。

    常见的图像处理任务包括显示; 基本操作如裁剪,翻转,旋转等;;图像分割,分类和特征提取;图像恢复;图像识别。Python是这些图像处理任务的绝佳选择,因为它作为一种科学编程语言日益普及,并且在其生态系统中免费提供许多最先进的图像处理工具。

    本文着眼于10个最常用的Python库,用于图像处理任务。这些库提供了一种简单直观的方法来转换图像并理解底层数据。

    1. scikit-image

    scikit-image是一个与NumPy数组一起使用的开源Python包。它实现了用于研究,教育和行业应用的算法和实用程序。它是一个相当简单直接的库,即使对那些不熟悉Python生态系统的人也是如此。代码质量高,经过同行评审,由一个活跃的志愿者社区编写。

    资源

    scikit-image文档丰富,有很多示例和实际使用方法。

    用法

    该包通过skimage导入,大多数功能可以在子模块中找到。

    图像过滤:

    使用match_template函数进行模板匹配:

    你可以在gallery中找到更多的例子。

    2. NumPy

    NumPy是Python编程中的核心库之一,并为数组提供支持。图像本质上是包含数据点像素的标准NumPy数组。因此,通过使用基本的NumPy操作(如slicing,masking和fancy indexing),您可以修改图像的像素值。可以使用 skimage加载图像并使用 Matplotlib显示。

    资源

    NumPy的官方文档页面提供了完整的资源和文档列表。

    用法

    使用Numpy来mask图片:

    3. SciPy

    SciPy是Python的另一个核心科学模块(如NumPy),可用于基本的图像操作和处理任务。特别是,子模块 scipy.ndimage(在SciPy v1.1.0中)提供了在n维NumPy数组上运行的函数。该软件包目前包括线性和非线性滤波,二进制形态,B样条插值和对象测量等功能。

    资源

    有关scipy.ndimage包所提供的完整功能列表,请参阅文档。

    用法

    使用SciPy通过高斯滤波器进行模糊

    4. PIL/Pillow

    PIL(Python Imaging Library)是一个免费的Python编程语言库,它增加了对打开,操作和保存许多不同图像格式的支持。然而,它的发展停滞不前,其最后一版发布于2009年。幸运的是,Pillow是一个积极开发的PIL分支,它更易于安装,可在所有主流操作系统上运行,并支持Python 3。该库包含基本图像处理功能,包括点操作,使用一组内置卷积内核进行过滤以及颜色空间转换。

    资源

    文档包含安装说明以及涵盖库的每个模块的示例。

    用法

    使用ImageFilter增强Pillow中的图像:

    5. OpenCV-Python

    OpenCV(Open Source Computer Vision Library)是计算机视觉应用中使用最广泛的库之一。OpenCV-Python是OpenCV的Python API。因为后台由C / C ++编写的代码组成,OpenCV-Python速度很快快,但它也很容易编码和部署(由于前端的Python包装器)。这使其成为执行计算密集型计算机视觉程序的绝佳选择。

    资源

    通过OpenCV2-Python-Guide可以很容易上手OpenCV-Python

    用法

    使用OpenCV-Python中的 Image Blending using Pyramids创建一个“Orapple”:

    6. SimpleCV

    SimpleCV是另一个用于构建计算机视觉应用程序的开源框架。它提供访问几个高性能计算机视觉库,如OpenCV,的接口,但无需了解位深度,文件格式,色彩空间等。它的学习曲线远小于OpenCV,并且(如其标语所示),“它令计算机视觉变得简单。”支持SimpleCV的一些观点是:

    即使是初学者也可以编写简单的机器视觉测试

    摄像机,视频文件,图像和视频流都可以互操作

    资源

    很容易按照官方文档的指导进行操作,并有大量的示例和用例可供遵循。

    用法

    7. Mahotas

    Mahotas是另一个用于Python的计算机视觉和图像处理库。它包含传统的图像处理功能,如过滤和形态操作,以及用于特征计算的更现代的计算机视觉功能,包括兴趣点检测和局部描述符。使用Python编写接口,适用于快速开发,但算法是用C ++实现的,并且针对速度进行了优化。Mahotas库运行快速,代码简约,依赖性小。阅读其官方文章以获得更多了解。

    资源

    文档包含安装说明,示例,甚至一些教程帮助您轻松开始使用Mahotas。

    用法

    Mahotas库依靠简单的代码来完成工作。例如,使用最少量的代码Finding Wally问题就可以很好地解决。

    解决Finding Wally问题:

    8. SimpleITK

    ITK(Insight Segmentation and Registration Toolkit)是一个“开源,跨平台系统,为开发人员提供了一套用于图像分析的广泛软件工具。SimpleITK是一个基于ITK构建的简化层,旨在促进其在快速原型设计,交易以及解释语言方面的应用。”它也是一个图像分析工具包,具有大量组件,支持一般过滤操作,图像分割和配准。SimpleITK是用C ++编写的,但它可用包括Python在内的大量编程语言进行操作。

    资源

    有大量的Jupyter Notebook说明了SimpleITK在教育和研究活动中的应用。Notebooks使用Python和R编程语言演示如何使用SimpleITK进行交互式图像分析。

    用法

    使用SimpleITK和Python创建可视化的严格CT / MR配准过程:

    9. pgmagick

    pgmagick是基于Python的GraphicsMagick库的包装器。GraphicsMagick图像处理系统,有时也被称为图像处理的瑞士军刀。其强大而高效的工具和库集合支持在超过88种主要格式(包括DPX,GIF,JPEG,JPEG-2000,PNG,PDF,PNM和TIFF)上读取,写入和操作图像。

    资源

    pgmagick的GitHub respository有安装说明和要求。还有一个详细的用户指南。

    用法

    图像缩放:

    边缘提取:

    10. Pycairo

    Pycairo是Cairo图形库的一组Python绑定。Cairo是一个用于绘制矢量图形的2D图形库。矢量图形很有趣,因为它们在调整大小或变换时不会失去清晰度。Pycairo可以从Python调用Cairo命令。

    资源

    Pycairo GitHub respository是一个很好的资源,包含有关安装和使用的详细说明。还有一个入门指南,有一个关于Pycairo的简短教程。

    用法

    用Pycairo绘制线条,基本形状和径向渐变:

    结论

    这些是Python中一些有用且免费提供的图像处理库。有些是众所周知的,有些可能对你来说是新的。尝试一下它们以了解更多关于它们的信息!

    展开全文
  • 整理了Python中关于Image模块的一些简单的图像处理操作
    版本信息:2.7.11
    环境:windows 7 64位系统
    编辑器:PyCharm
    运行工具:PyCharm
    文件地址:D:\phpStudy\WWW\python\Image

    一、引入图像模块

    1. PIL简介:PIL(Python Imaging Library Python,图像处理类库)提供了通用的图像处理功能,以及大量有用的基本图像操作,比如图像缩放、裁剪、旋转、颜色转换等。利用 PIL 中的函数,我们可以从大多数图像格式的文件中读取数据,然后写入最常见的图像格式文件中。PIL 中最重要的模块为 Image 

    2. 引入PIL:
    1. from PIL import Image
    注意:有一些教程默认是用import Image的,但是在window 的64位系统中如果没有在cmd中执行pip install PIL是找不到Image模块的,所以呢必须先安装Pillow,在cmd中运行pip install Pillow,这里也要变成from PIL import Image

    二、读取与存储操作

    1. PIL 的 open() 函数用于创建 PIL 图像对象,比如读取一张图片:
    1. # coding=utf-8
    2. from PIL import Image
    3. # 读取图片
    4. img = Image.open('qq_image.jpg')
    注意:在该路径下必须有qq_image.jpg图片,否则会出错

    2. 存储图片:
    save() 方法用于保存图像到具有指定文件名的文件。通过 save() 方法,PIL 可以将图像保存成多种格式的文件,PIL 是个足够智能的类库,可以根据文件扩展名来判定图像的格式。比如:img.save('qq_image_thumb.jpg', 'JPEG'),PIL 函数会进行简单的检查,如果文件不是 JPEG 格式,会自动将其转换成 JPEG 格式;如果转换失败,它会在控制台输出一条报告失败的消息。

    为了效果,生成缩略图并且保存为qq_image_thumb.jpg:
    1. # coding=utf-8
    2. from PIL import Image
    3. # 读取图片
    4. img = Image.open('qq_image.jpg')
    5. # 生成缩略图
    6. img.thumbnail((128, 128))
    7. # 保存图片
    8. img.save('qq_image_thumb.jpg', 'JPEG')
    运行后,进去文件目录:

     

    三、图像的一些基本操作

    1. 输出图片的信息(格式、尺寸以及图像类型)

    1. # coding=utf-8
    2. from PIL import Image
    3. # 读取图片
    4. img = Image.open('qq_image.jpg')
    5. # 输出图片的格式,尺寸以及图像类型
    6. print img.format, img.size, img.mode
    输出:JPEG (355, 346) RGB

    2. 显示图片

    1. # coding=utf-8
    2. from PIL import Image
    3. # 读取图片
    4. img = Image.open('qq_image.jpg')
    5. # 显示图片
    6. img.show()
    PyCharm下运行呢,会直接调用Windows照片查看器来显示图片

    3. 生成缩略图

    thumbnail() 方法接受一个元组参数(该参数指定生成缩略图的大小),然后将图像转换成符合元组参数指定大小的缩略图。
    1. # coding=utf-8
    2. from PIL import Image
    3. # 读取图片
    4. img = Image.open('qq_image.jpg')
    5. # 生成缩略图
    6. img.thumbnail((128, 128))
    7. # 显示图片
    8. img.show()
    这样运行之后就会显示128*128的图片

    4. 旋转图片

    要旋转一幅图像,可以使用逆时针方式表示旋转角度,然后调用 rotate() 方法:
    1. # coding=utf-8
    2. from PIL import Image
    3. # 读取图片
    4. img = Image.open('qq_image.jpg')
    5. # 逆时针旋转45度
    6. rorate1 = img.rotate(45)
    7. rorate1.show()
    8. # 逆时针旋转90
    9. rorate2 = img.transpose(Image.ROTATE_90)
    10. rorate2.show()
    运行后如图:
    rorate1:

    由于尺寸不变,旋转45度之后会填白

    rorate2:

     
    注意:只有选择90度,180度以及270度的时候才能用img.transpose(Image.ROTATE_90),其他角度用rotate

    5. 翻转

    1. # coding=utf-8
    2. from PIL import Image
    3. # 读取图片
    4. img = Image.open('qq_image.jpg')
    5. # 左右对换
    6. rorate3 = img.transpose(Image.FLIP_LEFT_RIGHT)
    7. rorate3.show()
    8. # 上下翻转
    9. rorate4 = img.transpose(Image.FLIP_TOP_BOTTOM)
    10. rorate4.show()
    运行后:
    rorate3:

     
    rorate4:

     

    6. 缩放图片

    要调整一幅图像的尺寸,我们可以调用 resize() 方法。该方法的参数是一个元组,用来指定新图像的大小:
    1. # coding=utf-8
    2. from PIL import Image
    3. # 读取图片
    4. img = Image.open('qq_image.jpg')
    5. # 缩放图片为50*50
    6. resize1 = img.resize((50, 50))
    7. resize1.show()

    7. 图片灰度化

    图像的颜色转换可以使用 convert() 方法来实现。要读取一幅图像,并将其转换成灰度图像,只需要加上 convert('L'),如下:
    1. # coding=utf-8
    2. from PIL import Image
    3. # 读取图片
    4. img = Image.open('qq_image.jpg')
    5. # 图片转换为灰度
    6. grey = img.convert('L')
    7. grey.show()
    运行后:

     

    8. 某个像素点的色彩值的获取以及更改

    1. # coding=utf-8
    2. from PIL import Image
    3. # 读取图片
    4. img = Image.open('qq_image.jpg')
    5. # 获取某个像素位置的值
    6. print img.getpixel((100, 100))
    7. # 更改某个像素位置的值
    8. img.putpixel((100, 100), (0, 0, 0))

    9. 裁剪图片

    使用 crop() 方法可以从一幅图像中裁剪指定区域:
    1. # coding=utf-8
    2. from PIL import Image
    3. # 读取图片
    4. img = Image.open('qq_image.jpg')
    5. # 裁剪图片 box为裁剪图片的区域范围
    6. box = (100, 100, 250, 250)
    7. region = img.crop(box)
    8. region.show()
    运行输出:

     注意:Python规定左上角为(0, 0)的坐标点,box由一个4元组(左,上,右,下)定义,表示为坐标为: (left, upper, right, lower),最后的两个数字必须比前面两个要大。如图:


    10. 粘贴图片

    为了效果,裁剪该图片的一部分然后旋转,最后粘贴到指定区域:
    1. # coding=utf-8
    2. from PIL import Image
    3. # 读取图片
    4. img = Image.open('qq_image.jpg')
    5. # 裁剪图片 box为裁剪图片的区域范围
    6. box = (100, 100, 250, 250)
    7. region = img.crop(box)
    8. region.show()
    9. # 逆时针旋转图片180度
    10. region2 = region.transpose(Image.ROTATE_180)
    11. region2.show()
    12. # 图片的粘贴
    13. img.paste(region2, box)
    14. img.show()
    运行:

     

    总结:

    如果需要更强大的图像处理操作的话,可以使用Matplotlib类库,它具有比PIL更强大的绘图功能,比如说可以绘制出强大的条形图、饼状图、散点图等。





    展开全文
  • 第 1 章 基本的图像操作和处理本章讲解操作和处理图像的基础知识,将通过大量...1.1 PIL:Python图像处理类库PIL(Python Imaging Library Python,图像处理类库)提供了通用的图像处理功能,以及大量有用的基本图...

    第 1 章 基本的图像操作和处理

    本章讲解操作和处理图像的基础知识,将通过大量示例介绍处理图像所需的 Python 工具包,并介绍用于读取图像、图像转换和缩放、计算导数、画图和保存结果等的基本工具。这些工具的使用将贯穿本书的剩余章节。

    1.1 PIL:Python图像处理类库

    PIL(Python Imaging Library Python,图像处理类库)提供了通用的图像处理功能,以及大量有用的基本图像操作,比如图像缩放、裁剪、旋转、颜色转换等。PIL 是免费的,可以从 http://www.pythonware.com/products/pil/ 下载。

    利用 PIL 中的函数,我们可以从大多数图像格式的文件中读取数据,然后写入最常见的图像格式文件中。PIL 中最重要的模块为 Image。要读取一幅图像,可以使用:

    from PIL import Image
    
    pil_im = Image.open('empire.jpg')

    上述代码的返回值 pil_im 是一个 PIL 图像对象。

    图像的颜色转换可以使用 convert() 方法来实现。要读取一幅图像,并将其转换成灰度图像,只需要加上 convert('L'),如下所示:

    pil_im = Image.open('empire.jpg').convert('L')

    在 PIL 文档中有一些例子,参见 http://www.pythonware.com/library/pil/handbook/index.htm。这些例子的输出结果如图 1-1 所示。

    图 1-1:用 PIL 处理图像的例子

    1.1.1 转换图像格式

    通过 save() 方法,PIL 可以将图像保存成多种格式的文件。下面的例子从文件名列表(filelist)中读取所有的图像文件,并转换成 JPEG 格式:

    from PIL import Image
    import os
    
    for infile in filelist:
      outfile = os.path.splitext(infile)[0] + ".jpg"
      if infile != outfile:
        try:
          Image.open(infile).save(outfile)
        except IOError:
          print "cannot convert", infile
    

    PIL 的 open() 函数用于创建 PIL 图像对象,save() 方法用于保存图像到具有指定文件名的文件。除了后缀变为“.jpg”,上述代码的新文件名和原文件名相同。PIL 是个足够智能的类库,可以根据文件扩展名来判定图像的格式。PIL 函数会进行简单的检查,如果文件不是 JPEG 格式,会自动将其转换成 JPEG 格式;如果转换失败,它会在控制台输出一条报告失败的消息。

    本书会处理大量图像列表。下面将创建一个包含文件夹中所有图像文件的文件名列表。首先新建一个文件,命名为 imtools.py,来存储一些经常使用的图像操作,然后将下面的函数添加进去:

    import os
    def get_imlist(path):
    
    """ 返回目录中所有JPG 图像的文件名列表"""
    
    return [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.jpg')]

    现在,回到 PIL。

    1.1.2 创建缩略图

    使用 PIL 可以很方便地创建图像的缩略图。thumbnail() 方法接受一个元组参数(该参数指定生成缩略图的大小),然后将图像转换成符合元组参数指定大小的缩略图。例如,创建最长边为 128 像素的缩略图,可以使用下列命令:

    pil_im.thumbnail((128,128))

    1.1.3 复制和粘贴图像区域

    使用 crop() 方法可以从一幅图像中裁剪指定区域:

    box = (100,100,400,400)
    region = pil_im.crop(box)

    该区域使用四元组来指定。四元组的坐标依次是(左,上,右,下)。PIL 中指定坐标系的左上角坐标为(0,0)。我们可以旋转上面代码中获取的区域,然后使用 paste() 方法将该区域放回去,具体实现如下:

    region = region.transpose(Image.ROTATE_180)
    pil_im.paste(region,box)

    1.1.4 调整尺寸和旋转

    要调整一幅图像的尺寸,我们可以调用 resize() 方法。该方法的参数是一个元组,用来指定新图像的大小:

    out = pil_im.resize((128,128))

    要旋转一幅图像,可以使用逆时针方式表示旋转角度,然后调用 rotate() 方法:

    out = pil_im.rotate(45)

    上述例子的输出结果如图 1-1 所示。最左端是原始图像,然后是灰度图像、粘贴有旋转后裁剪图像的原始图像,最后是缩略图。

    1.2 Matplotlib

    我们处理数学运算、绘制图表,或者在图像上绘制点、直线和曲线时,Matplotlib 是个很好的类库,具有比 PIL 更强大的绘图功能。Matplotlib 可以绘制出高质量的图表,就像本书中的许多插图一样。Matplotlib 中的 PyLab 接口包含很多方便用户创建图像的函数。Matplotlib 是开源工具,可以从 http://matplotlib.sourceforge.net/ 免费下载。该链接中包含非常详尽的使用说明和教程。下面的例子展示了本书中需要使用的大部分函数。

    1.2.1 绘制图像、点和线

    尽管 Matplotlib 可以绘制出较好的条形图、饼状图、散点图等,但是对于大多数计算机视觉应用来说,仅仅需要用到几个绘图命令。最重要的是,我们想用点和线来表示一些事物,比如兴趣点、对应点以及检测出的物体。下面是用几个点和一条线绘制图像的例子:

    from PIL import Image
    from pylab import *
    
    # 读取图像到数组中
    im = array(Image.open('empire.jpg'))
    
    # 绘制图像
    imshow(im)
    
    # 一些点
    x = [100,100,400,400]
    y = [200,500,200,500]
    
    # 使用红色星状标记绘制点
    plot(x,y,'r*')
    
    # 绘制连接前两个点的线
    plot(x[:2],y[:2])
    
    # 添加标题,显示绘制的图像
    title('Plotting: "empire.jpg"')
    show()

    上面的代码首先绘制出原始图像,然后在 x 和 y 列表中给定点的 x 坐标和 y 坐标上绘制出红色星状标记点,最后在两个列表表示的前两个点之间绘制一条线段(默认为蓝色)。该例子的绘制结果如图 1-2 所示。show() 命令首先打开图形用户界面(GUI),然后新建一个图像窗口。该图形用户界面会循环阻断脚本,然后暂停,直到最后一个图像窗口关闭。在每个脚本里,你只能调用一次 show() 命令,而且通常是在脚本的结尾调用。注意,在 PyLab 库中,我们约定图像的左上角为坐标原点。

    图像的坐标轴是一个很有用的调试工具;但是,如果你想绘制出较美观的图像,加上下列命令可以使坐标轴不显示:

    axis('off')

    上面的命令将绘制出如图 1-2 右边所示的图像。

    图 1-2:Matplotlib 绘图示例。带有坐标轴和不带坐标轴的包含点和一条线段的图像

    在绘图时,有很多选项可以控制图像的颜色和样式。最有用的一些短命令如表 1-1、表 1-2 和表 1-3 所示。使用方法见下面的例子:

    plot(x,y)         # 默认为蓝色实线
    plot(x,y,'r*')    # 红色星状标记
    plot(x,y,'go-')   # 带有圆圈标记的绿线
    plot(x,y,'ks:')   # 带有正方形标记的黑色虚线

    表1-1:用PyLab库绘图的基本颜色格式命令

    颜色

     

    'b'

    蓝色

    'g'

    绿色

    'r'

    红色

    'c'

    青色

    'm'

    品红

    'y'

    黄色

    'k'

    黑色

    'w'

    白色

    表1-2:用PyLab库绘图的基本线型格式命令

    线型

     

    '-'

    实线

    '--'

    虚线

    ':'

    点线

    表1-3:用PyLab库绘图的基本绘制标记格式命令

    标记

     

    '.'

    'o'

    圆圈

    's'

    正方形

    '*'

    星形

    '+'

    加号

    'x'

    叉号

    1.2.2 图像轮廓和直方图

    下面来看两个特别的绘图示例:图像的轮廓和直方图。绘制图像的轮廓(或者其他二维函数的等轮廓线)在工作中非常有用。因为绘制轮廓需要对每个坐标 [x, y] 的像素值施加同一个阈值,所以首先需要将图像灰度化:

    from PIL import Image
    from pylab import *
    
    # 读取图像到数组中
    im = array(Image.open('empire.jpg').convert('L'))
    
    # 新建一个图像
    figure()
    # 不使用颜色信息
    gray()
    # 在原点的左上角显示轮廓图像
    contour(im, origin='image')
    axis('equal')
    axis('off')

    像之前的例子一样,这里用 PIL 的 convert() 方法将图像转换成灰度图像。

    图像的直方图用来表征该图像像素值的分布情况。用一定数目的小区间(bin)来指定表征像素值的范围,每个小区间会得到落入该小区间表示范围的像素数目。该(灰度)图像的直方图可以使用 hist() 函数绘制:

    figure()
    hist(im.flatten(),128)
    show()

    hist() 函数的第二个参数指定小区间的数目。需要注意的是,因为 hist() 只接受一维数组作为输入,所以我们在绘制图像直方图之前,必须先对图像进行压平处理。flatten() 方法将任意数组按照行优先准则转换成一维数组。图 1-3 为等轮廓线和直方图图像。

    图 1-3:用 Matplotlib 绘制图像等轮廓线和直方图

    1.2.3 交互式标注

    有时用户需要和某些应用交互,例如在一幅图像中标记一些点,或者标注一些训练数据。PyLab 库中的 ginput() 函数就可以实现交互式标注。下面是一个简短的例子:

    from PIL import Image
    from pylab import *
    
    im = array(Image.open('empire.jpg'))
    imshow(im)
    print 'Please click 3 points'
    x = ginput(3)
    print 'you clicked:',x
    show()

    上面的脚本首先绘制一幅图像,然后等待用户在绘图窗口的图像区域点击三次。程序将这些点击的坐标 [x, y] 自动保存在 x 列表里。

    1.3 NumPy

    NumPyhttp://www.scipy.org/NumPy/)是非常有名的 Python 科学计算工具包,其中包含了大量有用的思想,比如数组对象(用来表示向量、矩阵、图像等)以及线性代数函数。NumPy 中的数组对象几乎贯穿用于本书的所有例子中 1 数组对象可以帮助你实现数组中重要的操作,比如矩阵乘积、转置、解方程系统、向量乘积和归一化,这为图像变形、对变化进行建模、图像分类、图像聚类等提供了基础。

    1PyLab 实际上包含 NumPy 的一些内容,如数组类型。这也是我们能够在 1.2 节使用数组类型的原因。

    NumPy 可以从 http://www.scipy.org/Download 免费下载,在线说明文档(http://docs.scipy.org/doc/numpy/)包含了你可能遇到的大多数问题的答案。关于 NumPy 的更多内容,请参考开源书籍 [24]。

    1.3.1 图像数组表示

    在先前的例子中,当载入图像时,我们通过调用 array() 方法将图像转换成 NumPy 的数组对象,但当时并没有进行详细介绍。NumPy 中的数组对象是多维的,可以用来表示向量、矩阵和图像。一个数组对象很像一个列表(或者是列表的列表),但是数组中所有的元素必须具有相同的数据类型。除非创建数组对象时指定数据类型,否则数据类型会按照数据的类型自动确定。

    对于图像数据,下面的例子阐述了这一点:

    im = array(Image.open('empire.jpg'))
    print im.shape, im.dtype
    
    im = array(Image.open('empire.jpg').convert('L'),'f')
    print im.shape, im.dtype
    

    控制台输出结果如下所示:

    (800, 569, 3) uint8
    (800, 569) float32
    

    每行的第一个元组表示图像数组的大小(行、列、颜色通道),紧接着的字符串表示数组元素的数据类型。因为图像通常被编码成无符号八位整数(uint8),所以在第一种情况下,载入图像并将其转换到数组中,数组的数据类型为“uint8”。在第二种情况下,对图像进行灰度化处理,并且在创建数组时使用额外的参数“f”;该参数将数据类型转换为浮点型。关于更多数据类型选项,可以参考图书 [24]。注意,由于灰度图像没有颜色信息,所以在形状元组中,它只有两个数值。

    数组中的元素可以使用下标访问。位于坐标 ij,以及颜色通道 k 的像素值可以像下面这样访问:

    value = im[i,j,k]

    多个数组元素可以使用数组切片方式访问。切片方式返回的是以指定间隔下标访问该数组的元素值。下面是有关灰度图像的一些例子:

    im[i,:] = im[j,:]      # 将第 j 行的数值赋值给第 i 行
    im[:,i] = 100          # 将第 i 列的所有数值设为100
    im[:100,:50].sum()     # 计算前100 行、前 50 列所有数值的和
    im[50:100,50:100]      # 50~100 行,50~100 列(不包括第 100 行和第 100 列)
    im[i].mean()           # 第 i 行所有数值的平均值
    im[:,-1]               # 最后一列
    im[-2,:] (or im[-2])   # 倒数第二行

    注意,示例仅仅使用一个下标访问数组。如果仅使用一个下标,则该下标为行下标。注意,在最后几个例子中,负数切片表示从最后一个元素逆向计数。我们将会频繁地使用切片技术访问像素值,这也是一个很重要的思想。

    我们有很多操作和方法来处理数组对象。本书将在使用到的地方逐一介绍。你可以查阅在线文档或者开源图书 [24] 获取更多信息。

    1.3.2 灰度变换

    将图像读入 NumPy 数组对象后,我们可以对它们执行任意数学操作。一个简单的例子就是图像的灰度变换。考虑任意函数 f,它将 0...255 区间(或者 0...1 区间)映射到自身(意思是说,输出区间的范围和输入区间的范围相同)。下面是关于灰度变换的一些例子:

    from PIL import Image
    from numpy import *
    
    im = array(Image.open('empire.jpg').convert('L'))
    
    im2 = 255 - im # 对图像进行反相处理
    
    im3 = (100.0/255) * im + 100 # 将图像像素值变换到100...200 区间
    
    im4 = 255.0 * (im/255.0)**2 # 对图像像素值求平方后得到的图像

    第一个例子将灰度图像进行反相处理;第二个例子将图像的像素值变换到 100...200 区间;第三个例子对图像使用二次函数变换,使较暗的像素值变得更小。图 1-4 为所使用的变换函数图像。图 1-5 是输出的图像结果。你可以使用下面的命令查看图像中的最小和最大像素值:

    print int(im.min()), int(im.max())

    图 1-4:灰度变换示例。三个例子中所使用函数的图像,其中虚线表示恒等变换

    图 1-5:灰度变换。对图像应用图 1-4 中的函数:f(x)=255-x 对图像进行反相处理(左);f(x)=(100/255)x+100 对图像进行变换(中);f(x)=255(x/255)2 对图像做二次变换(右)

    如果试着对上面例子查看最小值和最大值,可以得到下面的输出结果:

    2 255
    0 253
    100 200
    0 255

    array() 变换的相反操作可以使用 PIL 的 fromarray() 函数完成:

    pil_im = Image.fromarray(im)

    如果你通过一些操作将“uint8”数据类型转换为其他数据类型,比如之前例子中的 im3 或者 im4,那么在创建 PIL 图像之前,需要将数据类型转换回来:

    pil_im = Image.fromarray(uint8(im))

    如果你并不十分确定输入数据的类型,安全起见,应该先转换回来。注意,NumPy 总是将数组数据类型转换成能够表示数据的“最低”数据类型。对浮点数做乘积或除法操作会使整数类型的数组变成浮点类型。

    1.3.3 图像缩放

    NumPy 的数组对象是我们处理图像和数据的主要工具。想要对图像进行缩放处理没有现成简单的方法。我们可以使用之前 PIL 对图像对象转换的操作,写一个简单的用于图像缩放的函数。把下面的函数添加到 imtool.py 文件里:

    def imresize(im,sz):
      """ 使用PIL 对象重新定义图像数组的大小"""
      pil_im = Image.fromarray(uint8(im))
    
      return array(pil_im.resize(sz))

    我们将会在接下来的内容中使用这个函数。

    1.3.4 直方图均衡化

    图像灰度变换中一个非常有用的例子就是直方图均衡化。直方图均衡化是指将一幅图像的灰度直方图变平,使变换后的图像中每个灰度值的分布概率都相同。在对图像做进一步处理之前,直方图均衡化通常是对图像灰度值进行归一化的一个非常好的方法,并且可以增强图像的对比度。

    在这种情况下,直方图均衡化的变换函数是图像中像素值的累积分布函数(cumulative distribution function,简写为 cdf,将像素值的范围映射到目标范围的归一化操作)。

    下面的函数是直方图均衡化的具体实现。将这个函数添加到 imtool.py 里:

    def histeq(im,nbr_bins=256):
      """ 对一幅灰度图像进行直方图均衡化"""
    
      # 计算图像的直方图
      imhist,bins = histogram(im.flatten(),nbr_bins,normed=True)
      cdf = imhist.cumsum() # cumulative distribution function
      cdf = 255 * cdf / cdf[-1] # 归一化
    
      # 使用累积分布函数的线性插值,计算新的像素值
      im2 = interp(im.flatten(),bins[:-1],cdf)
    
      return im2.reshape(im.shape), cdf
    

    该函数有两个输入参数,一个是灰度图像,一个是直方图中使用小区间的数目。函数返回直方图均衡化后的图像,以及用来做像素值映射的累积分布函数。注意,函数中使用到累积分布函数的最后一个元素(下标为 -1),目的是将其归一化到 0...1 范围。你可以像下面这样使用该函数:

    from PIL import Image
    from numpy import *
    
    im = array(Image.open('AquaTermi_lowcontrast.jpg').convert('L'))
    im2,cdf = imtools.histeq(im)

    图 1-6 和图 1-7 为上面直方图均衡化例子的结果。上面一行显示的分别是直方图均衡化之前和之后的灰度直方图,以及累积概率分布函数映射图像。可以看到,直方图均衡化后图像的对比度增强了,原先图像灰色区域的细节变得清晰。

    图 1-6:直方图均衡化示例。左侧为原始图像和直方图,中间图为灰度变换函数,右侧为直方图均衡化后的图像和相应直方图

    图 1-7:直方图均衡化示例。左侧为原始图像和直方图,中间图为灰度变换函数,右侧为直方图均衡化后的图像和相应直方图

    1.3.5 图像平均

    图像平均操作是减少图像噪声的一种简单方式,通常用于艺术特效。我们可以简单地从图像列表中计算出一幅平均图像。假设所有的图像具有相同的大小,我们可以将这些图像简单地相加,然后除以图像的数目,来计算平均图像。下面的函数可以用于计算平均图像,将其添加到 imtool.py 文件里:

    def compute_average(imlist):
      """ 计算图像列表的平均图像"""
    
      # 打开第一幅图像,将其存储在浮点型数组中
      averageim = array(Image.open(imlist[0]), 'f')
    
      for imname in imlist[1:]:
        try:
          averageim += array(Image.open(imname))
        except:
          print imname + '...skipped'
      averageim /= len(imlist)
    
      # 返回uint8 类型的平均图像
      return array(averageim, 'uint8')

    该函数包括一些基本的异常处理技巧,可以自动跳过不能打开的图像。我们还可以使用 mean() 函数计算平均图像。mean() 函数需要将所有的图像堆积到一个数组中;也就是说,如果有很多图像,该处理方式需要占用很多内存。我们将会在下一节中使用该函数。

    1.3.6 图像的主成分分析(PCA)

    PCA(Principal Component Analysis,主成分分析)是一个非常有用的降维技巧。它可以在使用尽可能少维数的前提下,尽量多地保持训练数据的信息,在此意义上是一个最佳技巧。即使是一幅 100×100 像素的小灰度图像,也有 10 000 维,可以看成 10 000 维空间中的一个点。一兆像素的图像具有百万维。由于图像具有很高的维数,在许多计算机视觉应用中,我们经常使用降维操作。PCA 产生的投影矩阵可以被视为将原始坐标变换到现有的坐标系,坐标系中的各个坐标按照重要性递减排列。

    为了对图像数据进行 PCA 变换,图像需要转换成一维向量表示。我们可以使用 NumPy 类库中的 flatten() 方法进行变换。

    将变平的图像堆积起来,我们可以得到一个矩阵,矩阵的一行表示一幅图像。在计算主方向之前,所有的行图像按照平均图像进行了中心化。我们通常使用 SVD(Singular Value Decomposition,奇异值分解)方法来计算主成分;但当矩阵的维数很大时,SVD 的计算非常慢,所以此时通常不使用 SVD 分解。下面就是 PCA 操作的代码:

    from PIL import Image
    from numpy import *
    
    def pca(X):
      """ 主成分分析:
        输入:矩阵X ,其中该矩阵中存储训练数据,每一行为一条训练数据
        返回:投影矩阵(按照维度的重要性排序)、方差和均值"""
    
      # 获取维数
      num_data,dim = X.shape
    
      # 数据中心化
      mean_X = X.mean(axis=0)
      X = X - mean_X
    
    if dim>num_data:
      # PCA- 使用紧致技巧
      M = dot(X,X.T) # 协方差矩阵
      e,EV = linalg.eigh(M) # 特征值和特征向量
      tmp = dot(X.T,EV).T # 这就是紧致技巧
      V = tmp[::-1] # 由于最后的特征向量是我们所需要的,所以需要将其逆转
      S = sqrt(e)[::-1] # 由于特征值是按照递增顺序排列的,所以需要将其逆转
      for i in range(V.shape[1]):
        V[:,i] /= S
    else:
      # PCA- 使用SVD 方法
      U,S,V = linalg.svd(X)
      V = V[:num_data] # 仅仅返回前nun_data 维的数据才合理
    
    # 返回投影矩阵、方差和均值
    return V,S,mean_X
    

    该函数首先通过减去每一维的均值将数据中心化,然后计算协方差矩阵对应最大特征值的特征向量,此时可以使用简明的技巧或者 SVD 分解。这里我们使用了 range() 函数,该函数的输入参数为一个整数 n,函数返回整数 0...(n-1) 的一个列表。你也可以使用 arange() 函数来返回一个数组,或者使用 xrange() 函数返回一个产生器(可能会提升速度)。我们在本书中贯穿使用 range() 函数。

    如果数据个数小于向量的维数,我们不用 SVD 分解,而是计算维数更小的协方差矩阵 XXT 的特征向量。通过仅计算对应前 kk 是降维后的维数)最大特征值的特征向量,可以使上面的 PCA 操作更快。由于篇幅所限,有兴趣的读者可以自行探索。矩阵 V 的每行向量都是正交的,并且包含了训练数据方差依次减少的坐标方向。

    我们接下来对字体图像进行 PCA 变换。fontimages.zip 文件包含采用不同字体的字符 a 的缩略图。所有的 2359 种字体可以免费下载 2。假定这些图像的名称保存在列表 imlist 中,跟之前的代码一起保存传在 pca.py 文件中,我们可以使用下面的脚本计算图像的主成分:

    2免费字体图像库由 Martin Solli 收集并上传(http://webstaff.itn.liu.se/~marso/)。

    from PIL import Image
    from numpy import *
    from pylab import *
    import pca
    
    im = array(Image.open(imlist[0])) # 打开一幅图像,获取其大小
    m,n = im.shape[0:2] # 获取图像的大小
    imnbr = len(imlist) # 获取图像的数目
    
    # 创建矩阵,保存所有压平后的图像数据
    immatrix = array([array(Image.open(im)).flatten()
                   for im in imlist],'f')
    
    # 执行 PCA 操作
    V,S,immean = pca.pca(immatrix)
    
    # 显示一些图像(均值图像和前 7 个模式)
    figure()
    gray()
    subplot(2,4,1)
    imshow(immean.reshape(m,n))
    for i in range(7):
      subplot(2,4,i+2)
      imshow(V[i].reshape(m,n))
    
    show()

    注意,图像需要从一维表示重新转换成二维图像;可以使用 reshape() 函数。如图 1-8 所示,运行该例子会在一个绘图窗口中显示 8 个图像。这里我们使用了 PyLab 库的 subplot() 函数在一个窗口中放置多个图像。

    图 1-8:平均图像(左上)和前 7 个模式(具有最大方差的方向模式)

    1.3.7 使用pickle模块

    如果想要保存一些结果或者数据以方便后续使用,Python 中的 pickle 模块非常有用。pickle 模块可以接受几乎所有的 Python 对象,并且将其转换成字符串表示,该过程叫做封装(pickling)。从字符串表示中重构该对象,称为拆封(unpickling)。这些字符串表示可以方便地存储和传输。

    我们来看一个例子。假设想要保存上一节字体图像的平均图像和主成分,可以这样来完成:

    # 保存均值和主成分数据
    f = open('font_pca_modes.pkl', 'wb')
    pickle.dump(immean,f)
    pickle.dump(V,f)
    f.close()

    在上述例子中,许多对象可以保存到同一个文件中。pickle 模块中有很多不同的协议可以生成 .pkl 文件;如果不确定的话,最好以二进制文件的形式读取和写入。在其他 Python 会话中载入数据,只需要如下使用 load() 方法:

    # 载入均值和主成分数据
    f = open('font_pca_modes.pkl', 'rb')
    immean = pickle.load(f)
    V = pickle.load(f)
    f.close()

    注意,载入对象的顺序必须和先前保存的一样。Python 中有个用 C 语言写的优化版本,叫做 cpickle 模块,该模块和标准 pickle 模块完全兼容。关于 pickle 模块的更多内容,参见 pickle 模块文档页 http://docs.python.org/library/pickle.html

    在本书接下来的章节中,我们将使用 with 语句处理文件的读写操作。这是 Python 2.5 引入的思想,可以自动打开和关闭文件(即使在文件打开时发生错误)。下面的例子使用 with() 来实现保存和载入操作:

    # 打开文件并保存
    with open('font_pca_modes.pkl', 'wb') as f:
      pickle.dump(immean,f)
      pickle.dump(V,f)

    # 打开文件并载入
    with open('font_pca_modes.pkl', 'rb') as f:
      immean = pickle.load(f)
      V = pickle.load(f)

    上面的例子乍看起来可能很奇怪,但 with() 确实是个很有用的思想。如果你不喜欢它,可以使用之前的 open 和 close函数。

    作为 pickle 的一种替代方式,NumPy 具有读写文本文件的简单函数。如果数据中不包含复杂的数据结构,比如在一幅图像上点击的点列表,NumPy 的读写函数会很有用。保存一个数组 x 到文件中,可以使用:

    savetxt('test.txt',x,'%i')

    最后一个参数表示应该使用整数格式。类似地,读取可以使用:

    x = loadtxt('test.txt')

    你可以从在线文档 http://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html 了解更多内容。

    最后,NumPy 有专门用于保存和载入数组的函数。你可以在上面的在线文档里查看关于 save() 和 load() 的更多内容。

    1.4 SciPy

    SciPyhttp://scipy.org/) 是建立在 NumPy 基础上,用于数值运算的开源工具包。SciPy 提供很多高效的操作,可以实现数值积分、优化、统计、信号处理,以及对我们来说最重要的图像处理功能。接下来,本节会介绍 SciPy 中大量有用的模块。SciPy 是个开源工具包,可以从 http://scipy.org/Download 下载。

    1.4.1 图像模糊

    图像的高斯模糊是非常经典的图像卷积例子。本质上,图像模糊就是将(灰度)图像 I 和一个高斯核进行卷积操作:

    Iσ = I*

    其中 * 表示卷积操作; 是标准差为 σ 的二维高斯核,定义为 :

    G_\sigma=\frac{1}{2\pi\sigma}e^{-(x^2+y^2)/2\sigma^2}

    高斯模糊通常是其他图像处理操作的一部分,比如图像插值操作、兴趣点计算以及很多其他应用。

    SciPy 有用来做滤波操作的 scipy.ndimage.filters 模块。该模块使用快速一维分离的方式来计算卷积。你可以像下面这样来使用它:

    from PIL import Image
    from numpy import *
    from scipy.ndimage import filters
    
    im = array(Image.open('empire.jpg').convert('L'))
    im2 = filters.gaussian_filter(im,5)

    上面 guassian_filter() 函数的最后一个参数表示标准差。

    图 1-9 显示了随着 σ 的增加,一幅图像被模糊的程度。σ 越大,处理后的图像细节丢失越多。如果打算模糊一幅彩色图像,只需简单地对每一个颜色通道进行高斯模糊:

    im = array(Image.open('empire.jpg'))
    im2 = zeros(im.shape)
    for i in range(3):
      im2[:,:,i] = filters.gaussian_filter(im[:,:,i],5)
    im2 = uint8(im2)

    在上面的脚本中,最后并不总是需要将图像转换成 uint8 格式,这里只是将像素值用八位来表示。我们也可以使用:

    im2 = array(im2,'uint8')

    来完成转换。

    关于该模块更多的内容以及不同参数的选择,请查看 http://docs.scipy.org/doc/scipy/reference/ndimage.html 上 SciPy 文档中的 scipy.ndimage 部分。

    图 1-9:使用 scipy.ndimage.filters 模块进行高斯模糊:(a)原始灰度图像;(b)使用 σ=2 的高斯滤波器;(c)使用 σ=5 的高斯滤波器;(d)使用 σ=10 的高斯滤波器

    1.4.2 图像导数

    整本书中可以看到,在很多应用中图像强度的变化情况是非常重要的信息。强度的变化可以用灰度图像 I(对于彩色图像,通常对每个颜色通道分别计算导数)的 x 和 y 方向导数 Ix 和 Iy 进行描述。

    图像的梯度向量为∇I = [IxIy]T。梯度有两个重要的属性,一是梯度的大小

    \left|\boldsymbol{\nabla I}\right|=\sqrt{{\boldsymbol{I}_x}^2+{\boldsymbol{I}_y}^2}

    它描述了图像强度变化的强弱,一是梯度的角度

    α=arctan2(IyIx)

    描述了图像中在每个点(像素)上强度变化最大的方向。NumPy 中的 arctan2() 函数返回弧度表示的有符号角度,角度的变化区间为 -π...π。

    我们可以用离散近似的方式来计算图像的导数。图像导数大多数可以通过卷积简单地实现:

    Ix=I*Dx 和 Iy=I*Dy

    对于 Dx 和 Dy,通常选择 Prewitt 滤波器:

    D_x=\begin{vmatrix}-1&0&1\\-1&0&1\\ -1&0&1\end{vmatrix} 和 D_y=\begin{vmatrix}-1&-1&-1\\0&0&0\\ 1&1&1\end{vmatrix}

    或者 Sobel 滤波器:

    D_x=\begin{vmatrix}-1&0&1\\-2&0&2\\ -1&0&1\end{vmatrix} 和 D_y=\begin{vmatrix}-1&-2&-1\\0&0&0\\ 1&2&1\end{vmatrix}

    这些导数滤波器可以使用 scipy.ndimage.filters 模块的标准卷积操作来简单地实现,例如:

    from PIL import Image
    from numpy import *
    from scipy.ndimage import filters
    
    im = array(Image.open('empire.jpg').convert('L'))
    
    # Sobel 导数滤波器
    imx = zeros(im.shape)
    filters.sobel(im,1,imx)
    
    imy = zeros(im.shape)
    filters.sobel(im,0,imy)
    
    magnitude = sqrt(imx**2+imy**2)

    上面的脚本使用 Sobel 滤波器来计算 x 和 y 的方向导数,以及梯度大小。sobel() 函数的第二个参数表示选择 x 或者 y 方向导数,第三个参数保存输出的变量。图 1-10 显示了用 Sobel 滤波器计算出的导数图像。在两个导数图像中,正导数显示为亮的像素,负导数显示为暗的像素。灰色区域表示导数的值接近于零。

    图 1-10:使用 Sobel 导数滤波器计算导数图像:(a)原始灰度图像;(b)x 导数图像;(c)y 导数图像;(d)梯度大小图像

    上述计算图像导数的方法有一些缺陷:在该方法中,滤波器的尺度需要随着图像分辨率的变化而变化。为了在图像噪声方面更稳健,以及在任意尺度上计算导数,我们可以使用高斯导数滤波器:

    Ix=I*Gσx 和 Iy=I*Gσy

    其中,Gσx和 Gσy 表示  在 x 和 y 方向上的导数, 为标准差为 σ 的高斯函数。

    我们之前用于模糊的 filters.gaussian_filter() 函数可以接受额外的参数,用来计算高斯导数。可以简单地按照下面的方式来处理:

    sigma = 5 # 标准差
    
    imx = zeros(im.shape)
    filters.gaussian_filter(im, (sigma,sigma), (0,1), imx)
    
    imy = zeros(im.shape)
    filters.gaussian_filter(im, (sigma,sigma), (1,0), imy)

    该函数的第三个参数指定对每个方向计算哪种类型的导数,第二个参数为使用的标准差。你可以查看相应文档了解详情。图 1-11 显示了不同尺度下的导数图像和梯度大小。你可以和图 1-9 中做相同尺度模糊的图像做比较。

    图 1-11:使用高斯导数计算图像导数:x 导数图像(上),y 导数图像(中),以及梯度大小图像(下);(a)为原始灰度图像,(b)为使用 σ=2 的高斯导数滤波器处理后的图像,(c)为使 用 σ=5 的高斯导数滤波器处理后的图像,(d)为使用 σ=10 的高斯导数滤波器处理后的图像

    1.4.3 形态学:对象计数

    形态学(或数学形态学)是度量和分析基本形状的图像处理方法的基本框架与集合。形态学通常用于处理二值图像,但是也能够用于灰度图像。二值图像是指图像的每个像素只能取两个值,通常是 0 和 1。二值图像通常是,在计算物体的数目,或者度量其大小时,对一幅图像进行阈值化后的结果。你可以从http://en.wikipedia.org/wiki/Mathematical_morphology 大体了解形态学及其处理图像的方式。

    scipy.ndimage 中的 morphology 模块可以实现形态学操作。你可以使用 scipy.ndimage 中的 measurements 模块来实现二值图像的计数和度量功能。下面通过一个简单的例子介绍如何使用它们。

    考虑在图 1-12a3 里的二值图像,计算该图像中的对象个数可以通过下面的脚本实现:

    3这个图像实际上是图像“分割”后的结果。如果你想知道该图像是如何创建的,可以查看 9.3 节。

    from scipy.ndimage import measurements,morphology
    
    # 载入图像,然后使用阈值化操作,以保证处理的图像为二值图像
    im = array(Image.open('houses.png').convert('L'))
    im = 1*(im<128)
    
    labels, nbr_objects = measurements.label(im)
    print "Number of objects:", nbr_objects
    
    

    上面的脚本首先载入该图像,通过阈值化方式来确保该图像是二值图像。通过和 1 相乘,脚本将布尔数组转换成二进制表示。然后,我们使用 label() 函数寻找单个的物体,并且按照它们属于哪个对象将整数标签给像素赋值。图 1-12b 是labels 数组的图像。图像的灰度值表示对象的标签。可以看到,在一些对象之间有一些小的连接。进行二进制开(binary open)操作,我们可以将其移除:

    # 形态学开操作更好地分离各个对象
    im_open = morphology.binary_opening(im,ones((9,5)),iterations=2)
    
    labels_open, nbr_objects_open = measurements.label(im_open)
    print "Number of objects:", nbr_objects_open
    

    binary_opening() 函数的第二个参数指定一个数组结构元素。该数组表示以一个像素为中心时,使用哪些相邻像素。在这种情况下,我们在 y 方向上使用 9 个像素(上面 4 个像素、像素本身、下面 4 个像素),在 x 方向上使用 5 个像素。你可以指定任意数组为结构元素,数组中的非零元素决定使用哪些相邻像素。参数 iterations 决定执行该操作的次数。你可以尝试使用不同的迭代次数 iterations 值,看一下对象的数目如何变化。你可以在图 1-12c 与图 1-12d 中查看经过开操作后的图像,以及相应的标签图像。正如你想象的一样,binary_closing() 函数实现相反的操作。我们将该函数和在morphology 和 measurements 模块中的其他函数的用法留作练习。你可以从 scipy.ndimage 模块文档http://docs.scipy.org/doc/scipy/reference/ndimage.html 中了解关于这些函数的更多知识。

    图 1-12:形态学示例。使用二值开操作将对象分开,然后计算物体的数目:(a)为原始二值图像;(b)为对应原始图像的标签图像,其中灰度值表示物体的标签;(c)为使用开操作后的二值图像;(d)为开操作后图像的标签图像

    1.4.4 一些有用的SciPy模块

    SciPy 中包含一些用于输入和输出的实用模块。下面介绍其中两个模块:io 和 misc

    1. 读写.mat文件

      如果你有一些数据,或者在网上下载到一些有趣的数据集,这些数据以 Matlab 的 .mat 文件格式存储,那么可以使用 scipy.io 模块进行读取。

      data = scipy.io.loadmat('test.mat')

      上面代码中,data 对象包含一个字典,字典中的键对应于保存在原始 .mat 文件中的变量名。由于这些变量是数组格式的,因此可以很方便地保存到 .mat 文件中。你仅需创建一个字典(其中要包含你想要保存的所有变量),然后使用 savemat() 函数:

      data = {}
      data['x'] = x
      scipy.io.savemat('test.mat',data)

      因为上面的脚本保存的是数组 x,所以当读入到 Matlab 中时,变量的名字仍为 x。关于 scipy.io 模块的更多内容,请参见在线文档 http://docs.scipy.org/doc/scipy/reference/io.html

    2. 以图像形式保存数组

      因为我们需要对图像进行操作,并且需要使用数组对象来做运算,所以将数组直接保存为图像文件 4 非常有用。本书中的很多图像都是这样的创建的。

      imsave() 函数可以从 scipy.misc 模块中载入。要将数组 im 保存到文件中,可以使用下面的命令:

      from scipy.misc import imsave
      imsave('test.jpg',im)

      scipy.misc 模块同样包含了著名的 Lena 测试图像:

      lena = scipy.misc.lena()

      该脚本返回一个 512×512 的灰度图像数组。

    4所有 Pylab 图均可保存为多种图像格式,方法是点击图像窗口中的“保存”按钮。

    1.5 高级示例:图像去噪

    我们通过一个非常实用的例子——图像的去噪——来结束本章。图像去噪是在去除图像噪声的同时,尽可能地保留图像细节和结构的处理技术。我们这里使用 ROF(Rudin-Osher-Fatemi)去噪模型。该模型最早出现在文献 [28] 中。图像去噪对于很多应用来说都非常重要;这些应用范围很广,小到让你的假期照片看起来更漂亮,大到提高卫星图像的质量。ROF 模型具有很好的性质:使处理后的图像更平滑,同时保持图像边缘和结构信息。

    ROF 模型的数学基础和处理技巧非常高深,不在本书讲述范围之内。在讲述如何基于 Chambolle 提出的算法 [5] 实现 ROF 求解器之前,本书首先简要介绍一下 ROF 模型。

    一幅(灰度)图像 I 的全变差(Total Variation,TV)定义为梯度范数之和。在连续表示的情况下,全变差表示为:

    J(\boldsymbol{I})=\int\left|\nabla\boldsymbol{I}\right|\text{dx}            (1.1)

    在离散表示的情况下,全变差表示为:

    J(\boldsymbol{I})=\sum_{\text{x}}\left|\nabla\boldsymbol{I}\right|

    其中,上面的式子是在所有图像坐标 x=[x, y] 上取和。

    在 Chambolle 提出的 ROF 模型里,目标函数为寻找降噪后的图像 U,使下式最小:

    \min_U\left|\left|\boldsymbol{I}-\boldsymbol{U}\right|\right|^2+2\lambda J(\boldsymbol{U}),

    其中范数 ||I-U|| 是去噪后图像 U 和原始图像 I 差异的度量。也就是说,本质上该模型使去噪后的图像像素值“平坦”变化,但是在图像区域的边缘上,允许去噪后的图像像素值“跳跃”变化。

    按照论文 [5] 中的算法,我们可以按照下面的代码实现 ROF 模型去噪:

    from numpy import *
    
    def denoise(im,U_init,tolerance=0.1,tau=0.125,tv_weight=100):
      """ 使用A. Chambolle(2005)在公式(11)中的计算步骤实现Rudin-Osher-Fatemi(ROF)去噪模型
    
        输入:含有噪声的输入图像(灰度图像)、U 的初始值、TV 正则项权值、步长、停业条件
    
        输出:去噪和去除纹理后的图像、纹理残留"""
    
    m,n = im.shape # 噪声图像的大小
    
    # 初始化
    U = U_init
    Px = im # 对偶域的x 分量
    Py = im # 对偶域的y 分量
    error = 1
    
    while (error > tolerance):
      Uold = U
    
      # 原始变量的梯度
      GradUx = roll(U,-1,axis=1)-U # 变量U 梯度的x 分量
      GradUy = roll(U,-1,axis=0)-U # 变量U 梯度的y 分量
    
      # 更新对偶变量
      PxNew = Px + (tau/tv_weight)*GradUx
      PyNew = Py + (tau/tv_weight)*GradUy
      NormNew = maximum(1,sqrt(PxNew**2+PyNew**2))
    
      Px = PxNew/NormNew # 更新x 分量(对偶)
      Py = PyNew/NormNew # 更新y 分量(对偶)
    
      # 更新原始变量
      RxPx = roll(Px,1,axis=1) # 对x 分量进行向右x 轴平移
      RyPy = roll(Py,1,axis=0) # 对y 分量进行向右y 轴平移
    
      DivP = (Px-RxPx)+(Py-RyPy) # 对偶域的散度
      U = im + tv_weight*DivP # 更新原始变量
    
      # 更新误差
      error = linalg.norm(U-Uold)/sqrt(n*m);
    
    return U,
    展开全文
  • Image模块是在Python PIL图像处理中常见的模块,对图像进行基础操作的功能基本都包含于此模块内。如open、save、conver、show…等功能。 open类 Image.open(file) ⇒ image Image.open(file, mode) ⇒ image...

    Image模块

    Image模块是在Python PIL图像处理中常见的模块,对图像进行基础操作的功能基本都包含于此模块内。如opensaveconvershow…等功能。

    open类

    Image.open(file) ⇒ image
    Image.open(file, mode) ⇒ image

    要从文件加载图像,使用 open() 函数, 在 Image 模块:

        @zhangziju
        from PIL import Image             ##调用库
        im = Image.open("E:\mywife.jpg")  ##文件存在的路径
        im.show()                         

    我老婆

    需要知道的是在win的环境下im.show的方式为win自带的图像显示应用。打开并确认给定的图像文件。这个是一个懒操作;该函数只会读文件头,而真实的图像数据直到试图处理该数据才会从文件读取(调用load()方法将强行加载图像数据)。如果变量mode被设置,那必须是“r”。用户可以使用一个字符串(表示文件名称的字符串)或者文件对象作为变量file的值。文件对象必须实现read(),seek()和tell()方法,并且以二进制模式打开。

    Save类

    im.save(outfile,options…)
    im.save(outfile, format, options…)

    若要保存文件,则使用 Image 类的 save() 方法,此时保存文件的文件名就变得十分重要了,除非指定格式,否则这个库将会以文件名的扩展名作为格式保存。使用给定的文件名保存图像。如果变量format缺省,如果可能的话,则从文件名称的扩展名判断文件的格式。该方法返回为空。关键字options为文件编写器提供一些额外的指令。如果编写器不能识别某个选项,它将忽略它。用户可以使用文件对象代替文件名称。在这种情况下,用户必须指定文件格式。文件对象必须实现了seek()、tell()和write()方法,且其以二进制模式打开。如果方法save()因为某些原因失败,这个方法将产生一个异常(通常为IOError异常)。如果发生了异常,该方法也有可能已经创建了文件,并向文件写入了一些数据。如果需要的话,用户的应用程序可以删除这个不完整的文件。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im)
    im.save("E:\mywife.png")     ## 将"E:\mywife.jpg"保存为"E:\mywife.png"
    im = Image.open("E:\mywife.png")  ##打开新的png图片
    print(im.format, im.size, im.mode)

    这里写图片描述
    如下图,在指定路径下可看到新保存的png格式的图片。
    新的png图片

    format类

    im.format ⇒ string or None

    这个属性标识了图像来源,如果图像不是从文件读取它的值就是None。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.format) ## 打印出格式信息
    im.show()

    如下图可以看到其format为”JPEG”。

    format

    Mode类

    im.mode ⇒ string

    图像的模式,常见的mode 有 “L” (luminance) 表示灰度图像,“RGB”表示真彩色图像,和 “CMYK” 表示出版图像,表明图像所使用像素格式。如下表为常见的nodes描述:

    modes 描述
    1 1位像素,黑和白,存成8位的像素
    L 8位像素,黑白
    P 8位像素,使用调色板映射到任何其他模式
    RGB 3× 8位像素,真彩
    RGBA 4×8位像素,真彩+透明通道
    CMYK 4×8位像素,颜色隔离
    YCbCr 3×8位像素,彩色视频格式
    I 32位整型像素
    F 32位浮点型像素
    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.mode) ## 打印出模式信息
    im.show()

    如下图为图片的mode为“RGB”模式。

    mode

    convert类

    im.convert(mode)⇒ image

    将当前图像转换为其他模式,并且返回新的图像。当从一个调色板图像转换时,这个方法通过这个调色板来转换像素。如果不对变量mode赋值,该方法将会选择一种模式,在没有调色板的情况下,使得图像和调色板中的所有信息都可以被表示出来。当从一个颜色图像转换为黑白图像时,PIL库使用ITU-R601-2 luma转换公式:

    L = R * 299/1000 + G * 587/1000 + B * 114/1000

    当转换为2位图像(模式“1”)时,源图像首先被转换为黑白图像。结果数据中大于127的值被设置为白色,其他的设置为黑色;这样图像会出现抖动。如果要使用其他阈值,更改阈值127,可以使用方法point()。为了去掉图像抖动现象,可以使用dither选项。

    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    new_im = im.convert('P')
    print(new_im.mode)
    new_im.show()

    如下,将图像转换为“P”模式。

    这里写图片描述
    对比原始图像。

    这里写图片描述

    im.convert(“P”,**options) ⇒ image

    这个与第一个方法定义一样,但是当“RGB”图像转换为8位调色板图像时能更好的处理。可供选择的选项为:

    Dither=. 控制颜色抖动。默认是FLOYDSTEINBERG,与邻近的像素一起承担错误。不使能该功能,则赋值为NONE。

    Palette=. 控制调色板的产生。默认是WEB,这是标准的216色的“web palette”。要使用优化的调色板,则赋值为ADAPTIVE。

    Colors=. 当选项palette为ADAPTIVE时,控制用于调色板的颜色数目。默认是最大值,即256种颜色

    im.convert(mode,matrix) ⇒ image

    使用转换矩阵将一个“RGB”图像转换为“L”或者“RGB”图像。变量matrix为4或者16元组。

    
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.mode)
    rgb2xyz = (0.412453,0.357580, 0.180423, 0,
               0.212671,0.715160, 0.072169, 0,
               0.019334,0.119193, 0.950227, 0 )
    new_im = im.convert("L", rgb2xyz)
    print(new_im.mode)
    new_im.show()

    这里写图片描述
    转换后效果

    这里写图片描述

    Size类

    im.size ⇒ (width, height)

    图像的尺寸,按照像素数计算,它的返回值为宽度和高度的二元组(width, height)。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.size) ## 打印出尺寸信息
    im.show()

    如下图所示为图片的尺寸信息,750*560。

    这里写图片描述

    Palette类

    im.palette ⇒ palette or None

    颜色调色板表格。如果图像的模式是“P”,则返回ImagePalette类的实例;否则,将为None。
    如下为对非“P”模式下的图像进行palette信息显示。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.palette)

    易知,返回值为空,none

    这里写图片描述
    对图像进行convert操作,转换成“P”模式

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    new_im = im.convert('P')
    print(new_im.mode)
    print(new_im.palette)

    则返回值为ImagePalette类的实例。如下:

    这里写图片描述

    Info类

    im.info ⇒ dictionary

    存储图像相关数据的字典。文件句柄使用该字典传递从文件中读取的各种非图像信息。大多数方法在返回新的图像时都会忽略这个字典;因为字典中的键并非标准化的,对于一个方法,它不能知道自己的操作如何影响这个字典。如果用户需要这些信息,需要在方法open()返回时保存这个字典。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.info)

    这里写图片描述

    new类

    Image.new(mode,size) ⇒ image
    Image.new(mode, size,color) ⇒ image

    使用给定的变量mode和size生成新的图像。Size是给定的宽/高二元组,这是按照像素数来计算的。对于单通道图像,变量color只给定一个值;对于多通道图像,变量color给定一个元组(每个通道对应一个值)。在版本1.1.4及其之后,用户也可以用颜色的名称,比如给变量color赋值为“red”。如果没有对变量color赋值,图像内容将会被全部赋值为0(为黑色)。如果变量color是空,图像将不会被初始化,即图像的内容全为0。这对向该图像复制或绘制某些内容是有用的。

    如下为将图像设置为128x128大小的红色图像。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    n_im= Image.new("RGB", (128, 128), "#FF0000")
    n_im.show()

    显示效果如下:

    这里写图片描述
    如下图像为128x128大小的黑色图像,因为变量color不赋值的话,图像内容被设置为0,即黑色。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    n_im= Image.new("RGB", (128, 128))
    n_im.show()

    黑
    图像为128x128大小的绿色图像。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    n_im= Image.new("RGB", (128, 128),"green")
    n_im.show()

    这里写图片描述

    Copy类

    im.copy() ⇒ image

    拷贝这个图像。如果用户想粘贴一些数据到这张图,可以使用这个方法,但是原始图像不会受到影响。

    
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    im_copy = im.copy()

    图像im_copy和im完全一样。

    Crop类

    im.crop(box) ⇒ image

    从当前的图像中返回一个矩形区域的拷贝。变量box是一个四元组,定义了左、上、右和下的像素坐标。用来表示在原始图像中截取的位置坐标,如box(100,100,200,200)就表示在原始图像中以左上角为坐标原点,截取一个100*100(像素为单位)的图像,为方便理解,如下为示意图box(b1,a1,b2,a2)。作图软件为Visio2016。这是一个懒操作。对源图像的改变可能或者可能不体现在裁减下来的图像中。为了获取一个分离的拷贝,对裁剪的拷贝调用方法load()。

    box区域示意图

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    box = (300, 100, 700, 700)              ##确定拷贝区域大小
    region = im.crop(box)                   ##将im表示的图片对象拷贝到region中,大小为box
    region.show()

    如下图为box截取的图像区域显示。

    box区域图

    Paste类

    im.paste(image,box)

    将一张图粘贴到另一张图像上。变量box或者是一个给定左上角的2元组,或者是定义了左,上,右和下像素坐标的4元组,或者为空(与(0,0)一样)。如果给定4元组,被粘贴的图像的尺寸必须与区域尺寸一样。如果模式不匹配,被粘贴的图像将被转换为当前图像的模式。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    box=[0,0,100,100]
    im_crop = im.crop(box)
    print(im_crop.size,im_crop.mode)
    im.paste(im_crop, (100,100))             ##(100,100,0,0)
    im.paste(im_crop, (400,400,500,500))
    im.show()

    如下图为paste操作:

    这里写图片描述

    Filter类

    im.filter(filter) ⇒ image

    返回一个使用给定滤波器处理过的图像的拷贝。具体参考图像滤波在ImageFilter 模块的应用,在该模块中,预先定义了很多增强滤波器,可以通过filter( )函数使用,预定义滤波器包括:BLUR、CONTOUR、DETAIL、EDGE_ENHANCE、EDGE_ENHANCE_MORE、EMBOSS、FIND_EDGES、SMOOTH、SMOOTH_MORE、SHARPEN。其中BLUR就是均值滤波,CONTOUR找轮廓,FIND_EDGES边缘检测,使用该模块时,需先导入。

    @zhangziju
    from PIL import Image
    from PIL import ImageFilter                         ## 调取ImageFilter
    imgF = Image.open("E:\mywife.jpg")
    bluF = imgF.filter(ImageFilter.BLUR)                ##均值滤波
    conF = imgF.filter(ImageFilter.CONTOUR)             ##找轮廓
    edgeF = imgF.filter(ImageFilter.FIND_EDGES)         ##边缘检测
    imgF.show()
    bluF.show()
    conF.show()
    edgeF.show()

    滤波处理下的gakki~

    滤波

    Blend类

    Image.blend(image1,image2, alpha) ⇒ image

    使用给定的两张图像及透明度变量alpha,插值出一张新的图像。这两张图像必须有一样的尺寸和模式。

    合成公式为:out = image1 (1.0 - alpha) + image2 alpha

    若变量alpha为0.0,返回第一张图像的拷贝。若变量alpha为1.0,将返回第二张图像的拷贝。对变量alpha的值无限制。

    @zhangziju
    from PIL import Image
    im1 = Image.open("E:\mywife.jpg")
    im2 = Image.open("E:\mywife2.jpg")
    print(im1.mode,im1.size)
    print(im2.mode,im2.size)
    im = Image.blend(im1, im2, 0.2)
    im.show()

    需保证两张图像的模式和大小是一致的,如下为显示im1和im2的具体信息。

    这里写图片描述
    im1和im2按照第一张80%的透明度,第二张20%的透明度,合成为一张。
    这里写图片描述

    Split

    im.split() ⇒ sequence

    返回当前图像各个通道组成的一个元组。例如,分离一个“RGB”图像将产生三个新的图像,分别对应原始图像的每个通道(红,绿,蓝)。

    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    r,g,b = im.split()
    print(r.mode)
    print(r.size)
    print(im.size)

    这里写图片描述

    Composite类

    Image.composite(image1,image2, mask) ⇒ image

    复合类使用给定的两张图像及mask图像作为透明度,插值出一张新的图像。变量mask图像的模式可以为“1”,“L”或者“RGBA”。所有图像必须有相同的尺寸。

    @zhangziju
    from PIL import Image
    im1 = Image.open("E:\mywife.jpg")
    im2 = Image.open("E:\mywife2.jpg")
    r,g,b = im1.split()             ##分离出r,g,b
    print(b.mode)
    print(im1.mode,im1.size)
    print(im2.mode,im2.size)
    im = Image.composite(im1,im2,b)
    im.show()

    b.mode为”L”,两图尺寸一致。

    这里写图片描述
    最终效果

    这里写图片描述

    Eval类

    Image.eval(image,function) ⇒ image

    使用变量function对应的函数(该函数应该有一个参数)处理变量image所代表图像中的每一个像素点。如果变量image所代表图像有多个通道,那变量function对应的函数作用于每一个通道。注意:变量function对每个像素只处理一次,所以不能使用随机组件和其他生成器。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    def fun01(x):
        return x*0.3
    def fun02(y):
        return y*2.0
    im1_eval = Image.eval(im, fun01)
    im2_eval = Image.eval(im, fun02)
    im1_eval.show()
    im2_eval.show()
    

    在函数fun01和fun02下的图像显示。

    这里写图片描述

    Merge类

    Image.merge(mode,bands) ⇒ image

    合并类使用一些单通道图像,创建一个新的图像。变量bands为一个图像的元组或者列表,每个通道的模式由变量mode描述。所有通道必须有相同的尺寸。
    变量mode与变量bands的关系:

    len(ImageMode.getmode(mode).bands)= len(bands)

    @zhangziju
    from PIL import Image
    im1 = Image.open("E:\mywife.jpg")
    im2 = Image.open("E:\mywife2.jpg")
    r1,g1,b1 = im1.split()
    r2,g2,b2 = im2.split()
    print(r1.mode,r1.size,g1.mode,g1.size)
    print(r2.mode,r2.size,g2.mode,g2.size)
    new_im=[r1,g2,b2]
    print(len(new_im))
    im_merge = Image.merge("RGB",new_im)
    im_merge.show()

    打印信息显示

    这里写图片描述
    merge操作

    这里写图片描述

    Draft类

    im.draft(mode,size)

    配置图像文件加载器,使得返回一个与给定的模式和尺寸尽可能匹配的图像的版本。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.size,im.mode)
    new_im = im.draft("L", (200,200))
    print(new_im.size,new_im.mode)
    new_im.show()

    关键信息显示

    这里写图片描述
    转换效果

    这里写图片描述

    Getbands类

    im.getbands()⇒ tuple of strings

    返回包括每个通道名称的元组。例如,对于RGB图像将返回(“R”,“G”,“B”)。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.getbands())
    

    这里写图片描述

    Getbbox类

    im.getbbox() ⇒ 4-tuple or None

    计算图像非零区域的包围盒。这个包围盒是一个4元组,定义了左、上、右和下像素坐标。如果图像是空的,这个方法将返回空。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.getbbox())

    这里写图片描述

    Getdata类

    im.getdata() ⇒ sequence

    以包含像素值的sequence对象形式返回图像的内容。这个sequence对象是扁平的,以便第一行的值直接跟在第零行的值后面,等等。这个方法返回的sequence对象是PIL内部数据类型,它只支持某些sequence操作,包括迭代和基础sequence访问。使用list(im.getdata()),将它转换为普通的sequence。Sequence对象的每一个元素对应一个像素点的R、G和B三个值。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    sequ = im.getdata()
    sequ0 = list(sequ)
    print(sequ0[0])
    print(sequ0[1])
    print(sequ0[2])

    可视化显示sequence0里面的数据。

    这里写图片描述
    打印显示结果,与前面对比。

    这里写图片描述

    Getextrema类

    im.getextrema() ⇒ 2-tuple

    返回一个2元组,包括该图像中的最小和最大值。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.getextrema())

    该方法返回了R/G/B三个通道的最小和最大值的2元组。

    这里写图片描述

    Getpixel类

    im.getpixel(xy) ⇒ value or tuple

    返回给定位置的像素值。如果图像为多通道,则返回一个元组。该方法执行比较慢;如果用户需要使用python处理图像中较大部分数据,可以使用像素访问对象(见load),或者方法getdata()。

    @zahngziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.getpixel((0,0)))
    print(im.getpixel((4,0)))
    r,g,b = im.split()
    print(b.getpixel((11,8)))   

    这里写图片描述

    Histogram类

    im.histogram()⇒ list

    返回一个图像的直方图。这个直方图是关于像素数量的list,图像中的每个象素值对应一个成员。如果图像有多个通道,所有通道的直方图会连接起来(例如,“RGB”图像的直方图有768个值)。二值图像(模式为“1”)当作灰度图像(模式为“L”)处理。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    imhis = im.histogram()
    print(len(imhis))
    print(imhis[0])
    print(imhis[150])
    print(imhis[300])

    这里写图片描述

    im.histogram(mask)⇒ list

    返回图像中模板图像非零地方的直方图。模板图像与处理图像的尺寸必须相同,并且要么是二值图像(模式为“1”),要么为灰度图像(模式为“L”)。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    r,g,b = im.split()
    imhis = im.histogram()
    print(r.mode)
    print(len(imhis))
    print(imhis[0])
    print(imhis[150])
    print(imhis[300])

    这里写图片描述

    Load类

    im.load()

    为图像分配内存并从文件中加载它(或者从源图像,对于懒操作)。正常情况下,用户不需要调用这个方法,因为在第一次访问图像时,Image类会自动地加载打开的图像。在1.1.6及以后的版本,方法load()返回一个用于读取和修改像素的像素访问对象。这个访问对象像一个二维队列,如:

    pix = im.load()
    print pix[x, y]
    pix[x, y] =value

    通过这个对象访问比方法getpixel()和putpixel()快很多。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    pix = im.load()
    print(pix[0,2])

    这里写图片描述

    im.paste(colour,box)

    使用同一种颜色填充变量box对应的区域。对于单通道图像,变量colour为单个颜色值;对于多通道,则为一个元组。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    im.paste((256,256,0),(0,0,100,100))  ##(256,256,0)表示黄色
    im.show()

    这里写图片描述

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    im.paste("blue",(0,0,100,100))   ##或者“blue”
    im.show()

    这里写图片描述

    im.paste(image,box, mask)

    使用变量mask对应的模板图像来填充所对应的区域。可以使用模式为“1”、“L”或者“RGBA”的图像作为模板图像。模板图像的尺寸必须与变量image对应的图像尺寸一致。如果变量mask对应图像的值为255,则模板图像的值直接被拷贝过来;如果变量mask对应图像的值为0,则保持当前图像的原始值。变量mask对应图像的其他值,将对两张图像的值进行透明融合,如果变量image对应的为“RGBA”图像,即粘贴的图像模式为“RGBA”,则alpha通道被忽略。用户可以使用同样的图像作为原图像和模板图像

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    box=[300,300,400,400]
    im_crop =im.crop(box)
    r,g,b =im_crop.split()
    im.paste(im_crop, (200,200,300,300), r)
    im.show()

    这里写图片描述

    Putdata类

    im.putdata(data)
    im.putdata(data, scale, offset)

    从sequence对象中拷贝数据到当前图像,从图像的左上角(0,0)位置开始。变量scale和offset用来调整sequence中的值:

    pixel = value*scale + offset

    如果变量scale忽略,则默认为1.0。如果变量offset忽略,则默认为0.0。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    r, g, b = im.split()
    print(
    r.getpixel((0, 0)),
    r.getpixel((1, 0)),
    r.getpixel((2, 0)),
    r.getpixel((3, 0)),
    r.putdata([1, 2, 3, 4]),
    r.getpixel((0, 0)),
    r.getpixel((1, 0)),
    r.getpixel((2, 0)),
    r.getpixel((3, 0)),
    )

    这里写图片描述

    Resize类

    im.resize(size) ⇒ image
    im.resize(size, filter) ⇒ image

    返回改变尺寸的图像的拷贝。变量size是所要求的尺寸,是一个二元组:(width, height)。变量filter为NEAREST、BILINEAR、BICUBIC或者ANTIALIAS之一。如果忽略,或者图像模式为“1”或者“P”,该变量设置为NEAREST。在当前的版本中bilinear和bicubic滤波器不能很好地适应大比例的下采样(例如生成缩略图)。用户需要使用ANTIALIAS,除非速度比质量更重要。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    region = im.resize((400, 400))     ##重新设定大小
    region.show()

    很明显由于大小的重新设定,图片的显示效果有所转变,gakki依然美腻~
    设定大小

    Rotate类

    im.rotate(angle) ⇒ image
    im.rotate(angle,filter=NEAREST, expand=0) ⇒ image

    返回一个按照给定角度顺时钟围绕图像中心旋转后的图像拷贝。变量filter是NEAREST、BILINEAR或者BICUBIC之一。如果省略该变量,或者图像模式为“1”或者“P”,则默认为NEAREST。变量expand,如果为true,表示输出图像足够大,可以装载旋转后的图像。如果为false或者缺省,则输出图像与输入图像尺寸一样大。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    im_45 = im.rotate(45)
    im_30 = im.rotate(30, Image.NEAREST,1)
    print(im_45.size,im_30.size)
    im_45.show()
    im_30.show()

    这里写图片描述

    这里写图片描述

    Seek类

    im.seek(frame)

    在给定的文件序列中查找指定的帧。如果查找超越了序列的末尾,则产生一个EOFError异常。当文件序列被打开时,PIL库自动指定到第0帧上。

    @zhangziju
    from PIL import Image
    im_gif = Image.open("E:\mywife.gif")
    print(im_gif.mode)
    im_gif.show()    ##第0帧
    im_gif.seek(3)
    im_gif.show()
    im_gif.seek(9)
    im_gif.show()

    来来来~这是gakki原图欣赏下~

    这里写图片描述
    查找帧seek()的效果如下:

    这里写图片描述

    Tell类

    im.tell() ⇒ integer

    返回当前帧所处位置,从0开始计算。

    @zhangziju
    from PIL import Image
    im_gif = Image.open("E:\mywife.gif")
    print(im_gif.tell())
    im_gif.seek(8)
    print(im_gif.tell())

    这里写图片描述

    Thumbnail类

    im.thumbnail(size)
    im.thumbnail(size, filter)

    修改当前图像,使其包含一个自身的缩略图,该缩略图尺寸不大于给定的尺寸。这个方法会计算一个合适的缩略图尺寸,使其符合当前图像的宽高比,调用方法draft()配置文件读取器,最后改变图像的尺寸。变量filter应该是NEAREST、BILINEAR、BICUBIC或者ANTIALIAS之一。如果省略该变量,则默认为NEAREST。注意:在当前PIL的版本中,滤波器bilinear和bicubic不能很好地适应缩略图产生。用户应该使用ANTIALIAS,图像质量最好。如果处理速度比图像质量更重要,可以选用其他滤波器。这个方法在原图上进行修改。如果用户不想修改原图,可以使用方法copy()拷贝一个图像。这个方法返回空。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    im.thumbnail((100,100))

    Transform类

    im.transform(size,method, data) ⇒ image
    im.transform(size, method, data, filter) ⇒ image

    使用给定的尺寸生成一张新的图像,与原图有相同的模式,使用给定的转换方式将原图数据拷贝到新的图像中。在当前的PIL版本中,参数method为EXTENT(裁剪出一个矩形区域),AFFINE(仿射变换),QUAD(将正方形转换为矩形),MESH(一个操作映射多个正方形)或者PERSPECTIVE。变量filter定义了对原始图像中像素的滤波器。在当前的版本中,变量filter为NEAREST、BILINEAR、BICUBIC或者ANTIALIAS之一。如果忽略,或者图像模式为“1”或者“P”,该变量设置为NEAREST。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.size)
    imtra = im.transform((200, 200), Image.EXTENT, (0, 0, 500, 500))
    print(imtra.size)
    imtra.show()

    这里写图片描述

    这里写图片描述

    im.transform(size,EXTENT, data) ⇒ image
    im.transform(size, EXTENT, data, filter) ⇒ image

    从图像中裁剪一个区域。变量data为指定输入图像中两个坐标点的4元组(x0,y0,x1,y1)。输出图像为这两个坐标点之间像素的采样结果。例如,如果输入图像的(x0,y0)为输出图像的(0,0)点,(x1,y1)则与变量size一样。这个方法可以用于在当前图像中裁剪,放大,缩小或者镜像一个任意的长方形。它比方法crop()稍慢,但是与resize操作一样快。

    im.transform(size, AFFINE, data) ⇒ image
    im.transform(size, AFFINE,data, filter) ⇒ image

    对当前的图像进行仿射变换,变换结果体现在给定尺寸的新图像中。变量data是一个6元组(a,b,c,d,e,f),包含一个仿射变换矩阵的第一个两行。输出图像中的每一个像素(x,y),新值由输入图像的位置(ax+by+c, dx+ey+f)的像素产生,使用最接近的像素进行近似。这个方法用于原始图像的缩放、转换、旋转和裁剪。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.size)
    imtra = im.transform((200, 200), Image.AFFINE, (1,2,3,2,1,4))
    print(imtra.size)
    imtra.show()

    这里写图片描述
    这里写图片描述

    im.transform(size,QUAD, data) ⇒ image
    im.transform(size, QUAD, data, filter) ⇒ image

    输入图像的一个四边形(通过四个角定义的区域)映射到给定尺寸的长方形。变量data是一个8元组(x0,y0,x1,y1,x2,y2,x3,y3),它包括源四边形的左上,左下,右下和右上四个角。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.size)
    imtra = im.transform((200, 200), Image.QUAD, (0,0,0,500,600,500,600,0))
    print(imtra.size)
    imtra.show()

    这里写图片描述
    这里写图片描述

    im.transform(size,PERSPECTIVE, data) ⇒ image
    im.transform(size, PERSPECTIVE, data, filter) ⇒ image

    对当前图像进行透视变换,产生给定尺寸的新图像。变量data是一个8元组(a,b,c,d,e,f,g,h),包括一个透视变换的系数。对于输出图像中的每个像素点,新的值来自于输入图像的位置的(a x + b y + c)/(g x + h y + 1), (d x+ e y + f)/(g x + h y + 1)像素,使用最接近的像素进行近似。这个方法用于原始图像的2D透视。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    print(im.size)
    imtra = im.transform((200, 200), Image.PERSPECTIVE, (1,2,3,2,1,6,1,2))
    print(imtra.size)
    imtra.show()

    这里写图片描述
    wocao!!!gakki不见了!!!

    这里写图片描述

    Transpose类

    im.transpose(method)⇒ image

    返回当前图像的翻转或者旋转的拷贝。变量method的取值为:FLIP_LEFT_RIGHT,FLIP_TOP_BOTTOM,ROTATE_90,ROTATE_180,或ROTATE_270。

    @zhangziju
    from PIL import Image
    im = Image.open("E:\mywife.jpg")
    im.rotate(45)                             #逆时针旋转 45 度角。
    im.transpose(Image.FLIP_LEFT_RIGHT)       #左右对换。
    im.transpose(Image.FLIP_TOP_BOTTOM)       #上下对换。
    im.transpose(Image.ROTATE_90)             #旋转 90 度角。
    im.transpose(Image.ROTATE_180)            #旋转 180 度角。
    im.transpose(Image.ROTATE_270)            #旋转 270 度角。
    展开全文
  • python 图像处理

    2018-06-19 14:51:01
    转自:点击打开链接第 1 章 基本的图像操作和处理本章讲解操作和处理图像的基础知识,将通过大量...1.1 PIL:Python图像处理类库PIL(Python Imaging Library Python,图像处理类库)提供了通用的图像处理功能,以...
  • (Image模块方法16-25) 16、  Paste 定义1:im.paste(image,box) 含义1:将一张图粘贴到另一张图像上。变量box或者是一个给定左上角的2元组,或者是定义了左,上,右和下像素坐标的4元组,或者为空(与(0,0...
  • 图像处理中常见的概念有模式(mode)、通道(bands)、尺寸(size)、坐标系统(coordinate system)、调色板(palette)、信息(info)和滤波器(filters)。 模式(mode) 所谓图像模式就是把色彩分解成部分...
  • Image是pillow库中一个非常重要的模块,提供了大量用于图像处理的方法。使用该模块时,首先需要导入。>>> from PIL import Image接下来,我们通过几个示例来简单演示一下这个模块的用法。 (1)打开图像文件>>> im ...
  • 前面一篇文章我讲解了Python图像量化、采样处理及图像金字塔。本文主要讲解图像傅里叶变换的相关内容,在数字图像处理中,有两个经典的变换被广泛应用——傅里叶变换和霍夫变换。其中,傅里叶变换主要是将时间域上的...
  • 今天抽空学习了一下之前了解过的pillow库,以前看到的记得这个库可以给图片上加文字加数字,还可以将图片转化成字符画,不过一直没有找时间去学习一下这个模块,由于放假不用训练,所以就瞎搞了一下 0、...
  • import Image im = Image.open('test.png') ...im.save('thumb.jpg', 'JPEG')python的PIL库可以实现对图片的处理生成缩略图 thumbnail函数接受一个元组作为参数,分别对应着缩略图的宽高,在缩略时,函数会保持图
  • python图像处理】python的图像处理模块Image   版本信息:2.7.11 环境:windows 7 64位系统 编辑器:PyCharm 运行工具:PyCharm 文件地址:D:\phpStudy\WWW\python\Image 一、引入图像模块 1. PIL简介:...
  • Python图像处理

    2008-01-18 12:11:00
    Python图像处理 最近在做一件比较 evil 的事情——验证码识别,以此来学习一些新的技能。因为我是初学,对图像处理方面就不太了解了,欲要利吾事,必先利吾器,既然只是做一下实验,那用 Python 来作原型开发再...
  • Python中的图像处理

    2018-03-03 22:27:15
    第 1 章 基本的图像操作和处理本章讲解操作和处理图像的基础知识,将通过大量...1.1 PIL:Python图像处理类库PIL(Python Imaging Library Python,图像处理类库)提供了通用的图像处理功能,以及大量有用的基本图...
  • 提到图像处理第一个想到的库就是PIL,全称Python Imaging Library Python图像处理类库,它提供了大量的图像操作,比如图像缩放,裁剪,贴图,模糊等等,很多时候它需要配合numpy库一起使用 1.open() 你可以使用...
  • Python 图像处理详解

    2013-01-22 18:10:58
    Python图像处理  最近在做一件比较 evil 的事情——验证码识别,以此来学习一些新的技能。因为我是初学,对图像处理方面就不太了解了,欲要利吾事,必先利吾器,既然只是做一下实验,那用 Python 来作原型...
  • Image模块 Image模块是在Python PIL图像处理中常见的模块,对图像进行基础操作的功能基本都包含于此模块内。如open、save、conver、show…等功能。...记录一个值得学习的链接:Python图像处理PIL各模块详细介绍 ...
  • 文章目录Pillow模块讲解一、Image模块1.1 、打开图片和显示图片1.2、创建一个简单的图像1.3、图像混合(1)透明度混合(2)遮罩混合1.4、图像缩放(1)按像素缩放(2)按尺寸缩放1.5、图像的剪切与粘贴(1)图像粘贴...
  • Python图像处理库PIL的Image模块介绍(一) Python图像处理库PIL的Image模块介绍(二) Python图像处理库PIL的Image模块介绍(三) Python图像处理库PIL的Image模块介绍(四) Python图像处理库PIL的Image模块介绍...
1 2 3 4 5 ... 20
收藏数 37,601
精华内容 15,040