之前人工智能大作业需要用到Keras里Applications中的预训练模型VGG16,VGG16接收的图片大小至少是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))
利用format,size,mode方法来查看图片的格式信息,输出结果为:
格式: 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倍:练习map和lambda匿名函数
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得到的VGG16的fine 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数据集:
进行上述程序中的预处理之后: