机器学习CV代码练习(四)之图像描述-“利用去除最后一层的VGG16网络模型”提取图像特征,保存为pickle文件
-
利用个定的VGG16网络结构文件和网络权值文件导入VGG16,去除最后一层,以4096维度输出作为图像特征,从而提取到flicker8k数据集中所有图像的特征。
-
使用字典存储提取图像的特征,key为:不带.jpg后缀的文件名,value为:去除最后一层的VGG16网络的输出,使用pickle库将其保存为features.pkl文件。
-
所需数据集:链接:https://pan.baidu.com/s/1cWWkQw5QCObgOXzopVuBHw
提取码:lsmc -
所需预训练好的VGG模型架构及参数:链接:https://pan.baidu.com/s/1TAn7ZdNhCNscBhi6vQCafg
提取码:r40f
import os
from keras.models import model_from_json
from PIL import Image as pil_image
from keras import backend as K
import numpy as np
from pickle import dump
from os import listdir
from keras.models import Model
import cv2
def load_vgg16_model():#加载vgg16模型
"""从当前目录下面的 vgg16_exported.json 和 vgg16_exported.h5 两个文件中导入 VGG16 网络并返回创建的网络模型
json文件保存定义好的网络结构;
h5保存的网络权值
# Returns
创建的网络模型 model
"""
# 加载已经保存的模型,用其进行预测
#将json文件导入成字符串
json_file = open('vgg16_exported.json', 'r')#读文件
loaded_model_json = json_file.read()#读出内容
json_file.close()
loaded_model = model_from_json(loaded_model_json)#变为keras-model
loaded_model.load_weights("vgg16_exported.h5")
print("load model from disk")
return loaded_model
def preprocess_input(x):
"""预处理图像用于网络输入, 将图像由RGB格式转为BGR格式.
将图像的每一个图像通道减去其均值_凸显出了图片中主要特征
# Arguments
x: numpy 数组, 4维.
data_format: Data format of the image array.
# Returns
Preprocessed Numpy array.
"""
# x = cv2.cvtColor(x, cv2.COLOR_RGB2BGR)
# x = x - np.mean(x, axis=0)
# return np.array(x, dtype=K.floatx()) # 因为keras支持不同的后台backend,例如tensorflow等。K.floatx方法会返回后台支持的浮点数类型
pass
def load_img_as_np_array(path, target_size):#根据图像路径返回目标大小的np.array
"""从给定文件加载图像,转换图像大小为给定target_size,返回32位浮点数numpy数组.
#利用PIL库对path读取图像,并根据target-size对图像进行缩放
# Arguments
path: 图像文件路径
target_size: 元组(图像高度, 图像宽度).
# Returns
A PIL Image instance.
"""
# PIL库中的基本方法:
# from PIL import Image as pil_image
img = pil_image.open(path)
img = img.resize(target_size, pil_image.NEAREST)
return np.array(img, dtype=K.floatx())#因为keras支持不同的后台backend,例如tensorflow等。K.floatx方法会返回后台支持的浮点数类型
def extract_features(directory):#提取给定目标文件夹的所有特征
"""提取给定文件夹directory中所有图像的特征, 将提取的特征保存在文件features.pkl中,
提取的特征保存在一个dict中, key为文件名(不带.jpg后缀), value为特征值[np.array]
Args:
directory: 包含jpg文件的文件夹
Returns:
None
"""
model = load_vgg16_model()#加载训练好的load_vgg16_model模型
#去除模型最后一层
model.layers.pop()
#设计新的网络模型(输入、输出)
model = Model(inputs=model.inputs,outputs=model.layers[-1].output)
features = dict()#定义一个数据字典
i=0
for fn in listdir(directory):
# listdir在数据字典中找,fn为每一个文件名,不包含文件路径。为了读取文件,需要补充文件路径
fnn = directory + '\\' + fn
arr = load_img_as_np_array(fnn,target_size=(224,224))#模型输入为(224,224)
# print(arr.shape[0],arr.shape[1],arr.shape[2])
# 预处理之后的图像作为VGG模型的输入
# arr = preprocess_input(arr)
# #改变数组形态,增加一个维度(批处理输入的维度)。神经网络要接受的维度是4维的
arr = arr.reshape((1,arr.shape[0],arr.shape[1],arr.shape[2]))
#计算特征
feature = model.predict(arr,verbose=0)
# name, suffix = os.path.splitext(fn)#去掉文件后缀(name为名字;suffix为后缀)
id = fn
feature= feature[0]
features[id] = feature
print(i," ",id," ",feature)
i=i+1
return features
if __name__ == '__main__':
# 提取所有图像的特征,保存在一个文件中, 大约一小时的时间,最后的文件大小为127M
directory = 'Flicker8k_Dataset'
features = extract_features(directory)
# print('features',features)
print('提取特征的文件个数:%d' % len(features))
print(K.image_data_format())
#保存特征到文件
dump(features, open('features.pkl', 'wb'))