前提条件
- 了解Python语言,并会安装第三方库
- 掌握创建一个AWS EC2实例
- 掌握使用SSH连接AWS虚机
- 掌握在AWS上部署Flask项目,并用外网访问
- 知道Python实现一个简单的目标检测
实验环境
- Ubuntu 16.04 LTS
- Python 3.5.2
- Tesorflow 2.3.0
- Flask 1.1.1
- Numpy 1.18.5
- Opencv 3.4.2
下载相关库
sudo pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy==1.18.5
sudo pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python==3.4.2.16 opencv-contrib-python==3.4.2.16
sudo pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple flask
sudo pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple tensorflow==2.3.0
项目结构
├─Flask_obj_detection
│ ├─static
│ │ └─images
│ │ └─LeNet_classify_model.h5
│ ├─templates
│ │ └─upload.html
│ │ └─upload_success.html
│ ├─flask_app.py
│ ├─SelectSearch.py
具体步骤
创建项目结构
mkdir Flask_obj_detection
cd Flask_obj_detection
mkdir static templates
cd static
mkdir images
编写py文件
vi SelectSearch.py
其内容如下:
import sys
import cv2
import numpy as np
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
import os
def detect(path,detected_path,weight_path):
# 读取图片
img = cv2.imread(path)
# print(img)
# 按比例缩放图片
newHeight = 200
newWidth = int( img.shape[1] * 200 / img.shape[0] )
img = cv2.resize( img, (newWidth, newHeight) )
# 创建选择性搜索分割对象
ss = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()
# 设置输入图像,我们将运行分割
ss.setBaseImage( img )
# 快速但低召回选择性搜索方法
ss.switchToSelectiveSearchFast()
# 高召回但慢选择性搜索方法
# ss.switchToSelectiveSearchQuality()
# 运行选择性搜索分割输入图像
rects = ss.process()
# print(rects)
# print( 'Total Number of Region Proposals: {}'.format( len( rects ) ) )
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
'dog', 'frog', 'horse', 'ship', 'truck']
# 加载创建完全相同的模型,包括其权重和优化程序
loaded_model = tf.keras.models.load_model(weight_path)
while True:
# 创建原始图像的副本
new_img = img.copy()
# print(new_img)
region_score = []
max_rect = 0
max_name = ""
max_score = 0
# 重复所有的区域建议
for i, rect in enumerate( rects ):
x, y, w, h = rect # 预测框的左上角坐标(x,y)以及框的宽w,高h
pre_img = new_img[y:y+h,x:x+w]
pre_img = cv2.resize(pre_img,(32,32))
pre_img = (np.expand_dims(pre_img,0))
# 输入的图片维度为(1,32,32,3)
pred_arr = loaded_model.predict(pre_img)
# 预测标签
pre_label = np.argmax(pred_arr[0])
# 预测得分
score = np.max(pred_arr[0])
# 预测类名
class_name = class_names[pre_label]
if score > max_score:
max_rect = rect
max_name = class_name
max_score = score
# region_score.append([rect,class_name,score])
print([max_rect,max_name,max_score])
x,y,w,h = max_rect
# cv2.rectangle(new_img, (x, y), (x + w, y + h), (0, 255, 0), 1, cv2.LINE_AA )
cv2.rectangle(new_img, (x, y), (x + w, y + h), (0, 255, 0), 2, cv2.LINE_AA)
font = cv2.FONT_HERSHEY_SIMPLEX
text = max_name+" "+str(max_score*100)[0:4]+"%"
cv2.putText(new_img, text, (x, y-5), font, 0.5, (0,0,255), 2)
# 显示输出
# cv2.imshow("Output", new_img)
cv2.imwrite(detected_path, new_img)
break
# 等待按键输入
# k = cv2.waitKey( 0 ) & 0xFF
# q键
# if k == 113:
# break
# 关闭所有窗口
cv2.destroyAllWindows()
vi flask_app.py
其内容如下:
from flask import (Flask, render_template, request, flash, redirect, url_for, make_response, jsonify)
from werkzeug.utils import secure_filename
import os
import time
from datetime import timedelta
from SelectSearch import detect
ALLOWED_EXTENSIONS = set(["png","jpg","JPG","PNG", "bmp"])
def is_allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
app = Flask(__name__)
# 静态文件缓存过期时间
app.send_file_max_age_default = timedelta(seconds=1)
@app.route("/upload",methods = ['POST', 'GET'])
def upload():
if request.method == "POST":
f = request.files['file']
if not ( f and is_allowed_file(f.filename)):
return jsonify({
"error":1001, "msg":"请检查上传的图片类型,仅限于png、PNG、jpg、JPG、bmp"
})
basepath = os.path.dirname(__file__)
upload_path = os.path.join(basepath, "static/images",secure_filename(f.filename))
f.save(upload_path)
img_path = upload_path
detected_path = os.path.join(basepath, "static/images", "output" + secure_filename(f.filename))
weight_path = os.path.join(basepath, "static", "LeNet_classify_model.h5")
print(upload_path,detected_path)
detect(img_path,detected_path,weight_path)
# return render_template("upload_ok.html", userinput = user_input, val1=time.time(), path = detected_path)
path = "./images/" + "output" + secure_filename(f.filename)
print(path)
return render_template("upload_success.html", path = path, val1 = time.time()) #渲染模板,显示图片检测结果
return render_template("upload.html", path = "./images/test.jpg")
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)
编写HTML文件
vi upload.html
其内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>目标检测</title>
</head>
<body align="center">
<h1>目标检测</h1>
<img src="{{ url_for('static', filename= path,_t=val1) }}" width="400" height="400" alt="图片"/>
<form action="" enctype='multipart/form-data' method='POST'>
<input type="file" name="file" style="margin-top:20px;"/>
<input type="submit" value="检测图片" class="button-new" style="margin-top:15px;"/>
</form>
</body>
</html>
vi upload_success.html
其内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>目标检测</title>
</head>
<body align="center">
<h1>目标检测</h1>
<img src="{{ url_for('static', filename= path,_t=val1) }}" width="400" height="400" alt="图片"/>
<form action="" enctype='multipart/form-data' method='POST'>
<input type="file" name="file" style="margin-top:20px;"/>
<input type="submit" value="检测图片" class="button-new" style="margin-top:15px;"/>
</form>
</body>
</html>
运行项目
python3 flask_app.py
# 或者
export FLASK_APP=flask_app.py
flask run --host=0.0.0.0