该完整项目由团队协作完成,已上传至GitHub,点击直达
gdit-ai
广东科学技术职业学院 计算机工程技术学院(人工智能学院)AI应用实验室
主要从事深度学习算法、计算机视觉、智能算法应用与部署,基于人工智能,计算机视觉算法web前后端应用开发,android开发,微信小程序开发,可以承接相关的项目开发业务。QQ群:971601256
指导老师:胡建华,余君
系统环境:Ubuntu16.04 LTS、python3.x、Anaconda3和相关的编辑器
所需python库:numpy、tensorflow、Keras、opencv、Flask及相关依赖
编辑器:Pycharm和HBuilder X
后端:python3.x、Flask
前端:前端三大件(html+css+javascript)Vue、Element、axios
|——static #静态资源目录,此处为存放前端上传的图片
|——lib #css、js文件存放目录
|——upload #图片上传后的保存目录
|——index.html #前端页面代码
|——mange.py #Flask启动文件(主文件)
|——package.txt #记录运行此项目所需要的依赖包及版本信息(使用pip freeze>package.txt)命令打包
|——PredictAndMove.py #封装后的模型预测文件
|——vggmodel_65-0.00-1.00.hdf5 #hdf5模型文件
Flask非常灵活,官方并没有给出一个固定的项目目录组织结构,此处的目录结构仅为个人习惯以及项目调用使用,也更加符合大型项目结构的工程化构建方法。
保存Keras模型有很多种方法,首先不推荐使用pickle或cPickle来保存Keras模型,此处使用model.save()函数将Keras模型和权重保存在一个HDF5文件中。
HDF5模型保存结构
该项目采用前后端分离的组织架构,使用最流行的前端Vue框架以及Element组件库,使用axios通过JSON数据进行前后端的交互。
<div id="app">
input>
<el-button type="primary" round @click="handleClick" v-if="upload_awesome">上传图片el-button>
<div v-for="(file,index) in imageData">
<el-tag type="success" style="margin:5px 5px;display: flex;justify-content:center;">识别结果为:{{index}}el-tag>
<el-row>
<el-col :span="6" v-for="img in file">
<div class="img-box" style="width: 100%;">
<img :src="img.path" alt="图片正在加载...">
div>
el-col>
el-row>
div>
div>
为保证项目可以正常运行,建议参照官方文档下载和安装完整的Vue、Element、和axios包文件。这里为了压缩项目文件大小,所以只引入了用到的文件,并不是很好的做法。
官方文档地址
Vue: https://cn.vuejs.org/v2/guide/
Element: https://element.eleme.cn/#/zh-CN/component/installation
Axios: http://www.axios-js.com/zh-cn/docs/#axios
1:必须HTML头部(head)使用link标签引入element的css样式文件,script标签分别引入vue.min.js、element.js、axios.min.js文件。
2:页面主体使用element的el-button组件编写上传图片按钮,el-tag组件渲染模型的识别结果,el-col和el-row组件控制图片显示的布局风格。
3:使用@符号绑定了事件函数,用来在JavaScript中调用这些函数进行逻辑处理。
<script type="text/javascript">
var vm = new Vue({
el: '#app', // 创建Vue实例
data: { //定义数据对象
upload_awesome: true,
imageData: {},
file: '',
retData: '',
index:'识别中'
},
methods: { //事件处理器,this将自动绑定到Vue实例上面
handleClick() {
this.$refs['input'].click();
},
fileChange(e) {
this.file = e.target.files[0];
this.uploads()
},
uploads() {
let self = this;
let param = new FormData();
param.append('file', this.file);
axios.post('/upload/', param, {}).then(function(response) {
if (response.status === 200) {
let data = response.data;
self.$set(self.$data, 'imageData', data)
self.$set(self.$data, 'upload_awesome', false)
}
})
.catch(function(error) {
console.log("上传图片失败!")
})
},
}
})
</script>
这里编写前端逻辑代码,包括上传和展示,下面分别介绍自定义的三个函数fileChange()、handleClick()和uploads()。
handleClick():
该函数主要是点击上传按钮之后,动态的去改变input属性,从而触发
fileChange():
使用@change对input的值进行监听,如果监听到值的改变,就截取上传文件的name,并调用upload()函数
uploads():
该函数为主函数,即是通过该函数与服务器通信,以获取、交换数据。下面对该函数的核心代码进行解读
param.append('file', this.file);
将上传的文件信息加入到param变量
axios.post():
axios中post请求实例方法的别名,创建该请求的基本配置选项如下axios.post(url[, data[, config]]),即请求路径(url)、数据、和配置,只有URL是必需的,详情请访问下面网址http://www.axios-js.com/zh-cn/docs/#axios-options-url-config-1
then函数则接受该请求的响应信息,结构如下:
通过if (response.status === 200) {}
判断响应状态,并更新相应的数据,同时视图会进行重渲染,这是vue的特性。
在使用catch时,或传递拒绝回调作为then的第二个参数时,响应可以通过error对象可被使用,主要作用是处理错误。
项目涉及到flask的内容较少,考虑到实用性的问题,此处并没有对核心代码进行路由、蓝图规划和拆分(后面可能会进行更新)。
import os
import json
from flask import Flask, request, jsonify
from werkzeug.utils import secure_filename
导入python的第三方库文件,以及flask用到的依赖库文件
@app.route('/upload/', methods=['POST'])
def upload():
if request.method == 'POST':
f = request.files['file']
if not (f and allowed_file(f.filename)):
return jsonify({"error": 1001, "msg": "请检查上传的图片类型,仅限于jpg,jpeg,png,gif"})
upload_path = os.path.join(path, secure_filename(f.filename))
f.save(upload_path)
# 图片展示
files = os.listdir(path)
fileList = {}
for file in files:
file_d = os.path.join(path, file)
# 执行模型脚本
res = os.popen("python ./PredictAndMove.py %s" % file_d)
labels = res.read()
label = str(labels).strip('\n')
if label in fileList.keys():
fileList[label].append({"filename": file, "path": file_d})
else:
fileList[label] = [{"filename": file, "path": file_d}]
# 将字典形式的数据转化为字符串
return json.dumps(fileList)
- 定义全局配置、判断后缀名函数以及路由注册
- 配置信息是以键值对的格式书写,判断文件格式的函数中使用rsplit()方法通过指定分隔符对字符串进行分割并返回一个列表
- 路由注册通过render_template()方法渲染前端模板(index.html),flask会在templates文件夹内寻找模板文件
- 调用模型预测的文件
upload()函数为该项目后端的核心模块(详细解释请前往GitHub下载查看源代码)后端整体逻辑为:
保存前端上传的图片–>执行模型预测文件–>返回json数据给前端
补充:若项目运行出现这种报错,是因为路径的问题所导致,建议使用Ubuntu系统运行flask程序,或者将用到的路径全部更换为绝对路径
打开终端输入python app.py
此时服务器即为启动状态,打开浏览器,通过127.0.0.1:5000或者ip:5000的方式访问网页,上传图像,进行识别并在前端进行展示