pillow常用功能,及验证码实现
一、创建图形:
1. Image.new(mode, size, color=0):创建一个空白图片
mode参数:
1:1位像素,表示黑和白,但是存储的时候每个像素存储为8bit。
L:8位像素,表示黑和白。
P:8位像素,使用调色板映射到其他模式。
RGB:3x8位像素,为真彩色。
RGBA:4x8位像素,有透明通道的真彩色。
CMYK:4x8位像素,颜色分离。
YCbCr:3x8位像素,彩色视频格式。
I:32位整型像素。
F:32位浮点型像素。
PIL也支持一些特殊的模式,包括RGBX(有padding的真彩色)和RGBa(有自左乘alpha的真彩色)。
size参数:
size属性定义或获取图片的尺寸。这是一个二元组,包含水平和垂直方向上的像素数。
color参数:
对于单通道图像,变量color只给定一个值;对于多通道图像,变量color给定一个元组(每个通道对应一个值)。
在版本1.1.4及其之后,用户也可以用颜色的名称,比如给变量color赋值为“red”。
如果没有对变量color赋值,图像内容将会被全部赋值为0(图像即为黑色)。
如果变量color是空,图像将不会被初始化,即图像的内容全为0。
from PIL import Image im= Image.new("RGB", (128, 128), "#FF0000") im.save("test1.png") #图像im为128x128大小的红色图像。 im= Image.new("RGB", (128, 128)) #图像im为128x128大小的黑色图像,因为变量color不赋值的话,图像内容被设置为0,即黑色。 im.save("test2.png") im= Image.new("RGB", (128, 128), "red") #图像im为128x128大小的红色图像。 im.save("test3.png") #保存图片到本地
显示图像:
im.show()
2. Image.frombuffer():使用标准的“raw”解码器,从字符串或者buffer对象中的像素数据创建一个图像
定义:Image.frombuffer(mode,size, data) ⇒ image
Image.frombuffer(mode, size,data, decoder, parameters) ⇒ image
对于一些模式,这个图像存储与原始的buffer(这意味着对原始buffer对象的改变体现在图像本身)共享内存。
并非所有的模式都可以共享内存;支持的模式有“L”,“RGBX”,“RGBA”和“CMYK”。对于其他模式,这个函数与fromstring()函数一致。
3.Image.fromstring():使用标准的“raw”解码器,从字符串的像素数据创建一个图像
定义:Image.fromstring(mode,size, data) ⇒ image
Image.fromstring(mode, size,data, decoder, parameters) ⇒ image
二、图像操作
1.打开一个已经存在的图片
1).使用open(file, mode)打开图片,和打开文件一样,得到一个文件对象。略
2)使用Image.open(file)打开图片,得到一个PIL的Image类对象。
img = Image.open("test3.png") print(img.mode) # "RGB" print(img.size) # (670, 502)
2.合并图片:blend
定义:Image.blend(image1,image2, alpha) ⇒ image
含义:
- 使用给定的两张图像及透明度变量alpha,插值出一张新的图像。这两张图像必须有一样的尺寸和模式。
- 合成公式为:out = image1 *(1.0 - alpha) + image2 * alpha
- 如果变量alpha为0.0,将返回第一张图像的拷贝。如果变量alpha为1.0,将返回第二张图像的拷贝。对变量alpha的值没有限制。
from PIL import Image im1 = Image.open("jing.jpg") im2 = Image.open("wu.jpg") im = Image.blend(im1,im2,0.5) im.save("he.jpg")
3.合并图片:composite
定义:Image.composite(image1,image2, mask) ⇒ image
含义:使用给定的两张图像及mask图像作为透明度,插值出一张新的图像。变量mask图像的模式可以为“1”,“L”或者“RGBA”。所有图像必须有相同的尺寸。
from PIL import Image im1 = Image.open("jing.jpg") im2 = Image.open("wu.jpg") r,g,b = im1.split() print(g.mode) im = Image.composite(im1,im2,b) im.save("he.jpg") b.save("he1.jpg")
from PIL import Image im = Image.open("jing.jpg") def deffun(c): return c*0.89 #改变了亮度 im_eval = Image.eval(im,deffun) im_eval.save("gai.jpg") #注:图像im_eval与im01比较,其像素值均为im01的一半,则其亮度自然也会比im01暗一些。
4.合并图片:merge
定义:Image.merge(mode,bands) ⇒ image
含义:使用一些单通道图像,创建一个新的图像。
变量bands为一个图像的元组或者列表,每个通道的模式由变量mode描述。
所有通道必须有相同的尺寸。
变量mode与变量bands的关系: len(ImageMode.getmode(mode).bands)= len(bands)
from PIL import Image im1 = Image.open("jing.jpg") im2 = Image.open("wu.jpg") r1,g1,b1 = im1.split() r2,g2,b2 = im2.split() imgs =[r1,g2,b2] im_merge = Image.merge("RGB",imgs) im_merge.save("he.jpg")
其它方法:convert、copy、draft、filter、fromstring、getbands、getbbox、getcolors、getdata、getextrema、getpixel、histogram、load、paste..........
三、ImageFont模块的函数
1.加载字体对象:ImageFont.load(file)⇒ Font instance
从指定的文件中加载一种字体,该函数返回对应的字体对象。如果该函数失败,将产生IOError异常。
2.加载字体对象:ImageFont.load(file)⇒ Font instance
和函数load()一样,但是如果没有指定当前路径的话,会从sys.path开始查找指定的字体文件。
3.创建字体对象:
定义1:ImageFont.truetype(file,size) ⇒ Font instance
加载一个TrueType或者OpenType字体文件,并且创建一个字体对象。
这个函数从指定的字体类型(对应字体文件)加载了一个字体对象,并且为指定大小的字体创建了字体对象。
定义2:ImageFont.truetype(file,size, encoding=value) ⇒ Font instance
通常的编码方式有“unic”(Unicode),“symb”(Microsoft Symbol),“ADOB”(Adobe Standard),“ADBE”(Adobe Expert)和“armn”(Apple Roman)。
4.ImageFont.load_default()⇒ Font instance
加载一个默认的字体
5.font.getsize(text)⇒ (width, height) 返回给定文本的宽度和高度,返回值为2元组。
6.font.getmask(text,mode=”“) ⇒ Image object 为给定的文本返回一个位图
四、图形扭曲:
定义1:Img.transform(size, method, data)
定义2:img.transform(size, method, data, filter) ⇒ image
参数说明:
size:一个二元组,变换后图片的宽度和高度
method:变换的方式
- Image.EXTENT(从原图中裁剪出一个矩形区域),这个方法可以用于在当前图像中裁剪,放大,缩小或者镜像一个任意的长方形。此时data为指定输入图像中两个坐标点的4元组(x0,y0,x1,y1)
- Image.AFFINE(仿射变换),这个方法用于原始图像的缩放、转换、旋转和裁剪。此时data为一个6元组(a,b,c,d,e,f),包含一个仿射变换矩阵的第一个两行。输出图像中的每一个像素(x,y),新值由输入图像的位置(ax+by+c, dx+ey+f)的像素产生,使用最接近的像素进行近似。
- Image.QUAD(将正方形转换为矩形),输入图像的一个四边形(通过四个角定义的区域)映射到给定尺寸的长方形。data为一个8元组(x0,y0,x1,y1,x2,y2,x3,y3),它包括源四边形的左上,左下,右下和右上四个角。
- Image.MESH(一个操作映射多个正方形),与QUAD类似,但是变量data是目标长方形和对应源四边形的list。
- Image.PERSPECTIVE,对当前图像进行透视变换,产生给定尺寸的新图像。这个方法用于原始图像的2D透视。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)像素,使用最接近的像素进行近似。
filter:定义了对原始图像中像素的滤波器。
NEAREST、BILINEAR、BICUBIC或者ANTIALIAS之一。
如果忽略,或者图像模式为“1”或者“P”,该变量设置为NEAREST。
methd:Image.EXTENT 示例
from PIL import Image img01 = Image.open("timg.jpeg") print(img01.mode) # "RGB" print(img01.size) # (550,404) trans1 = img01.transform((300,300),Image.EXTENT,(0,0,600,600)) print(trans1.size) # (300,300) trans1.show()
methd:Image.AFFINE 示例
trans2 = img01.transform((300,300), Image.AFFINE,(1,2,3,2,1,4))
method:Image.QUAD示例
trans3 = img01.transform((300,300), Image.QUAD, (0,0,0,500,600,500,600,0))
method:Image.Mesh
method:Image.PERSPECTIVE示例
trans5 = img01.transform((300,300), Image.PERSPECTIVE, (1,2,3,2,1,6,1,2))
翻转或者旋转图形,返回新的图形:img.transpose(method) => image
method的取值为:FLIP_LEFT_RIGHT,FLIP_TOP_BOTTOM,ROTATE_90,ROTATE_180,或者ROTATE_270
t = img01.transpose(Image.FLIP_TOP_BOTTOM)
五、图像滤波:img.filter(imagFilter)
图像滤波:在图像处理中,经常需要对图像进行平滑、锐化、边界增强等滤波处理。
imageFilter参数:
• BLUR:模糊滤波
• CONTOUR:轮廓滤波
• DETAIL:细节滤波
• EDGE_ENHANCE:边界增强滤波
• EDGE_ENHANCE_MORE:边界增强滤波(程度更深)
• EMBOSS:浮雕滤波
• FIND_EDGES:寻找边界滤波
• SMOOTH:平滑滤波
• SMOOTH_MORE:平滑滤波(程度更深)
• SHARPEN:锐化滤波
• GaussianBlur(radius=2):高斯模糊 ,radius指定平滑半径
• UnsharpMask(radius=2, percent=150, threshold=3):反锐化掩码滤波
- radius指定模糊半径;
- percent指定反锐化强度(百分比);
- threshold控制被锐化的最小亮度变化。
• Kernel(size, kernel, scale=None, offset=0):核滤波
当前版本只支持核大小为3x3和5x5的核大小,且图像格式为“L”和“RGB”的图像。
- size指定核大小(width, height);
- kernel指定核权值的序列;
- scale指定缩放因子;
- offset指定偏移量,如果使用,则将该值加到缩放后的结果上。
• RankFilter(size, rank):排序滤波
- size指定滤波核的大小;
- rank指定选取排在第rank位的像素,若大小为0,则为最小值滤波;若大小为size * size / 2则为中值滤波;若大小为size * size - 1则为最大值滤波。
• MedianFilter(size=3):中值滤波,size指定核的大小
• MinFilter(size=3):最小值滤波器,size指定核的大小
• MaxFilter(size=3):最大值滤波器,size指定核的大小
• ModeFilter(size=3):波形滤波器,size指定核的大小
选取核内出现频次最高的像素值作为该点像素值,仅出现一次或两次的像素将被忽略,若没有像素出现两次以上,则保留原像素值。
from PIL import ImageFilter f1 = img01.filter(ImageFilter.BLUR) f2 = img01.filter(ImageFilter.CONTOUR) f3 = img01.filter(ImageFilter.MinFilter(3))
f3 = img01.filter(ImageFilter.EDGE_ENHANCE_MORE)
六、使用PIL生成验证码图片
draw.text((x0,y0), string, fill):写入字符串,第一个参数是一个二元组的起始坐标点,第二个参数是要写入的字符串
draw.text((x0,y0), string, fill,font=font):写入特殊字体的字符串;font字体可选,如选,则是特殊字体
draw.point((x0,y0), fill):画点,第一个参数是一个二元组坐标(1个点),第二个参数,填充颜色
draw.line((x0,y0,x1,y1), 开始角度,结束角度,fill):画线,第一个参数是一个四元组的坐标(2个点)
1.创建图形:
size = (240, 60)
width, height = size
img = Image.new("RGB", size, (238, 99, 99))
2.创建画笔:
from PIL import ImageDraw draw = ImageDraw.Draw(img)
3.使用画笔,绘制干扰线,如果需要:
import random line_num = random.randint(2, 4) # 干扰线条数 for i in range(line_num): # 起始点 begin = (random.randint(0, size[0]), random.randint(0, size[1])) # 结束点 end = (random.randint(0, size[0]), random.randint(0, size[1])) draw.line([begin, end], fill=(0, 0, 0))
4.使用画笔,绘制干扰点,如果需要:
point_chance = 2 # 干扰点出现的概率 for w in range(width): for h in range(height): tmp = random.randint(0, 100) if tmp > 100 - point_chance: # 概率2% draw.point((w, h), fill=(0, 0, 0))
5.使用画笔,绘制验证字符:
_letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z _upper_cases = _letter_cases.upper() # 大写字母 _numbers = ''.join(map(str, range(3, 10))) # 数字 init_chars = ''.join((_letter_cases, _upper_cases, _numbers)) length = 4 #验证码字符数 c_chars = random.sample(init_chars, length) # 随机获取4个字符 strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开 font = ImageFont.load_default() # 获取字体对象 font_width, font_height = font.getsize(strs) # 返回给定文本的宽度和高度 draw.text(((width - font_width) / 3, (height - font_height) / 3), strs, font=font, fill=(0,0,255)) # 绘制验证码:width、height图片的宽度和高度
6.图形扭曲:
# 图形扭曲参数 data = [1 - float(random.randint(1, 2)) / 100, 0, 0, 0, 1 - float(random.randint(1, 10)) / 100, float(random.randint(1, 2)) / 500, 0.001, float(random.randint(1, 2)) / 500 ] img = img.transform(size, Image.PERSPECTIVE, data) # 扭曲图形,得到新的图形
7.滤波处理:
img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,EDGE_ENHANCE_MORE:边界加强(阈值更大)
验证码,代码整合:
import random from PIL import Image, ImageDraw, ImageFont, ImageFilter _letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z _upper_cases = _letter_cases.upper() # 大写字母 _numbers = ''.join(map(str, range(3, 10))) # 数字,去除可能干扰的1,2 init_chars = ''.join((_letter_cases, _upper_cases, _numbers)) def check_code(width=120, height=30, char_length=4, font_file='Ubuntu-BI.ttf', font_size=28): code = [] img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255)) draw = ImageDraw.Draw(img, mode='RGB') def rndChar(): """ 生成随机字母 :return: """ # return chr(random.randint(65, 90)) return random.sample(init_chars, 1)[0] def rndColor(): """ 生成随机颜色 :return: """ return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255)) # 写文字 font = ImageFont.truetype(font_file, font_size) # 使用默认字体 font = ImageFont.load_default() for i in range(char_length): char = rndChar() code.append(char) h = random.randint(0, 4) draw.text([i * width / char_length, h], char, font=font, fill=rndColor()) # 写干扰点 point_chance = 20 # 干扰点出现的概率 for i in range(40): if random.randint(0, 100) < point_chance: draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor()) # 写干扰圆圈 arc_chance = 5 # 干扰圆圈出现的概率 for i in range(40): if random.randint(0, 100) < arc_chance: draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor()) x = random.randint(0, width) y = random.randint(0, height) draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor()) # 画干扰线 for i in range(5): x1 = random.randint(0, width) y1 = random.randint(0, height) x2 = random.randint(0, width) y2 = random.randint(0, height) draw.line((x1, y1, x2, y2), fill=rndColor()) # # # 图形扭曲参数 # params = [1 - float(random.randint(1, 2)) / 100, # 0, # 0, # 0, # 1 - float(random.randint(1, 10)) / 100, # float(random.randint(1, 2)) / 500, # 0.001, # float(random.randint(1, 2)) / 500 # ] # # 扭曲图片 # img = img.transform((width, height), Image.PERSPECTIVE, params) # 滤波 img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) return img, ''.join(code) if __name__ == '__main__': # # 1. 直接打开 # img,code = check_code() # img.show() # 2. 写入文件 # img,code = check_code() # with open('code.png','wb') as f: # img.save(f,format='png') # 3. 写入内存(Python3) from io import BytesIO stream = BytesIO() img, code = check_code() img.save(stream, 'png') stream.getvalue() img.show() # 4. 写入内存(Python2) # import StringIO # stream = StringIO.StringIO() # img, code = check_code() # img.save(stream, 'png') # stream.getvalue()
posted on 2018-11-08 15:12 myworldworld 阅读(1017) 评论(0) 收藏 举报
浙公网安备 33010602011771号