PIL基础

Wesley13
• 阅读 607

PIL官方文档:

http://effbot.org/imagingbook/

一、PIL(Python Imaging Library)的基本概念

PIL中所涉及的基本概念有如下几个:通道(bands)、模式(mode)、尺寸(size)、坐标系统(coordinate system)、调色板(palette)、信息(info)和滤波器(filters)。

1、通道

每张图片都是由一个。或者多个数据通道构成。PIL允许在单张图片中合成相同维数和深度的多个通道。

以RGB图像为例,每张图片都是由三个数据通道构成,分别为R、G和B通道。而对于灰度图像,则只有一个通道。

2、模式

图像的模式定义了图像的类型和像素的位宽。当前支持如下模式:

1:1位像素,表示黑和白,但是存储的时候每个像素存储为8bit。

L:8位像素,表示黑和白。

P:8位像素,使用调色板映射到其他模式。

RGB:3x8位像素,为真彩色。

RGBA:4x8位像素,有透明通道的真彩色。

CMYK:4x8位像素,颜色分离。

YCbCr:3x8位像素,彩色视频格式。

I:32位整型像素。

F:32位浮点型像素。

PIL也支持一些特殊的模式,包括RGBX(有padding的真彩色)和RGBa(有自左乘alpha的真彩色)。

3、尺寸

通过size属性可以获取图片的尺寸。这是一个二元组,包含水平和垂直方向上的像素数。

4、坐标系统

PIL使用笛卡尔像素坐标系统,坐标(0,0)位于左上角。注意:坐标值表示像素的角;位于坐标(0,0)处的像素的中心实际上位于(0.5,0.5)。

坐标经常用于二元组(x,y)。长方形则表示为四元组,前面是左上角坐标。例如,一个覆盖800x600的像素图像的长方形表示为(0,0,800,600)。

5、调色板

调色板模式 ("P")使用一个颜色调色板为每个像素定义具体的颜色值

6、信息

使用info属性可以为一张图片添加一些辅助信息。这个是字典对象。加载和保存图像文件时,多少信息需要处理取决于文件格式。

7、滤波器

对于将多个输入像素映射为一个输出像素的几何操作,PIL提供了4个不同的采样滤波器:

NEAREST:最近滤波。从输入图像中选取最近的像素作为输出像素。它忽略了所有其他的像素。

BILINEAR:双线性滤波。在输入图像的2x2矩阵上进行线性插值。注意:PIL的当前版本,做下采样时该滤波器使用了固定输入模板。

BICUBIC:双立方滤波。在输入图像的4x4矩阵上进行立方插值。注意:PIL的当前版本,做下采样时该滤波器使用了固定输入模板。

ANTIALIAS:平滑滤波。这是PIL 1.1.3版本中新的滤波器。对所有可以影响输出像素的输入像素进行高质量的重采样滤波,以计算输出像素值。在当前的PIL版本中,这个滤波器只用于改变尺寸和缩略图方法。

注意:在当前的PIL版本中,ANTIALIAS滤波器是下采样(例如,将一个大的图像转换为小图)时唯一正确的滤波器。BILIEAR和BICUBIC滤波器使用固定的输入模板,用于固定比例的几何变换和上采样是最好的。

二、PIL模块中常用的类

PIL模块中常用的最重要的类是Image类,需要在程序中引入Image。Image常用的方法有:

Open():打开一张图片,方法内需传入图片的名称,即:路径+文件名.后缀名,例如:Image.open(“pic14.jpg”),open()方法会返回一个Image对象,我们可以使用Image的方法来获取该对象的属性。

对象名.format():获取图像的格式,如:jpg,jpeg,ppm等。

对象名.size:获取图像的大小尺寸

对象名.mode:获取图像的颜色属性,灰度图或RGB

对象名.show():将图片显示出来

对象名.save(arg1,arg2):将图片保存,arg1是图片保存的名称,即:路径+文件名,arg2是图片保存的格式。

对象名.crop(arg):截取图片的某一部分,参数arg是一个元组类型的变量,形式为:(left,upper,right,lower)。在PIL的坐标系中,图片的左上角是坐标系的原点。这里的(left,upper,right,lower)代表的是截取部分的坐标,用(left,upper)坐标表示截取区域的左上角点,用(right,lower)坐标代表截取区域的右下角点,这样的话,区域的位置和大小就都确定了。

对象名.split():将图片的几个通道分开,例如:r,g,b=im.split()

Image.merge(“RGB”,(b,g,r)):将图片的通道分开后重新组合得到一张新的图片。

三、案例代码

1、打开一张图片,然后显示并获取图片的尺寸大小,并生成缩略图

代码:

