PIL:Python Imaging Library,是Python平台事实上的图像处理标准库了。但是PIL仅支持到Python 2.7,加上年久失修,于是一群志愿者在PIL的基础上创建了兼容的版本,名字叫Pillow,支持最新Python 3.x。
下面来介绍如何安装及使用Pillow库。
安装
pip install pillow
在安装后通过在python控制台中输入"import PIL"命令可以验证是否成功安装
使用Pillow
1、读取图像
pillow的Image模块读取图像文件后得到的是PIL类型的image文件
import requests
from io import BytesIO
from PIL import Image
import matplotlib.pyplot as plt
#========================================================
# 加载图片
#========================================================
def read_image(path, mode='RGB'):
'''
加载本地单张图片
INPUT -> 单张图片路径, 特殊模式
OUTPUT -> 单张图文件
'''
pil_im = Image.open(path)
if mode == '1':
# 非黑即白模式: 0表示黑, 255表示白
return pil_im.convert('1')
elif mode == 'L':
# 灰色模式: 0表示黑,255表示白,其他数字表示不同的灰度。转换算法 L = R * 299/1000 + G * 587/1000+ B * 114/1000
return pil_im.convert('L')
elif mode == 'RGB':
return pil_im.convert('RGB')
def read_net_image(url, mode='RGB'):
'''
加载网络单张图片
INPUT -> 单张图片网址, 特殊模式
OUTPUT -> 单张图文件
'''
pil_im = Image.open(BytesIO(requests.get(url).content))
if mode == '1':
return pil_im.convert('1')
elif mode == 'L':
return pil_im.convert('L')
elif mode == 'RGB':
return pil_im
img=read_image('test.png', 'RGB')
plt.axis('off') # 不显示坐标轴
plt.imshow(img)
plt.show()
查看PIL类型的image文件的信息
print(pil_im.size) #图片的尺寸
print(type(img))
print(pil_im.mode) #图片的模式
print(pil_im.format) #图片的格式
获得某点像素用getpixel((w, h))可以直接返回这个点三个通道的像素值(Pillow采取左上角为(0,0)的坐标系统)
#得到像素:
print(pil_im.getpixel((100,200)))
2、保存图像
img.save('test.jpg')
这行代码不仅能保存图片,还是转换格式,如本例中,就由原来的png图片保存为了jpg图片。
3、像素访问
from PIL import Image
from PIL import ImageColor
'''200×200的透明正方形'''
img = Image.new('RGBA', (200, 200))
'''遍历上半部份的所有像素'''
for x in range(200):
for y in range(100):
'''设置每个像素的颜色'''
img.putpixel((x, y), (255,255,255))
for x in range(200):
for y in range(100,200):
'''假定不知道RGB元组,必须使用ImageColor.getcolor()'''
img.putpixel((x, y), ImageColor.getcolor('darkgray', 'RGBA'))
img.save('putpixel.png')
4、通道分离与合并
r,g,b=img.split() #分离三通道
pic=Image.merge('RGB',(r,g,b)) #合并三通道
5、裁剪图片
def image_clip(pil_im, x, y, width, height):
'''
从一张图片中截取某个区域
INPUT -> 单张图文件, 坐标点x, 坐标点y, 目标宽度, 目标高度
OUTPUT -> 截取后的图片
'''
im_w, im_h = pil_im.size
x2 = x + width
y2 = y + height
if x + width > im_w:
x2 = im_w
if y + height > im_h:
y2 = im_h
box = (x, y, x2, y2)
region = pil_im.crop(box)
return region
6、刚体几何变换
图像的放缩
def image_resize1(pil_im, dst_w, dst_h):
'''
使一张图片变换尺寸(非等比例)(指定宽高)
INPUT -> 单张图文件, 目标宽度, 目标高度
OUTPUT -> 处理后的图片
'''
return pil_im.resize((dst_w, dst_h))
def image_resize_proportionally1(pil_im, c):
'''
使一张图片变换尺寸(等比例)(倍数缩放)
INPUT -> 单张图文件, 目标宽度, 目标高度
OUTPUT -> 处理后的图片
'''
height, width = pil_im.size
dst_w = height*c
dst_h = width*c
return pil_im.resize((dst_w, dst_h))
def image_resize_proportionally2(pil_im, dst_w, dst_h):
'''
使一张图片变换尺寸(等比例)
INPUT -> 单张图文件, 目标宽度, 目标高度
OUTPUT -> 处理后的图片
'''
ori_w, ori_h = pil_im.size
widthRatio = heightRatio = None
ratio = 1
if (ori_w and ori_w > dst_w) or (ori_w and ori_h > dst_h):
if (ori_w > dst_w):
widthRatio = float(dst_w) / ori_w # 获取宽度缩放比例
if (ori_h > dst_h):
heightRatio = float(dst_h) / ori_h # 获取高度缩放比例
if widthRatio and heightRatio:
if widthRatio < heightRatio:
ratio = widthRatio
else:
ratio = heightRatio
if widthRatio and not heightRatio:
ratio = widthRatio
if heightRatio and not widthRatio:
ratio = heightRatio
newWidth = int(ori_w * ratio)
newHeight = int(ori_h * ratio)
else:
newWidth = ori_w
newHeight = ori_h
return pil_im.resize((newWidth,newHeight), Image.ANTIALIAS)
图像的旋转
def image_rotate(pil_im, angle, clockwise=False):
'''
使一张图片旋转
INPUT -> 单张图文件, 旋转角度, 旋转方向(默认逆时针)
OUTPUT -> 旋转后的图文件
'''
if clockwise:
angle = 360 - int(angle)
pil_im = pil_im.rotate(angle, expand=True) # expand参数如果设为True,就会放大图像的尺寸,以适应整个旋转后的新图像
else:
pil_im = pil_im.rotate(angle, expand=True)
return pil_im
7、图像加水印
from PIL import ImageDraw, ImageFont, ImageEnhance
def image_watermark_logo(ori_im, mark_im):
'''
给一张图片加上图片水印
INPUT -> 原始图片, 水印图片, 透明度
OUTPUT -> 处理后的图片
'''
ori_w, ori_h = ori_im.size
mark_w, mark_h = mark_im.size
# 图层
dst_im = Image.new('RGBA', ori_im.size, (255,255,255,0)) # 设置图片尺寸和透明度
dst_im.paste(mark_im, (ori_w-mark_w, ori_h-mark_h))
# 覆盖
dst_im = Image.composite(dst_im, ori_im, dst_im)
return dst_im
def image_watermark_text(ori_im, fontpath, text=''):
'''
给一张图片加上文字水印
INPUT -> 原始图片, 字体路径, 文本
OUTPUT -> 处理后的图片
'''
ori_im = ori_im.convert('RGBA')
ori_w, ori_h = ori_im.size
# 文本遮罩层
text_overlay = Image.new('RGBA', ori_im.size, (255,255,255,0))
image_draw = ImageDraw.Draw(text_overlay)
# 获取文本大小
fnt = ImageFont.truetype(fontpath, 20)
text_size_x, text_size_y = image_draw.textsize(text, font=fnt)
# 设置文本位置
text_xy = (ori_w-text_size_x, ori_h-text_size_y)
# 设置文本颜色和透明度
image_draw.text(text_xy, text, font=fnt, fill=(255,255,255,50))
# 覆盖
dst_im = Image.alpha_composite(ori_im, text_overlay)
return dst_im
8、图像标识框
def image_tag(pil_im, x1, y1, x2, y2):
'''
在图片上标记矩形框
INPUT -> 单张图文件, 对角点坐标(PIL使用笛卡尔像素坐标系统,坐标(0,0)位于左上角)
OUTPUT -> 绘制后的图文件
'''
canvas = ImageDraw.Draw(pil_im)
canvas.line([(x1, y1), (x2, y1), (x2, y2), (x1, y2), (x1, y1)], fill='red')
return canvas
9、使用图像滤镜
ImageFilter是PIL的滤镜模块,通过这些预定义的滤镜,可以方便的对图片进行一些过滤操作,从而去掉图片中的噪音(部分的消除),这样可以降低将来处理的复杂度(如模式识别等)。
ImageFilter.BLUR 模糊滤镜
ImageFilter.CONTOUR 轮廓
ImageFilter.EDGE_ENHANCE 边界加强
ImageFilter.EDGE_ENHANCE_MORE 边界加强(阀值更大)
ImageFilter.EMBOSS 浮雕滤镜
ImageFilter.FIND_EDGES 边界滤镜
ImageFilter.SMOOTH 平滑滤镜
ImageFilter.SMOOTH_MORE 平滑滤镜(阀值更大)
ImageFilter.SHARPEN 锐化滤镜
要使用PIL的滤镜功能,需要引入ImageFilter模块
from import ImageFilter
def filterDemo():
img = Image.open("sandstone_half.jpg")
imgfilted = img.filter(ImageFilter.SHARPEN)
imgfilted.save("sandstone_sharpen.jpg")
10、PIL Image图像与numpy数组互转
前面的一些例子中,我们都是利用Image.open()来打开一幅图像,然后直接对这个PIL对象进行操作。如果只是简单的操作还可以,但是如果操作稍微复杂一些,就比较吃力了。因此,通常我们加载完图片后,都是把图片转换成矩阵来进行更加复杂的操作。
#========================================================
# 图像数组化与还原
#========================================================
def image_to_array(pil_im):
'''
图片转化为数组
INPUT -> 单张图文件
OUTPUT -> 数组
'''
return np.array(pil_im, 'f')
def array_to_image(image_arr):
'''
数组还原为图片
INPUT -> 数组
OUTPUT -> 单张图文件
'''
if len(image_arr.shape) == 3: # 格式为(height(rows), weight(colums), 3)
r = Image.fromarray(np.uint8(image_arr[:,:,0]))
g = Image.fromarray(np.uint8(image_arr[:,:,1]))
b = Image.fromarray(np.uint8(image_arr[:,:,2]))
image = Image.merge("RGB", (r, g, b))
return image
elif len(image_arr.shape) == 2: # 格式为(height(rows), weight(colums))
return Image.fromarray(np.uint8(image_arr))