Python常用模块之PIL

之前人工智能大作业需要用到KerasApplications中的预训练模型VGG16VGG16接收的图片大小至少是48*48的三通道RGB图片,而这次MNIST数据集中的图片尺寸均为28*28单通道灰度图片,所以需要将数据集中的图片进行缩放,并且增加通道。但考虑到无法直接对数组进行缩放操作,因此学习了PIL库。思路是,先将28*28的数组转化为单通道灰度图象,再对图片使用PIL库中的函数增加通道、缩放,再将三通道图片转化为三维数组。主要用到了PIL库,以及map函数,lambda生成匿名函数。

获取图片信息

首先举几个简单的例子属下一下PIL模块。载入PIL模块中的Image,加载图片:

fromPILimportImage

im = Image.open(r'D:\MyProjects\Python\Neural Network\pics_test\20905320.jpg')
print('格式: %s\n尺寸: %s\n储存形式: %s'%(im.format, im.size, im.mode))

利用formatsizemode方法来查看图片的格式信息,输出结果为:

格式: JPEG
尺寸: (1080, 1350)
储存形式: RGB

旋转翻转图片

对图片进行基本操作(左右翻转,上下翻转,旋转固定角度):

#左右翻转
im_leftright = im.transpose(Image.FLIP_LEFT_RIGHT)
im_leftright.show()
im_leftright.save(r'D:\MyProjects\Python\Neural Network\pics_test\im_leftright.jpg', 'JPEG')

#上下翻转
im_topbottom = im.transpose(Image.FLIP_TOP_BOTTOM)
im_topbottom.show()
im_topbottom.save(r'D:\MyProjects\Python\Neural Network\pics_test\im_topbottom.jpg', 'JPEG')

#旋转固定角度
im_CCW = im.rotate(90) #逆时针旋转90
im_CCW.show()
im_CCW.save(r'D:\MyProjects\Python\Neural Network\pics_test\countercolckwise.jpg', 'JPEG')

im_CW = im.rotate(-90)#顺时针旋转90
im_CW.show()
im_CW.save(r'D:\MyProjects\Python\Neural Network\pics_test\im_colckwise.jpg', 'JPEG')

效果如下:


缩放图片

#改造图片的大小
scaledown = 100, 100
scaleup = 1000, 1000

#压缩尺寸
im_shrink = im.resize(scaledown, Image.ANTIALIAS)
im_shrink.show()
im_shrink.save(r'D:\MyProjects\Python\Neural Network\pics_test\im_shrink.jpg', 'JPEG')

#拉伸尺寸
im_expand = im.resize(scaleup, Image.ANTIALIAS)
im_expand.show()
im_expand.save(r'D:\MyProjects\Python\Neural Network\pics_test\im_expand.jpg', 'JPEG')

#保存缩略图
im.save(r'D:\MyProjects\Python\Neural Network\pics_test\thumbnail_5.jpg', 'JPEG', quality = 5)
im.save(r'D:\MyProjects\Python\Neural Network\pics_test\thumbnail_90.jpg', 'JPEG', quality = 90)

对于图片的压缩和拉伸都可以通过resize方法来实现,需要给定缩放后的尺寸作为依据。记得加上Image.ANTIALIAS保证图片质量。

补充一下这几个参数的意义: PIL.Image.NEAREST:最低质量 PIL.Image.BILINEAR:双线性 PIL.Image.BICUBIC:三次样条插值 PIL.Image.ANTIALIAS:最高质量缩放

效果如下所示:

图片保存质量可以通过改变save方法中的quality参数来改变,如下图所示:

#缩略图
im.thumbnail(scaledown, Image.ANTIALIAS)
im.show()
im.save(r'D:\MyProjects\Python\Neural Network\pics_test\thumbnail.jpg', 'JPEG')

上面这种方法也可以生成缩略图,但要注意,此处是直接将原始的图像(读进来的数据,而不是被载入的文件)修改了,其他的方法都是产生新的图片。

我们再用PIL库做几件有趣的事:

批量添加水印

#读进来所有jpg格式的专辑封面,存放进Images列表
images = []
names_pic = []
foreachfileinglob.glob(r"D:\MyProjects\Python\Neural Network\album_covers\*.jpg"):
   
filepath, name = os.path.split(eachfile)
   
names_pic.append(name.split('.')[0])    #依次保存图片名字
   
