1. 项目概述
最近在做一个挺有意思的智能垃圾分类小程序项目,用到了图像识别技术。这个项目源于一个很实际的需求:现在城市垃圾越来越多,但很多人还是搞不清楚该怎么分类。传统的垃圾分类要么靠人工指导,要么靠用户自己查分类表,效率都很低。
我们团队决定开发一个基于微信小程序的智能垃圾分类系统,用户只要拍个照,系统就能自动识别垃圾类型并给出分类建议。整个系统采用了前后端分离的架构,前端用UniApp开发微信小程序,后端用PHP+Node.js混合架构,图像识别部分用了深度学习模型。
2. 系统架构设计
2.1 整体架构
系统采用典型的三层架构:
- 表现层:微信小程序(UniApp+Vue.js)
- 业务逻辑层:PHP(ThinkPHP/Laravel)
- 数据访问层:MySQL+Redis
特别的是,我们把图像识别服务单独抽离出来,用Node.js+Express实现,主要是考虑到Node.js在处理高并发I/O请求时的性能优势。
2.2 技术选型考量
选择UniApp是因为它"一次开发,多端运行"的特性,可以很方便地适配各种小程序平台。后端选择PHP主要是考虑到团队的技术栈和快速开发的需求,而Node.js则是专门用来处理图像识别这种计算密集型任务。
数据库方面,MySQL作为主数据库存储用户数据和分类记录,Redis用来缓存热门垃圾的分类结果,减少模型重复计算的开销。
3. 核心功能实现
3.1 图像识别模块
图像识别是整个系统的核心。我们对比了几种主流的轻量级CNN模型:
| 模型 | 参数量 | 准确率 | 推理速度 |
|---|---|---|---|
| MobileNetV2 | 3.4M | 88% | 快 |
| ResNet18 | 11.7M | 92% | 中等 |
| EfficientNet-B0 | 5.3M | 90% | 较快 |
最终选择了MobileNetV2,因为它在准确率和推理速度之间取得了较好的平衡,特别适合移动端场景。
模型训练我们用了迁移学习的方法:
- 使用ImageNet预训练权重初始化
- 冻结底层卷积层
- 只训练顶部的全连接层
- 使用垃圾图片数据集fine-tune
python复制# 模型定义示例
base_model = MobileNetV2(weights='imagenet', include_top=False)
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024, activation='relu')(x)
predictions = Dense(num_classes, activation='softmax')(x)
model = Model(inputs=base_model.input, outputs=predictions)
# 冻结底层
for layer in base_model.layers:
layer.trainable = False
# 编译模型
model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
3.2 微信小程序前端
小程序端主要功能点:
- 拍照/相册上传
- 识别结果展示
- 分类知识库
- 用户历史记录
使用UniApp开发的最大好处是可以复用大部分代码到其他平台。我们主要用到了这些技术点:
- Vue.js组件化开发
- uni.uploadFile API上传图片
- WebSocket实时通信
- 自定义动画效果提升用户体验
javascript复制// 图片上传示例
uni.chooseImage({
count: 1,
success: (res) => {
const tempFilePaths = res.tempFilePaths;
uni.uploadFile({
url: 'https://your-api.com/upload',
filePath: tempFilePaths[0],
name: 'file',
success: (uploadRes) => {
this.result = JSON.parse(uploadRes.data);
}
});
}
});
4. 后端服务实现
4.1 PHP业务逻辑
PHP部分主要负责:
- 用户认证
- 数据持久化
- 业务逻辑处理
- API接口提供
我们使用Laravel框架,主要考虑到它完善的ORM和优雅的路由定义。数据库设计主要包含以下几张表:
- users(用户表)
- garbage_types(垃圾类型表)
- recognition_records(识别记录表)
- feedbacks(用户反馈表)
php复制// Laravel路由示例
Route::group(['prefix' => 'api'], function() {
Route::post('login', 'AuthController@login');
Route::post('register', 'AuthController@register');
Route::middleware('auth:api')->group(function() {
Route::get('history', 'RecognitionController@history');
Route::post('feedback', 'FeedbackController@store');
});
});
4.2 Node.js图像服务
Node.js服务专门处理图像识别请求,主要优化点:
- 使用Express.js搭建REST API
- 引入TensorFlow.js加载预训练模型
- 实现请求队列避免过载
- 添加结果缓存机制
javascript复制// Express服务示例
const express = require('express');
const tf = require('@tensorflow/tfjs-node');
const app = express();
// 加载模型
let model;
(async () => {
model = await tf.loadGraphModel('file://./model/model.json');
})();
app.post('/recognize', async (req, res) => {
const imageBuffer = req.body.image;
// 图像预处理
const tensor = preprocessImage(imageBuffer);
// 推理
const predictions = model.predict(tensor);
// 后处理
const results = processPredictions(predictions);
res.json(results);
});
5. 性能优化实践
5.1 缓存策略
我们实现了两级缓存:
- 内存缓存:使用Node.js内存缓存高频识别结果
- Redis缓存:持久化存储常见垃圾的分类结果
缓存键设计为垃圾图片的MD5值,这样相同的图片可以直接返回缓存结果,无需重复计算。
5.2 并发处理
针对高并发场景,我们做了以下优化:
- 使用Node.js集群模式充分利用多核CPU
- 实现请求限流(rate limiting)
- 设置合理的超时时间
- 添加服务降级策略
javascript复制// 集群模式示例
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
// 启动worker进程
const app = require('./app');
app.listen(3000);
}
6. 部署方案
6.1 服务器配置
我们使用了两台服务器:
- Web服务器:4核8G,运行PHP+Nginx
- AI服务器:8核16G(带GPU),运行Node.js
数据库使用阿里云RDS MySQL 5.7,Redis使用阿里云Redis服务。
6.2 CI/CD流程
使用Jenkins实现自动化部署:
- 代码提交触发Git Hook
- 运行单元测试
- 构建Docker镜像
- 滚动更新服务
dockerfile复制# PHP服务Dockerfile示例
FROM php:7.4-fpm
RUN apt-get update && apt-get install -y \
libzip-dev \
zip \
&& docker-php-ext-install zip pdo_mysql
WORKDIR /var/www
COPY . .
RUN chown -R www-data:www-data /var/www
7. 踩坑与解决方案
7.1 模型精度问题
初期模型在特定类别(如不同塑料制品)上准确率较低。解决方案:
- 增加数据增强(旋转、裁剪、调色)
- 针对难样本重点采集
- 调整类别权重
7.2 小程序性能优化
发现小程序在低端机上卡顿明显。优化措施:
- 图片压缩后再上传
- 减少不必要的setData调用
- 使用虚拟列表优化长列表渲染
- 提前加载关键资源
7.3 跨平台兼容性
UniApp虽然号称"一次编写,多端运行",但各平台仍有差异。我们:
- 封装平台特定代码
- 使用条件编译
- 针对各平台单独测试
javascript复制// 条件编译示例
// #ifdef MP-WEIXIN
// 微信小程序特有代码
// #endif
// #ifdef H5
// H5特有代码
// #endif
8. 项目成果
经过3个月的开发和优化,系统达到了以下指标:
- 分类准确率:92.5%(测试集)
- 平均响应时间:800ms
- 最大并发量:500+ QPS
- 用户满意度:4.7/5.0
目前系统已在多个社区试点运行,日均识别请求量超过1万次,大大提升了垃圾分类的效率。
