基于CNN的水面漂浮垃圾智能识别系统开发实践
1. 项目概述:基于CNN的水面漂浮垃圾识别系统
水面环境污染治理一直是环保领域的重要课题,其中漂浮垃圾的快速识别与定位是开展清理工作的首要环节。传统的人工巡查方式效率低下且成本高昂,而基于计算机视觉的自动识别技术为解决这一问题提供了新的思路。本项目采用卷积神经网络(CNN)构建了一个水面漂浮垃圾识别系统,能够对航拍或监控视频中的水面区域进行实时检测和分类。
在实际测试中,系统对塑料袋、泡沫制品、树枝等常见漂浮物的识别准确率达到92.3%,单帧图像处理时间仅为0.15秒(使用GTX 1080Ti显卡),完全满足实时监测需求。系统采用B/S架构设计,前端通过Vue.js实现可视化交互界面,后端基于Spring Boot框架搭建服务,模型训练使用Python的TensorFlow框架完成。
2. 系统架构设计
2.1 整体技术栈选择
系统采用前后端分离的架构设计,主要基于以下技术栈:
前端技术:
- Vue.js 2.x:轻量级前端框架,组件化开发
- Element UI:提供丰富的UI组件
- ECharts:用于数据可视化展示
- Axios:处理HTTP请求
后端技术:
- Spring Boot 2.5:简化配置的Java后端框架
- MyBatis-Plus:增强型ORM框架
- Shiro:权限控制框架
- Redis:缓存处理
AI模型部分:
- Python 3.8
- TensorFlow 2.4
- OpenCV 4.5:图像预处理
- LabelImg:标注工具
2.2 系统架构设计
系统采用典型的三层架构:
┌───────────────────────────────────────┐ │ 客户端层 │ │ (Web浏览器、移动端、API调用端) │ └───────────────┬───────────────┬───────┘ │ │ ┌───────────────▼───────┐ ┌─────▼───────────────┐ │ 表现层 │ │ API网关 │ │ (Vue.js前端界面) │ │ (路由、鉴权、限流) │ └───────────────┬───────┘ └──────────┬──────────┘ │ │ ┌───────────────▼────────────────────▼───────┐ │ 业务逻辑层 │ │ (Spring Boot服务、算法模型调用、业务处理) │ └───────────────┬────────────────────┬───────┘ │ │ ┌───────────────▼───────┐ ┌──────────▼──────────┐ │ 数据访问层 │ │ 模型服务层 │ │ (MySQL数据库操作) │ │ (TensorFlow模型推理) │ └───────────────────────┘ └─────────────────────┘2.3 数据库设计
系统使用MySQL 8.0作为主数据库,主要包含以下表结构:
用户管理模块:
CREATE TABLE `sys_user` ( `id` bigint NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL COMMENT '用户名', `password` varchar(100) NOT NULL COMMENT '密码', `salt` varchar(20) DEFAULT NULL COMMENT '盐', `email` varchar(100) DEFAULT NULL COMMENT '邮箱', `mobile` varchar(100) DEFAULT NULL COMMENT '手机号', `status` tinyint DEFAULT '1' COMMENT '状态 0:禁用 1:正常', `create_time` datetime DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统用户';检测记录模块:
CREATE TABLE `detect_record` ( `id` bigint NOT NULL AUTO_INCREMENT, `user_id` bigint DEFAULT NULL COMMENT '用户ID', `image_path` varchar(255) DEFAULT NULL COMMENT '图片路径', `result_json` text COMMENT '检测结果JSON', `detect_time` datetime DEFAULT NULL COMMENT '检测时间', `device_type` varchar(50) DEFAULT NULL COMMENT '设备类型', `location` varchar(100) DEFAULT NULL COMMENT '地理位置', PRIMARY KEY (`id`), KEY `idx_user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='检测记录表';垃圾类别模块:
CREATE TABLE `garbage_category` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL COMMENT '类别名称', `code` varchar(20) NOT NULL COMMENT '类别编码', `description` varchar(255) DEFAULT NULL COMMENT '类别描述', `create_time` datetime DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `idx_code` (`code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='垃圾类别表';3. CNN模型设计与实现
3.1 数据集准备与预处理
项目使用了自建的水面垃圾数据集,包含以下类别:
- 塑料制品(塑料袋、瓶子等)
- 泡沫制品
- 树枝树叶
- 纸制品
- 其他垃圾
数据集统计:
- 总样本数:12,458张
- 训练集:9,966张(80%)
- 验证集:1,246张(10%)
- 测试集:1,246张(10%)
数据增强策略:
train_datagen = ImageDataGenerator( rotation_range=20, width_shift_range=0.2, height_shift_range=0.2, shear_range=0.2, zoom_range=0.2, horizontal_flip=True, fill_mode='nearest', rescale=1./255 )3.2 模型架构设计
采用改进的ResNet50架构作为基础模型:
def build_model(input_shape=(256, 256, 3), num_classes=5): base_model = ResNet50( weights='imagenet', include_top=False, input_shape=input_shape ) # 冻结基础模型的前面层 for layer in base_model.layers[:100]: layer.trainable = False # 添加自定义层 x = base_model.output x = GlobalAveragePooling2D()(x) x = Dense(1024, activation='relu')(x) x = Dropout(0.5)(x) predictions = Dense(num_classes, activation='softmax')(x) model = Model(inputs=base_model.input, outputs=predictions) model.compile( optimizer=Adam(lr=0.0001), loss='categorical_crossentropy', metrics=['accuracy'] ) return model3.3 模型训练与优化
训练参数配置:
- Batch size: 32
- Epochs: 50
- 初始学习率: 0.0001
- 使用ReduceLROnPlateau回调自动调整学习率
- 使用EarlyStopping防止过拟合
训练过程可视化:
模型评估结果:
- 测试集准确率: 92.3%
- 平均推理时间: 0.15秒/帧
- 模型大小: 98MB
3.4 模型部署方案
采用TensorFlow Serving进行模型部署:
# Dockerfile示例 FROM tensorflow/serving:2.4.0 COPY models/ /models/ ENV MODEL_NAME=floating_garbage EXPOSE 8500 EXPOSE 8501后端服务调用模型示例:
public DetectionResult detectGarbage(String imagePath) { // 图像预处理 BufferedImage image = ImageIO.read(new File(imagePath)); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(image, "jpg", baos); byte[] imageBytes = baos.toByteArray(); // 构建gRPC请求 PredictRequest request = PredictRequest.newBuilder() .setModelSpec(ModelSpec.newBuilder() .setName("floating_garbage") .setSignatureName("serving_default")) .putInputs("input_1", TensorProto.newBuilder() .setDtype(DataType.DT_STRING) .addStringVal(ByteString.copyFrom(imageBytes)) .build()) .build(); // 调用TensorFlow Serving PredictResponse response = stub.predict(request); // 处理返回结果 Map<String, TensorProto> outputs = response.getOutputsMap(); TensorProto outputProto = outputs.get("output_1"); // 转换为DetectionResult对象 return convertToResult(outputProto); }4. 系统功能实现
4.1 用户管理模块
实现基于RBAC的权限控制系统:
@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Autowired private PasswordEncoder passwordEncoder; @Override public User registerUser(UserRegisterDTO dto) { if (userMapper.existsByUsername(dto.getUsername())) { throw new BusinessException("用户名已存在"); } User user = new User(); user.setUsername(dto.getUsername()); user.setPassword(passwordEncoder.encode(dto.getPassword())); user.setEmail(dto.getEmail()); user.setStatus(1); user.setCreateTime(new Date()); userMapper.insert(user); // 分配默认角色 userRoleMapper.insert(new UserRole(user.getId(), 2L)); // 2为普通用户角色 return user; } @Override public PageInfo<UserVO> listUsers(UserQueryDTO query) { PageHelper.startPage(query.getPageNum(), query.getPageSize()); List<User> users = userMapper.selectByQuery(query); return PageInfo.of(users.stream().map(this::convertToVO).collect(Collectors.toList())); } }4.2 图像检测模块
前端上传检测代码示例:
<template> <div class="detect-container"> <el-upload action="/api/detect/upload" :before-upload="beforeUpload" :on-success="handleSuccess" :show-file-list="false" accept="image/*" > <el-button type="primary">上传图片检测</el-button> </el-upload> <div v-if="result" class="result-container"> <h3>检测结果</h3> <el-image :src="imageUrl" fit="contain"></el-image> <el-table :data="result.details" border> <el-table-column prop="category" label="垃圾类别"></el-table-column> <el-table-column prop="confidence" label="置信度"> <template #default="{row}"> {{ (row.confidence * 100).toFixed(2) }}% </template> </el-table-column> <el-table-column prop="location" label="位置"> <template #default="{row}"> ({{ row.x1 }}, {{ row.y1 }}) - ({{ row.x2 }}, {{ row.y2 }}) </template> </el-table-column> </el-table> </div> </div> </template> <script> export default { data() { return { imageUrl: '', result: null } }, methods: { beforeUpload(file) { const isImage = file.type.startsWith('image/') if (!isImage) { this.$message.error('只能上传图片文件') } return isImage }, handleSuccess(response) { this.imageUrl = response.data.imageUrl this.result = response.data.result } } } </script>4.3 历史记录管理
实现检测记录的查询与统计功能:
@RestController @RequestMapping("/api/record") public class RecordController { @Autowired private RecordService recordService; @GetMapping("/list") public Result listRecords(RecordQueryDTO query) { PageInfo<RecordVO> pageInfo = recordService.listRecords(query); return Result.success(pageInfo); } @GetMapping("/statistics") public Result getStatistics(StatisticsQuery query) { Map<String, Object> data = recordService.getStatistics(query); return Result.success(data); } } @Service public class RecordServiceImpl implements RecordService { @Override public Map<String, Object> getStatistics(StatisticsQuery query) { Map<String, Object> result = new HashMap<>(); // 按类别统计 List<CategoryStat> categoryStats = recordMapper.countByCategory(query); result.put("byCategory", categoryStats); // 按时间统计 List<DateStat> dateStats = recordMapper.countByDate(query); result.put("byDate", dateStats); // 总量统计 int totalCount = recordMapper.countTotal(query); result.put("totalCount", totalCount); return result; } }5. 系统测试与优化
5.1 功能测试用例
图像检测功能测试:
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 状态 |
|---|---|---|---|---|
| 正常检测 | 上传清晰的水面垃圾图片 | 返回正确的检测结果和置信度 | 符合预期 | 通过 |
| 空图像 | 上传空白或全黑图片 | 返回"未检测到垃圾"提示 | 符合预期 | 通过 |
| 大文件 | 上传20MB以上的图片 | 返回"文件过大"错误 | 符合预期 | 通过 |
| 非图像文件 | 上传PDF文档 | 提示"不支持的文件格式" | 符合预期 | 通过 |
| 多物体识别 | 上传包含多种垃圾的图片 | 正确识别所有垃圾类别 | 识别率92% | 通过 |
5.2 性能测试结果
使用JMeter进行压力测试:
单接口测试:
- 登录接口:500并发,平均响应时间238ms,错误率0%
- 图像检测接口:100并发,平均响应时间1.2s,错误率0%
混合场景测试:
- 模拟50用户同时操作系统:登录→上传检测→查看历史
- 平均响应时间:890ms
- 吞吐量:68请求/秒
- CPU使用率峰值:78%
- 内存使用峰值:2.3GB/4GB
5.3 模型优化策略
针对实际使用中发现的问题,采取了以下优化措施:
类别不平衡处理:
- 使用类别权重调整损失函数
class_weights = compute_class_weight('balanced', classes, y_train) model.fit(..., class_weight=class_weights)小目标检测优化:
- 在原始模型基础上添加FPN(Feature Pyramid Network)结构
- 使用Focal Loss替代交叉熵损失
推理速度优化:
- 使用TensorRT加速推理
- 将模型量化为FP16精度
- 优化后推理时间从0.15s降至0.08s
数据增强改进:
- 添加针对水面场景的特殊增强:
def water_ripple_augmentation(image): # 模拟水面波纹效果 rows, cols = image.shape[:2] img_output = np.zeros_like(image) for i in range(rows): for j in range(cols): offset_x = int(5.0 * math.sin(2 * 3.14 * i / 60)) offset_y = 0 if j + offset_x < cols: img_output[i,j] = image[i, (j + offset_x) % cols] else: img_output[i,j] = 0 return img_output
6. 项目部署与运维
6.1 服务器环境配置
推荐生产环境配置:
- CPU: Intel Xeon 4核以上
- 内存: 8GB以上
- GPU: NVIDIA T4或以上(如需实时检测)
- 系统: Ubuntu 20.04 LTS
环境安装脚本示例:
# 安装Docker sudo apt-get update sudo apt-get install docker.io sudo systemctl start docker sudo systemctl enable docker # 安装NVIDIA Docker(如使用GPU) distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list sudo apt-get update sudo apt-get install -y nvidia-docker2 sudo systemctl restart docker # 拉取TensorFlow Serving镜像 docker pull tensorflow/serving:2.4.0-gpu6.2 容器化部署
使用Docker Compose编排服务:
version: '3' services: web: image: openjdk:11-jre ports: - "8080:8080" volumes: - ./app.jar:/app.jar environment: - SPRING_PROFILES_ACTIVE=prod - TF_SERVING_HOST=tf-serving command: ["java", "-jar", "/app.jar"] depends_on: - tf-serving - mysql - redis tf-serving: image: tensorflow/serving:2.4.0-gpu ports: - "8500:8500" - "8501:8501" volumes: - ./models:/models environment: - MODEL_NAME=floating_garbage deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu] mysql: image: mysql:8.0 ports: - "3306:3306" environment: - MYSQL_ROOT_PASSWORD=yourpassword - MYSQL_DATABASE=garbage_db volumes: - ./mysql_data:/var/lib/mysql redis: image: redis:6.0 ports: - "6379:6379" volumes: - ./redis_data:/data nginx: image: nginx:1.19 ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf - ./frontend/dist:/usr/share/nginx/html depends_on: - web6.3 监控与日志
使用Prometheus + Grafana监控系统:
Spring Boot配置Prometheus监控:
# application.yml management: endpoints: web: exposure: include: health,info,prometheus metrics: tags: application: ${spring.application.name}Grafana监控面板示例:
日志收集方案:
- 使用ELK(Elasticsearch + Logstash + Kibana)收集分析日志
- 日志格式规范:
@Slf4j @RestController public class DetectController { @PostMapping("/detect") public Result detect(@RequestParam MultipartFile file) { log.info("检测请求接收,文件大小: {}KB", file.getSize()/1024); try { DetectionResult result = detectService.detect(file); log.info("检测完成,结果: {}", result); return Result.success(result); } catch (Exception e) { log.error("检测失败", e); return Result.error("检测失败"); } } }7. 项目总结与改进方向
7.1 项目成果
本项目实现了一个完整的水面漂浮垃圾识别系统,主要成果包括:
- 开发了基于改进ResNet50的垃圾识别模型,准确率达到92.3%
- 构建了完整的B/S架构业务系统,支持用户管理、图像检测、历史查询等功能
- 实现了前后端分离的开发模式,前端使用Vue.js,后端使用Spring Boot
- 设计了高性能的部署方案,支持Docker容器化部署
- 建立了完整的监控体系,包括系统指标、业务日志和模型性能监控
7.2 经验总结
在项目开发过程中积累的主要经验:
数据质量至关重要:初期由于数据标注不统一导致模型性能波动,建立严格的标注规范后效果显著提升
模型服务化考量:
- 需要平衡模型大小和推理速度
- 考虑多模型版本管理和灰度发布
- 监控模型性能衰减,建立定期重训练机制
前后端协作优化:
- 制定统一的API规范
- 使用Swagger维护接口文档
- 建立Mock服务支持并行开发
性能优化技巧:
- 使用Redis缓存频繁访问的数据
- 采用消息队列处理耗时操作
- 前端实现图片压缩上传
7.3 未来改进方向
模型层面:
- 尝试YOLOv5等目标检测模型,实现像素级定位
- 引入半监督学习,减少标注成本
- 开发多模态模型,结合红外等传感器数据
系统功能:
- 增加视频流实时分析功能
- 开发移动端APP,支持现场拍摄检测
- 实现区域污染热力图分析
工程化改进:
- 引入CI/CD自动化部署流程
- 完善自动化测试体系
- 增加模型解释性模块,提高结果可信度
业务扩展:
- 对接政府环保监管平台
- 开发垃圾清理任务调度模块
- 建立污染源追踪分析功能
在实际部署使用过程中,我们发现模型对光线变化较为敏感,下一步计划通过增加数据增强策略和使用更先进的网络结构来提升模型的鲁棒性。同时,我们也在探索将系统与无人机巡检平台集成,实现更大范围的自动化水面监测。