keras|OpenCV-Python实战(22)——使用Keras和Flask在Web端部署图像识别应用


OpenCV-Python实战(22)——使用Keras和Flask在Web端部署图像识别应用

    • 0. 前言
    • 1. Keras 应用程序
    • 2. 创建 Keras 应用程序的深度学习 REST API
    • 小结
    • 系列链接

0. 前言 在深度学习简介中,我们学习了如何使用 Keras 创建深度学习应用程序。在本文中,我们将看到如何使用 KerasFlask 创建深度学习 API REST。更具体地说,我们首先学习如何使用 Keras 中包含的预训练深度学习架构,然后介绍如何使用这些预训练深度学习架构创建深度学习 API
1. Keras 应用程序 Keras Applications 是 Keras 深度学习库的应用模块,提供了许多流行的深度学习模型架构(例如 VGG16ResNet50XceptionMobileNet 等)的预训练权重,可用于预测、特征提取和微调。
Keras 在实例化模型时会自动下载预训练的权重,所有这些深度学习架构与所有后端(TensorFlowTheanoCNTK) 兼容。这些深度学习架构在 ImageNet 数据集 上进行训练和验证,用于图像分类任务:
keras|OpenCV-Python实战(22)——使用Keras和Flask在Web端部署图像识别应用
文章图片

在上图中,可以看到 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() 函数加载和预处理图像以进行分类:
def preprocessing_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);然后,使用 NumPyexpand_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() 函数显示每种架构预测的图像分类结果:
def put_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)

程序输出结果如下所示:
keras|OpenCV-Python实战(22)——使用Keras和Flask在Web端部署图像识别应用
文章图片

2. 创建 Keras 应用程序的深度学习 REST API 在上一节中,我们学习了如何使用 Keras 提供的深度学习模型定义和预训练权重。接下来,我们进一步了解如何基于这些预训练架构创建深度学习 REST API
首先是导入需要的包,如下:
# keras_rest_api.py from 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() 函数,用于创建深度学习架构并加载所需的权重:
def load_model(): global model # 加载 NASNetMobile 权重 model = NASNetMobile(weights='imagenet')

接下来定义 preprocessing_image() 函数用于预处理:
def preprocessing_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"]) def predict(): 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 requestsKERAS_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) in enumerate(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 += 40 else: print("Request failed")

如上所示,对 Keras 深度学习 REST API 执行 POST 请求,打印结果并在图像中呈现结果:
keras|OpenCV-Python实战(22)——使用Keras和Flask在Web端部署图像识别应用
文章图片

小结 在本文中,我们学习了使用 Keras 和 Flask 创建深度学习 REST API。更具体地说,我们首先学习了使用 Keras 中包含的预训练深度学习架构,然后使用这些预训练深度学习架构创建深度学习 REST API,用于高性能图像识别任务。
系列链接 【keras|OpenCV-Python实战(22)——使用Keras和Flask在Web端部署图像识别应用】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端的部署

    推荐阅读