import os, sys
from PIL import Image,ImageFilter,ImageDraw
im=Image.open("pic01.jpg")
im.show()
xsize,ysize=im.size
im.thumbnail((xsize//2,ysize//2))
im.save("thumb_pic01.jpg","JPEG")

程序结果:

(1024, 638)

程序会使用系统默认的图片查看器将图片显示出来,并以二元组的形式将图片的尺寸打印出来。在生成缩略图时,需要将缩略图的尺寸以元组的形式传入,然后保存。

2、将图片旋转90°并保存

代码:

import os, sys
from PIL import Image,ImageFilter,ImageDraw
im = Image.open("pic01.jpg")
im=im.resize((im.size[0]//2,im.size[1]//2))
out=im.rotate(90).save("pic01_rotate_90.jpg")

程序结果:

程序运行结果:将rotate方法返回的图片以指定的名称存储起来,打开图片发现图片被裁剪了。也可以使用transpose()方法对图片进行上下翻转、左右翻转,旋转等操作。示例如下:

import os, sys
from PIL import Image,ImageFilter,ImageDraw
im = Image.open("pic01.jpg")
out=im.transpose(Image.FLIP_LEFT_RIGHT)#将图片进行左右翻转操作
out.show()
out=im.transpose(Image.FLIP_TOP_BOTTOM)#将图片进行上下翻转操作
out.show()
out=im.transpose(Image.ROTATE_180)#将图片旋转180°
out.show()

3、 截取图片并实现将图片沿着某一方向滑动的效果

首先我们需要定义一个函数以实现让图片沿着x方向滑动,代码如下:

import os, sys
from PIL import Image,ImageFilter,ImageDraw
def roll_x_side(image, delta):
        "Roll an image sideways"
        xsize, ysize = image.size
        delta = delta % xsize
        if delta == 0: return image
        part1 = image.crop((0, 0, delta, ysize))
            part2 = image.crop((delta, 0, xsize, ysize))
        image.paste(part2, (0, 0, xsize-delta, ysize))
        image.paste(part1, (xsize-delta, 0, xsize, ysize)
        return image

在这里我们指定了滑动的距离。然后使用了crop方法,将要截取区域的左上角顶点的坐标和右下角顶点的坐标以一个四元组的形式传入该方法,crop()方法会返回该区域的图片。在获取需要截取的区域后,再将该区域粘贴到滑动后的区域。这样就实现了沿着x轴的滑动。实现沿着y轴滑动的函数与之类似,代码如下:

def roll_y_side(image, delta):
        "Roll an image sideways"
        xsize, ysize = image.size
        delta = delta % ysize
        if delta == 0: return image
        part1 = image.crop((0, 0, xsize, delta))
           part2 = image.crop((0, delta, xsize, ysize))
        image.paste(part2, (0, 0, xsize, ysize-delta))
        image.paste(part1, (0, ysize-delta, xsize, ysize))
        return image

完整的代码如下:

import os, sys
from PIL import Image,ImageFilter,ImageDraw
def roll_x_side(image, delta):
        "Roll an image sideways"
        xsize, ysize = image.size
        delta = delta % xsize
        if delta == 0: return image
        part1 = image.crop((0, 0, delta, ysize))
            part2 = image.crop((delta, 0, xsize, ysize))
        image.paste(part2, (0, 0, xsize-delta, ysize))
        image.paste(part1, (xsize-delta, 0, xsize, ysize)
        return image
def roll_y_side(image, delta):
        "Roll an image sideways"
        xsize, ysize = image.size
        delta = delta % ysize
        if delta == 0: return image
        part1 = image.crop((0, 0, xsize, delta))
           part2 = image.crop((0, delta, xsize, ysize))
        image.paste(part2, (0, 0, xsize, ysize-delta))
        image.paste(part1, (0, ysize-delta, xsize, ysize))
        return image
im = Image.open("pic01.jpg")
im_01=roll_x_side(im,300)
im_01.save("pic01_x_roll.jpg")
im_01.show()
im_02=roll_y_side(im,300)
im_02.save("pic01_y_roll.jpg")
im_02.show()

4、 将彩色图片分开成单个通道再合并

代码:

im=Image.open("pic01.jpg")
im.show()
r, g, b = im.split()
r.show()
g.show()
b.show()_#_将这几个单通道的图片重新组合成一张新的图片
im = Image.merge("RGB", (b, r, g))
im.show()

5、 颜色变换:将彩色图片转换为灰度图

代码:

im = Image.open("pic01.jpg")
im.show()
out=im.convert("L")#将RGB格式的图片转换为灰度图
out.show()
print(out.mode,out.format,out.size)

6、 图像滤波

代码:

im = Image.open("pic01.jpg")
out=im.filter(ImageFilter.DETAIL)#细节增强
out.show()
out=im.filter(ImageFilter.BLUR)#模糊化
out.show()
out=im.filter(ImageFilter.CONTOUR)#轮廓滤波,将图片的轮廓提取出来
out.show()
out=im.filter(ImageFilter.EDGE_ENHANCE)#边缘强化
out.show()
out=im.filter(ImageFilter.EDGE_ENHANCE_MORE)#深度边缘增强滤波,会使得图像中边缘部分更加明显
out.show()
out=im.filter(ImageFilter.EMBOSS)#浮雕滤波,会使图像呈现出浮雕效果
out.show()
out=im.filter(ImageFilter.SMOOTH)#平滑滤波
out.show()
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这