中药图片拍照识别系统-移动端+后端
## 项目说明
中药识别系统主要采用APP端拍照上传的方式,构建卷积神经网络(CNN)对图像进行识别,具有识别效率高,准确度高的特点。APP端的功能包括但不限于拍照识别、中药问答(付费咨询)、检索查询、中药性状以及功效查看、方剂智能推荐【开发中】等;本系统包含APP端以及服务器端。
## 版本说明 3.x
1. APP端使用**Flutter**重写界面,使用体验得到提升。
2. 深度学习运行时框架采用**ONNX Runtime**。**计算速度**得到明显加快,同时深度学习框架依赖部署文件减小到**40M**。
## 项目介绍
**本项目包含六个模块:**
- **medicine-app:**[APP端](medicine-app)
- **medicine-server:**[服务器端](medicine-server)
- **medicine-crawler:**[爬虫工程](medicine-crawler)
- **medicine-model:**[卷积神经网络](medicine-model)
- **medicine-util:**[公用工具类](medicine-util)
- **medicine-dataset:**[数据集](medicine-dataset)
## 项目预览
- **项目运行展示**
- [**视频演示**](https://www.bilibili.com/video/BV14T4y157rM)
- [**APP下载地址**](https://gitee.com/xiaohaoo/chinese-medicine-identification/releases)
## 开发文档
[阅读文档](http://xiaohaoo.gitee.io/chinese-medicine-identification-admin/)
## 技术简介
1. **medicine-app APP端**
- Flutter开发
2. **medicine-server服务器端工程**
Gradle构建
SpringBoot框架,一键启动与部署
文档数据库:MongoDB
全文检索:Elasticsearch + IK分词器
数据库:MySQL
深度学习运行时架构:ONNX Runtime(ONNX Runtime is a cross-platform inference and training machine-learning accelerator)
3. **medicine-crawler爬虫工程**
爬虫主要用来爬取**训练集**以及**中药的详细信息**,包含但不限于:中药名称、中药形态、图片、
别名、英文名、配伍药方、功效与作用、临床应用、产地分布、药用部位、
性味归经、药理研究、主要成分、使用禁忌、采收加工、药材性状等信息。
爬虫框架:WebMagic([参考代码](./medicine-crawler/src/main/java/cn/xiaohaoo/datacollection/MedicineCountPageProcessor.java))
数据持久化:MongoDB
数据结构(简略展示)
- 中药一级分类信息
![](./medicine-doc/assets/images/中药分类信息.jpg)
- 中药详细信息
![](./medicine-doc/assets/images/中药详细信息.jpg)
4. **medicine-model卷积神经网络工程**
- Language: Python
- 使用TensorFlow 深度学习框架,使用Keras会大幅缩减代码量
- [数据集](medicine-dataset)
- 常用的**卷积网络模型**及在ImageNet上的准确率
|模型|大小|Top-1准确率|Top-5准确率|参数数量|深度|
|:---:|:---:|:---:|:---:|:---:|:---:|
|**Xception**|**88 MB**|**0.790**|**0.945**|**22,910,480**|**126**|
|VGG16|528 MB|0.713|0.901|138,357,544|23|
|VGG19|549 MB|0.713|0.900|143,667,240|26|
|ResNet50|98 MB|0.749|0.921|25,636,712|168|
|ResNet101|171 MB|0.764|0.928|44,707,176|-|
|ResNet152|232 MB|0.766|0.931|60,419,944|-|
|ResNet50V2|98 MB|0.760|0.930|25,613,800|-|
|ResNet101V2|171 MB|0.772|0.938|44,675,560|-|
|ResNet152V2|232 MB|0.780|0.942|60,380,648|-|
|ResNeXt50|96 MB|0.777|0.938|25,097,128|-|
|ResNeXt101|170 MB|0.787|0.943|44,315,560|-|
|InceptionV3|92 MB|0.779|0.937|23,851,784|159|
|InceptionResNetV2|215 MB|0.803|0.953|55,873,736|572|
|MobileNet|16 MB|0.704|0.895|4,253,864|88|
|MobileNetV2|14 MB|0.713|0.901|3,538,984|88|
|DenseNet121|33 MB| 0.750|0.923|8,062,504|121|
|DenseNet169|57 MB| 0.762|0.932|14,307,880|169|
|DenseNet201|80 MB|0.773|0.936|20,242,984|201|
|NASNetMobile|23 MB|0.744|0.919|5,326,716|-|
|NASNetLarge|343 MB|0.825|0.960|88,949,818|-|
由于硬件条件限制,综合考虑模型的准确率、大小以及复杂度等因素,采用了**Xception模型**,该模型是134层(包含激活层,批标准化层等)拓扑深度的卷积网络模型。
- **Xception函数定义:**
```python
def Xception(include_top=True,
weights='imagenet',
input_tensor=None,
input_shape=None,
pooling=None,
classes=1000,
**kwargs)
# 参数
# include_top:是否保留顶层的全连接网络
# weights:None代表随机初始化,即不加载预训练权重。'imagenet’代表加载预训练权重
# input_tensor:可填入Keras tensor作为模型的图像输入tensor
# input_shape:可选,仅当include_top=False有效,应为长为3的tuple,指明输入图片的shape,图片的宽高必须大于71,如(150,150,3)
# pooling:当include_top=False时,该参数指定了池化方式。None代表不池化,最后一个卷积层的输出为4D张量。‘avg’代表全局平均池化,‘max’代表全局最大值池化。
# classes:可选,图片分类的类别数,仅当include_top=True并且不加载预训练权重时可用
```
- **构建代码**
[基于Xception的模型微调,详细请参考代码](medicine-model/src)
1. 设置Xception参数
迁移学习参数权重加载:xception_weights
```python
# 设置输入图像的宽高以及通道数
img_size = (299, 299, 3)
base_model = keras.applications.xception.Xception(include_top=False,
weights='..\\resources\\keras-model\\xception_weights_tf_dim_ordering_tf_kernels_notop.h5',
input_shape=img_size,
pooling='avg')
# 全连接层,使用softmax激活函数计算概率值,分类大小是628
model = keras.layers.Dense(628, activation='softmax', name='predictions')(base_model.output)
model = keras.Model(base_model.input, model)
# 锁定卷积层
for layer in base_model.layers:
layer.trainable = False
```
2. 全连接层训练(v1.0)
```python
from base_model import model
# 设置训练集图片大小以及目录参数
img_size = (299, 299)
dataset_dir = '..\\dataset\\dataset'
img_save_to_dir = 'resources\\image-traing\\'
log_dir = 'resources\\train-log'
model_dir = 'resources\\keras-model\\'
# 使用数据增强
train_datagen = keras.preprocessing.image.ImageDataGenerator(
rescale=1. / 255,
shear_range=0.2,
width_shift_range=0.4,
height_shift_range=0.4,
rotation_range=90,
zoom_range=0.7,
horizontal_flip=True,
vertical_flip=True,
preprocessing_function=keras.applications.xception.preprocess_input)
test_datagen = keras.preprocessing.image.ImageDataGenerator(
preprocessing_function=keras.applications.xception.preprocess_input)
train_generator = train_datagen.flow_from_directory(
dataset_dir,
save_to_dir=img_save_to_dir,
target_size=img_size,
class_mode='categorical')
validation_generator = test_datagen.flow_from_directory(
dataset_dir,
save_to_dir=img_save_to_dir,
target_size=img_size,
class_mode='categorical')
# 早停法以及动态学习率设置
early_stop = EarlyStopping(monitor='val_loss', patience=13)
reduce_lr = ReduceLROnPlateau(monitor='val_loss', patience=7, mode='auto', factor=0.2)
tensorboard = keras.callbacks.tensorboard_v2.TensorBoard(log_dir=log_dir)
for layer in model.layers:
layer.trainable = False
# 模型编译
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
history = model.fit_generator(train_generator,
steps_per_epoch=train_generator.samples // train_generator.batch_size,
epochs=100,
validation_data=validation_generator,
validation_steps=validation_generator.samples // validation_generator.batch_size,
callbacks=[early_stop, reduce_lr, tensorboard])
# 模型导出
model.save(model_dir + 'chinese_medicine_model_v1.0.h5')
```
3. 对于顶部的6层卷积层,我们使用数据集对权重参数进行微调
```python
# 加载模型
model=keras.models.load_model('resources\\keras-model\\chinese_medicine_model_v2.0.h5')
for layer in model.layers:
layer.trainable = False
for layer in model.layers[126:132]:
layer.trainable = True
history = model.fit_generator(train_generator,
steps_per_epoch=train_generator.samples // train_generator.batch_size,
epochs=100,
validation_data=validation_generator,
validation_steps=validation_generator.samples // validation_generator.batch_size,
callbacks=[early_stop, reduce_lr, tensorboard])
model.save(model_dir + 'chinese_medicine_model_v2.0.h5')
```
4. 服务器端,使用ONNX Runtime调用训练好的模型
- **模型概览**
[模型详细结构](medicine-doc/assets/images/model.png)
- **训练过程正确率以及损失函数可视化展示**
![正确率](medicine-doc/assets/images/正确率.png)
![损失函数](medicine-doc/assets/images/损失函数.png)
5. **medicine-dataset数据集**
- [数据集:](medicine-dataset/dataset2)像素:299*299
- [中药名字编码表](medicine-doc/assets/medicine_label.txt)
6. **medicine-util公用工具类**
- 关于[MongoDbUtil](medicine-util/src/main/java/cn/xiaohaoo/medicine/util/mongo/)说明
## 依赖环境说明
|依赖|版本|
|:---:|:---:|
|JDK|11+|
|Python|3.6|
|Gradle|6.5|
|TensorFlow|2.0|
|MongoDB|4.2.2|
|MySQL|8.0+|
|Spring Boot|2.2.2|
|Elasticsearch|7.4.2|
|IK分词器|7.4.2|
|ONNX Runtime|1.8.1|
## 开源软件使用须知
- **允许用于个人学习;**
- **开源版不适合商用;**
- **禁止将本项目的代码和资源进行任何形式的出售,产生的一切任何后果责任由侵权者自负;**
- **[LICENSE](LICENSE)**
## 交流、反馈与参与贡献
- 如需关注项目最新动态,请Watch、Star项目,同时也是对项目最好的支持
- 欢迎参与技术讨论、二次开发等咨询、问题和建议!
- QQ:993021993
- 微信:
![WECHAT](medicine-doc/assets/WECHAT.png)
#### 开源不易,感谢各位朋友的star! ^_^