OpenCV-Python实战(22)——使用Keras和Flask在Web端部署图像识别应用
0. 前言
在深度学习简介中,我们学习了如何使用
Keras
创建深度学习应用程序。在本文中,我们将看到如何使用
Keras
和
Flask
创建深度学习
API REST
。更具体地说,我们首先学习如何使用
Keras
中包含的预训练深度学习架构,然后介绍如何使用这些预训练深度学习架构创建深度学习
API
。
1. Keras 应用程序
Keras Applications 是
Keras
深度学习库的应用模块,提供了许多流行的深度学习模型架构(例如
VGG16
、
ResNet50
、
Xception
和
MobileNet
等)的预训练权重,可用于预测、特征提取和微调。
Keras
在实例化模型时会自动下载预训练的权重,所有这些深度学习架构与所有后端(
TensorFlow
、
Theano
和
CNTK
) 兼容。这些深度学习架构在 ImageNet 数据集 上进行训练和验证,用于图像分类任务:
在上图中,可以看到
Keras Applications
模块中可用的各个模型的介绍,接下来,我们将使用这些预训练模型进行图像分类任务。除了图像分类任务外,这些预训练模型还可用于特征提取(例如,从任意中间层提取特征)和微调(例如,在新的任务中微调预训练模型)。
第一步是导入所需要的包:
from keras.preprocessing import image
from keras.applications import inception_v3, vgg16, vgg19, resnet50, mobilenet, xception, nasnet, densenet
from keras.applications.imagenet_utils import decode_predictions
第二步是实例化不同的模型架构:
# 加载可用模型
model_inception_v3 = inception_v3.InceptionV3(weights='imagenet')
model_vgg_16 = vgg16.VGG16(weights='imagenet')
model_vgg_19 = vgg19.VGG19(weights='imagenet')
model_resnet_50 = resnet50.ResNet50(weights='imagenet')
model_mobilenet = mobilenet.MobileNet(weights='imagenet')
model_xception = xception.Xception(weights='imagenet')
model_nasnet_mobile = nasnet.NASNetMobile(weights='imagenet')
model_densenet_121 = densenet.DenseNet121(weights='imagenet')
第三步是使用
preprocessing_image()
函数加载和预处理图像以进行分类:
defpreprocessing_image(img_path, target_size, architecture):
img = image.load_img(img_path, target_size=target_size)
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = architecture.preprocess_input(x)return x
x_inception_v3 = preprocessing_image(img_path,(299,299), inception_v3)
x_vgg_16 = preprocessing_image(img_path,(224,224), vgg16)
x_vgg_19 = preprocessing_image(img_path,(224,224), vgg19)
x_resnet_50 = preprocessing_image(img_path,(224,224), resnet50)
x_mobilenet = preprocessing_image(img_path,(224,224), mobilenet)
x_xception = preprocessing_image(img_path,(299,299), xception)
x_nasnet_mobile = preprocessing_image(img_path,(224,224), nasnet)
x_densenet_121 = preprocessing_image(img_path,(224,224), densenet)
preprocessing_image()
函数的第一步是使用
image.load_img()
函数加载图像,指定目标大小,由于
Keras
加载的是
PIL
格式
(width, height)
的图像,需要使用
image.img_to_array()
函数将其转换为
NumPy
格式
(height, width, channel)
;然后,使用
NumPy
的
expand_dims()
函数将输入图像转换为四维张量
(batchsize, height, width, channels)
;预处理图像的最后一步是对图像进行归一化,每种架构使用特定预处理方式,通过调用
preprocess_input()
函数实现;最后调用
preprocessing_image()
函数。
图像经过预处理后,就来到第四步使用
model.predict()
获得分类结果(每个类别的预测概率):
# 获取预测结果概率
preds_inception_v3 = model_inception_v3.predict(x_inception_v3)
preds_vgg_16 = model_vgg_16.predict(x_vgg_16)
preds_vgg_19 = model_vgg_19.predict(x_vgg_19)
preds_resnet_50 = model_resnet_50.predict(x_resnet_50)
preds_mobilenet = model_mobilenet.predict(x_mobilenet)
preds_xception = model_xception.predict(x_xception)
preds_nasnet_mobile = model_nasnet_mobile.predict(x_nasnet_mobile)
preds_densenet_121 = model_nasnet_mobile.predict(x_densenet_121)
预测值由元组列表(类别 ID, 描述, 预测置信度)构成:
# 打印结果 (class, description, probability):print('Predicted InceptionV3:', decode_predictions(preds_inception_v3, top=5)[0])print('Predicted VGG16:', decode_predictions(preds_vgg_16, top=5)[0])print('Predicted VGG19:', decode_predictions(preds_vgg_19, top=5)[0])print('Predicted ResNet50:', decode_predictions(preds_resnet_50, top=5)[0])print('Predicted MobileNet:', decode_predictions(preds_mobilenet, top=5)[0])print('Predicted Xception:', decode_predictions(preds_xception, top=5)[0])print('Predicted NASNetMobile:', decode_predictions(preds_nasnet_mobile, top=5)[0])print('Predicted DenseNet121:', decode_predictions(preds_densenet_121, top=5)[0])
模型输出是输入中的每个图像的预测结果元组(类别 ID 、描述和预测置信度),由于我们只有一张图像用作输入,因此得到的输出如下:
Predicted InceptionV3: [('n02510455', 'giant_panda', 0.97168857), ('n04254680', 'soccer_ball', 0.00053718797), ('n04266014', 'space_shuttle', 0.00035958426), ('n02509815', 'lesser_panda', 0.00035547058), ('n02500267', 'indri', 0.00032849688)]
Predicted VGG16: [('n02510455', 'giant_panda', 0.9851264), ('n02445715', 'skunk', 0.007836222), ('n02447366', 'badger', 0.006254676), ('n02441942', 'weasel', 0.0002136865), ('n02509815', 'lesser_panda', 0.00015041522)]
Predicted VGG19: [('n02510455', 'giant_panda', 0.9984491), ('n02445715', 'skunk', 0.0007714728), ('n02447366', 'badger', 0.00059817365), ('n02488702', 'colobus', 2.128689e-05), ('n02442845', 'mink', 1.9781652e-05)]
Predicted ResNet50: [('n02510455', 'giant_panda', 0.9832449), ('n02110341', 'dalmatian', 0.002478397), ('n02509815', 'lesser_panda', 0.0022290186), ('n02447366', 'badger', 0.0020123231), ('n02412080', 'ram', 0.00044684077)]
Predicted MobileNet: [('n02510455', 'giant_panda', 0.9991955), ('n02509815', 'lesser_panda', 0.0003145063), ('n02500267', 'indri', 0.0001445993), ('n02497673', 'Madagascar_cat', 0.0001292361), ('n02493509', 'titi', 5.8193353e-05)]
Predicted Xception: [('n02510455', 'giant_panda', 0.91967607), ('n02509815', 'lesser_panda', 0.0037806507), ('n04399382', 'teddy', 0.0013589169), ('n02134418', 'sloth_bear', 0.00050903426), ('n02132136', 'brown_bear', 0.0004746767)]
Predicted NASNetMobile: [('n02510455', 'giant_panda', 0.8976383), ('n02509815', 'lesser_panda', 0.0012320529), ('n04254680', 'soccer_ball', 0.0012049181), ('n02488702', 'colobus', 0.0007275882), ('n02971356', 'carton', 0.00048007787)]
Predicted DenseNet121: [('n02510455', 'giant_panda', 0.992669), ('n02509815', 'lesser_panda', 0.0039006013), ('n02445715', 'skunk', 0.0011870685), ('n02500267', 'indri', 0.0009038625), ('n02447366', 'badger', 0.00013635056)]
最后,使用
put_text()
函数显示每种架构预测的图像分类结果:
defput_text(img, model_name, decoded_preds, y_pos):# 调用了 cv2.putText() 函数来渲染图像分类结果字符串
cv2.putText(img,"{}: {}, {:.2f}".format(model_name, decoded_preds[0][0][1], decoded_preds[0][0][2]),(20, y_pos), cv2.FONT_HERSHEY_SIMPLEX,1.5,(255,0,255),2)
put_text(numpy_image_res,"InceptionV3", decode_predictions(preds_inception_v3),40)
put_text(numpy_image_res,"VGG16", decode_predictions(preds_vgg_16),80)
put_text(numpy_image_res,"VGG19", decode_predictions(preds_vgg_19),120)
put_text(numpy_image_res,"ResNet50", decode_predictions(preds_resnet_50),160)
put_text(numpy_image_res,"MobileNet", decode_predictions(preds_mobilenet),200)
put_text(numpy_image_res,"Xception", decode_predictions(preds_xception),240)
put_text(numpy_image_res,"NASNetMobile", decode_predictions(preds_nasnet_mobile),280)
put_text(numpy_image_res,"DenseNet121", decode_predictions(preds_densenet_121),320)
程序输出结果如下所示:
2. 创建 Keras 应用程序的深度学习 REST API
在上一节中,我们学习了如何使用
Keras
提供的深度学习模型定义和预训练权重。接下来,我们进一步了解如何基于这些预训练架构创建深度学习
REST API
。
首先是导入需要的包,如下:
# keras_rest_api.pyfrom keras.applications import nasnet, NASNetMobile
from keras.preprocessing.image import img_to_array
from keras.applications import imagenet_utils
from PIL import Image
import numpy as np
import flask
import io
然后是初始化
Flask
应用程序和深度学习模型:
# 初始化 Flask 应用程序和深度学习模型
app = flask.Flask(__name__)
model =None
第三步是定义
load_model()
函数,用于创建深度学习架构并加载所需的权重:
defload_model():global model
# 加载 NASNetMobile 权重
model = NASNetMobile(weights='imagenet')
接下来定义 preprocessing_image() 函数用于预处理:
defpreprocessing_image(image, target):if image.mode !="RGB":
image = image.convert("RGB")# 缩放
image = image.resize(target)# 将 PIL 类型转换为 Numpy 类型
image = img_to_array(image)# 维度扩展
image = np.expand_dims(image, axis=0)# 根据特定架构进行预处理
image = nasnet.preprocess_input(image)return image
最后,我们使用 route() 装饰器将 predict() 函数绑定到 /predict URL。 predict() 函数处理请求并将预测返回给客户端,如下所示:
@app.route("/predict", methods=["POST"])defpredict():
result ={'success':False}if flask.request.method =='POST':if flask.request.files.get('image'):# 读取 PIL 格式的输入图像
image = flask.request.files['image'].read()
image = Image.open(io.BytesIO(image))# 输入图像预处理
image = preprocessing_image(image, target=(224,224))# 图像分类
predictions = model.predict(image)
results = imagenet_utils.decode_predictions(predictions)
result['predictions']=[]# 将预测添加到结果中for(imagenet_id, label, prob)in results[0]:
r ={'label': label,'probability':float(prob)}
result['predictions'].append(r)
result['success']=True# 将结果作为 JSON 响应返回return flask.jsonify(result)if __name__ =='__main__':print("Loading Keras pre-trained model")
load_model()print("Starting")
app.run()
运行编写完成的服务器端程序:
$ python keras_rest_api.py
接下来,我们测试
Keras
深度学习
REST API
执行
POST
请求,打印结果,并创建一个图像来渲染获得的结果:
import requests
KERAS_REST_API_URL ='http://localhost:5000/predict'
IMAGE_PATH ='pandas.jpeg'# 加载图像并构建有效负载
image =open(IMAGE_PATH,'rb').read()
payload ={'image': image}# 获取结果
r = requests.post(KERAS_REST_API_URL, files=payload).json()# 获得原始图像以进行可视化
image_array = np.asarray(bytearray(image), dtype=np.uint8)
img_opencv = cv2.imdecode(image_array,-1)
y_pos =40if r['success']:for(i, result)inenumerate(r['predictions']):print("{}. {}: {:.4f}".format(i +1, result["label"], result["probability"]))# 渲染结果图像
cv2.putText(img_opencv,"{}. {}: {:.4f}".format(i +1, result["label"], result["probability"]),(20, y_pos), cv2.FONT_HERSHEY_SIMPLEX,1.5,(255,0,255),2)
y_pos +=40else:print("Request failed")
如上所示,对
Keras
深度学习
REST API
执行
POST
请求,打印结果并在图像中呈现结果:
小结
在本文中,我们学习了使用 Keras 和 Flask 创建深度学习
REST API
。更具体地说,我们首先学习了使用
Keras
中包含的预训练深度学习架构,然后使用这些预训练深度学习架构创建深度学习
REST API
,用于高性能图像识别任务。
系列链接
OpenCV-Python实战(1)——OpenCV简介与图像处理基础
OpenCV-Python实战(2)——图像与视频文件的处理
OpenCV-Python实战(3)——OpenCV中绘制图形与文本
OpenCV-Python实战(4)——OpenCV常见图像处理技术
OpenCV-Python实战(5)——OpenCV图像运算
OpenCV-Python实战(6)——OpenCV中的色彩空间和色彩映射
OpenCV-Python实战(7)——直方图详解
OpenCV-Python实战(8)——直方图均衡化
OpenCV-Python实战(9)——OpenCV用于图像分割的阈值技术
OpenCV-Python实战(10)——OpenCV轮廓检测
OpenCV-Python实战(11)——OpenCV轮廓检测相关应用
OpenCV-Python实战(12)——一文详解AR增强现实
OpenCV-Python实战(13)——OpenCV与机器学习的碰撞
OpenCV-Python实战(14)——人脸检测详解
OpenCV-Python实战(15)——面部特征点检测详解
OpenCV-Python实战(16)——人脸追踪详解
OpenCV-Python实战(17)——人脸识别详解
OpenCV-Python实战(18)——深度学习简介与入门示例
OpenCV-Python实战(19)——OpenCV与深度学习的碰撞
OpenCV-Python实战(20)——OpenCV计算机视觉项目在Web端的部署
OpenCV-Python实战(21)——OpenCV人脸检测项目在Web端的部署
版权归原作者 盼小辉丶 所有, 如有侵权,请联系我们删除。