im = Image.open(eachfile)
   
images.append(im)
   
watermark = Image.open('watermark.png')
ww, wh = watermark.size
foriinrange(len(images)):
   
#将尺寸缩小0.8:练习maplambda匿名函数
   
size_new = tuple(map(lambdax : int(x*0.8), watermark.size))
   
watermark_new = watermark.resize(size_new, Image.ANTIALIAS)

   
iw, ih = images[i].size
   
#peste会在原图上做修改,因此需要提前进行备份
   
temp = images[i].resize((1000,1000), Image.ANTIALIAS)
   
iw, ih = temp.size
   
temp.paste(watermark, (iw-ww, ih-wh))
   
temp.paste(watermark_new, (int((iw-ww)/2), int((ih-wh)/2)))  
   
temp.save(r"D:\MyProjects\Python\NeuralNetwork\album_covers_watermark\%s_watermarked.jpg"%names_pic[i], 'PNG')

这句代码glob.glob(r"D:\MyProjects\Python\NeuralNetwork\album_covers\*.jpg"),是获得文件夹D:\MyProjects\Python\Neural Network\album_covers\下所有jpg格式的文件的绝对路径。其实添加水印主要就是读取图片集合,读取水印图片,再利用paste方法将水印图片粘贴到目标图片的某个位置即可。

只是需要注意的是,paste方法会在元数据上进行修改,如果不希望在原图上修改,请进行备份。另外确定像素点的坐标时要将图片想象成一个矩阵,就如索引[0, 0]是左上角第一个元素,图片坐标的原点也是左上角。而右下角像素的坐标就是图片的[行数, 列数]

添加滤镜

#添加滤镜
images[8].filter(ImageFilter.DETAIL).show()        #细节增强
images[8].filter(ImageFilter.BLUR).show()          #模糊滤波
images[8].filter(ImageFilter.FIND_EDGES).show()    #找到边缘
images[8].filter(ImageFilter.EDGE_ENHANCE).show()  #边缘增强

处理MNIST数据集

importpickle
importnumpyasnp
fromPILimportImage
fromkeras.datasetsimportmnist
fromkeras.utilsimportto_categorical

defloadData():
   
'''
  keras.dataset中读进来的mnist的每个手写数字的数据,并分出测试集和训练集;
  为了提高效率,不必每次重新预处理70000的样本,初次运行时即将处理好的数据存放进pickle文件中
  '''
  (
x_train, y_train), (x_test, y_test) = mnist.load_data()
   

   
X_train = feature_preprocesing(x_train)
   
Y_train = to_categorical(y_train)
   
X_test = feature_preprocesing(x_test)
   
Y_test = to_categorical(y_test)
   
   
withopen('pickle/mnist_dataset_resized.pkl', 'wb') asdata:
       
pickle.dump((X_train, Y_train, X_test, Y_test), data)


deffeature_preprocesing(arr28):
   
'''
  keras.dataset中读进来的mnist的每个手写数字的数据都是28*28的数组.
  为了数据可用于由imagenet数据集pre-trained得到的VGG16fine tune(要求图像尺寸最小为48*48),
  需要对数据做出如下预处理:
      1. array转化为image格式
      2. 利用PIL模块,更改图片尺寸
      3. 将单通道的图片转化为多通道的图片
      4. 将每个图片转化为三维数组,尺寸为(56*56*3)
  '''
   
new_shape = 56, 56
   
pic28 = list(map(Image.fromarray, arr28))
   
pic56 = list(map(lambdax:x.resize(new_shape, Image.ANTIALIAS), pic28))
   
pic56_3 = list(map(lambdax:Image.merge('RGB',(x,x,x)), pic56))
   
arr56_3 = np.array(list(map(np.array, pic56_3)))
   
   
returnarr56_3

对于图片的预处理主要包括:

1.    array转化为image格式(28*28*1)

2.    利用PIL模块,更改图片尺寸为(56*56*1)

3.    将单通道的图片转化为多通道的图片,尺寸为(56*56*3)

4.    将每个图片转化为三维数组

用到了map函数来对于每一个图片进行操作,因为方法没办法表示成函数的形式,只能用lambda构造匿名函数来对每一个图片进行操作。

进行预处理之前的Keras.dataset中的MNIST数据集:

进行上述程序中的预处理之后:

 

猜你喜欢

转载自blog.csdn.net/Lau_Sen/article/details/80720713