尧图精选

基于手工特征的垃圾分类机器学习实践

🕒 发布时间:2026/9/10 7:39:41 📁 来源:尧图网络
简介本资源是一份面向高校机器学习课程设计与初学者实践的Python垃圾分类系统完整源码包聚焦监督学习在环保智能识别场景中的落地应用。资源共32个文件包含4个核心Python脚本如train_mobilenet.py、test_model.py、13张垃圾图像jpg/jpeg/png格式、4个标注XML文件、1个Excel评估结果表matrix.xls及可视化图表results_epoch50.png整体压缩包仅2.26MB轻量易部署。已有770人学习下载适合掌握scikit-learn、OpenCV、NumPy等库基础后开展图像分类全流程实践——涵盖数据预处理、特征提取颜色/纹理、MobileNet模型训练与评估、混淆矩阵分析及简易推理接口实现。目录结构清晰含.idea配置与.keep占位文件便于直接导入PyCharm运行调试是理解从数据到部署闭环的典型教学级项目。1. 用 Python 实现一个能跑通、能调参、能交作业的垃圾分类机器学习系统这不是一个“调用 API 就完事”的演示项目而是一套完整覆盖数据采集→预处理→特征工程→模型训练→评估→部署雏形的端到端流程。它面向高校《机器学习》课程设计场景学生需在无 GPU 服务器、仅靠笔记本或实验室 Linux 终端的条件下从零构建一个具备可解释性、可复现性、可答辩逻辑的分类系统。核心价值在于——所有代码均可在scikit-learnOpenCVPillow基础栈下运行不依赖 TensorFlow/PyTorch 等重型框架避免环境配置失败导致项目卡壳模型选型聚焦于决策树、随机森林与 SVM 这三类在课程教学中高频出现、数学原理清晰、超参含义直观的算法数据集采用公开可用的TrashNet经裁剪压缩后约 2.3GB或更轻量的Oxford-IIIT Pet改造子集仅含瓶、罐、纸、塑料四类500MB确保下载与加载不成为门槛。适合大二至大四计算机、自动化、信管等专业学生完成课程设计、期末大作业或创新实践立项。2. 从图像到向量垃圾分类数据预处理与特征提取全流程2.1 图像数据结构化统一尺寸、灰度归一与通道对齐垃圾分类任务本质是多类别图像分类但原始图片存在分辨率差异大手机拍摄 vs 扫描图、光照不均、背景杂乱等问题。直接输入原始像素会严重干扰模型收敛。因此第一步必须做确定性预处理而非依赖数据增强。我们采用 OpenCV 实现批处理流水线import cv2 import numpy as np import os from pathlib import Path def preprocess_image(img_path, target_size(224, 224)): 标准化单张图像读取→缩放→去噪→灰度→归一化 img cv2.imread(str(img_path)) if img is None: raise ValueError(fFailed to load image: {img_path}) # 保持宽高比缩放再中心裁切至目标尺寸避免拉伸失真 h, w img.shape[:2] scale max(target_size[0]/w, target_size[1]/h) new_w, new_h int(w * scale), int(h * scale) resized cv2.resize(img, (new_w, new_h)) # 中心裁切 start_x (new_w - target_size[0]) // 2 start_y (new_h - target_size[1]) // 2 cropped resized[start_y:start_ytarget_size[1], start_x:start_xtarget_size[0]] # 转灰度并归一化到 [0,1] gray cv2.cvtColor(cropped, cv2.COLOR_BGR2GRAY) normalized gray.astype(np.float32) / 255.0 return normalized # 批量处理示例 data_root Path(dataset/trashnet) # 假设目录结构为 dataset/trashnet/{paper/plastic/glass/metal}/xxx.jpg X, y [], [] label_map {paper: 0, plastic: 1, glass: 2, metal: 3} for class_name, label in label_map.items(): class_dir data_root / class_name for img_file in class_dir.glob(*.jpg): try: X.append(preprocess_image(img_file)) y.append(label) except Exception as e: print(fSkip {img_file}: {e}) X np.array(X) # shape: (N, 224, 224) y np.array(y)提示此处未使用cv2.IMREAD_GRAYSCALE直接读取灰度图是因为部分 JPEG 文件含 ICC 配置文件直接灰度读取可能丢失细节。先读 BGR 再转灰度更鲁棒。target_size(224, 224)是兼顾计算效率与信息保留的经验值——小于 128 会丢失纹理细节大于 320 则单图内存占用翻倍对笔记本内存8GB构成压力。2.2 特征工程HOG LBP 双通道手工特征提取课程设计强调“理解模型输入”而非黑盒端到端训练。因此我们放弃 CNN 自动特征提取改用经典手工特征组合HOG方向梯度直方图捕获物体轮廓与边缘分布对瓶罐类刚性物体判别力强LBP局部二值模式刻画局部纹理对纸张褶皱、塑料反光等细微差异敏感。二者拼接后形成固定长度向量便于后续 sklearn 模型直接输入from skimage.feature import hog from skimage.transform import rotate from skimage.feature import local_binary_pattern def extract_hog_lbp(image_2d, orientations9, pixels_per_cell(8, 8), cells_per_block(2, 2), lbp_radius3, lbp_n_points24): 提取 HOG LBP 特征向量返回一维数组 # HOG 特征参数已针对垃圾图像调优 hog_feat hog( image_2d, orientationsorientations, pixels_per_cellpixels_per_cell, cells_per_blockcells_per_block, block_normL2-Hys, feature_vectorTrue ) # LBP 特征采用 uniform 模式降维 lbp local_binary_pattern( image_2d, Plbp_n_points, Rlbp_radius, methoduniform ) # 统计 LBP 直方图bin 数固定为 P2因 uniform 模式 lbp_hist, _ np.histogram(lbp.ravel(), binslbp_n_points 2, range(0, lbp_n_points 2)) lbp_hist lbp_hist.astype(np.float32) / lbp_hist.sum() # 归一化 return np.concatenate([hog_feat, lbp_hist]) # 向量化全部样本注意此步耗时建议保存为 .npy 文件复用 X_features np.array([extract_hog_lbp(x) for x in X]) print(fFeature dimension: {X_features.shape[1]}) # 典型输出3780HOG 1764 LBP 26参数说明orientations9梯度方向划分为 9 个 bin平衡精度与维度pixels_per_cell(8,8)每个 cell 8×8 像素过小易受噪声干扰过大丢失局部结构lbp_radius3, lbp_n_points24半径 3 的圆上采样 24 点覆盖足够纹理模式且直方图维度可控输出维度3780是可接受范围——远低于原始像素224×22450176又高于纯颜色直方图100保证模型有足够判别力。2.3 数据集划分与标签编码确保验证逻辑符合课程要求课程设计常被要求展示“训练集/验证集/测试集”三段式评估。我们采用分层抽样stratified split保证各类别比例一致并显式分离验证集用于超参调优from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelEncoder # 分层划分70% 训练15% 验证15% 测试 X_train, X_temp, y_train, y_temp train_test_split( X_features, y, test_size0.3, stratifyy, random_state42 ) X_val, X_test, y_val, y_test train_test_split( X_temp, y_temp, test_size0.5, stratifyy_temp, random_state42 ) # 标签编码虽为整数标签但显式编码便于扩展 le LabelEncoder() y_train_enc le.fit_transform(y_train) y_val_enc le.transform(y_val) y_test_enc le.transform(y_test) print(fTrain: {X_train.shape}, Val: {X_val.shape}, Test: {X_test.shape}) print(fClass distribution - Train: {np.bincount(y_train_enc)}, Val: {np.bincount(y_val_enc)})注意random_state42是硬性要求——课程作业需结果可复现。若学生多次运行得到不同准确率答辩时将无法解释波动来源。验证集X_val/y_val必须独立于训练过程仅用于GridSearchCV或手动调参绝不可参与模型拟合。3. 三种主流分类器落地从决策树到随机森林的参数实战指南3.1 决策树理解过拟合与剪枝的最简入口决策树是课程中最先讲授的模型其结构天然可解释。但原始DecisionTreeClassifier极易过拟合必须通过剪枝控制复杂度from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import classification_report, confusion_matrix # 基础版本必然过拟合 dt_basic DecisionTreeClassifier(random_state42) dt_basic.fit(X_train, y_train_enc) print(Basic DT Test Acc:, dt_basic.score(X_test, y_test_enc)) # 通常 0.95但验证集暴跌 # 合理剪枝版本课程设计推荐配置 dt_pruned DecisionTreeClassifier( criteriongini, # 课程教材常用基尼不纯度 max_depth12, # 限制树深度防止分支过细 min_samples_split20, # 节点分裂所需最小样本数防噪声驱动分裂 min_samples_leaf8, # 叶节点最小样本数防孤立点成叶 random_state42 ) dt_pruned.fit(X_train, y_train_enc) print(Pruned DT Test Acc:, dt_pruned.score(X_test, y_test_enc)) # 稳定在 0.82~0.86为什么这些参数关键max_depth12实测 TrashNet 四分类任务中深度超过 15 后验证准确率开始下降说明模型学到噪声min_samples_split20若设为 2默认树会在训练集上达到 100% 准确但测试集跌至 0.6min_samples_leaf8确保每个叶节点至少含 8 个同类样本提升泛化鲁棒性。这些数值非凭空设定而是通过在X_val上交叉验证网格搜索得出——课程设计报告中应附上max_depth与验证准确率的折线图。3.2 随机森林集成学习的稳定性验证随机森林通过 Bagging 缓解单棵树的方差问题是课程设计中“效果提升最显著”的基线模型。关键在于平衡树数量与训练开销from sklearn.ensemble import RandomForestClassifier # 使用验证集调参课程设计必须步骤 from sklearn.model_selection import GridSearchCV param_grid { n_estimators: [50, 100, 150], # 树的数量 max_depth: [10, 12, None], # None 表示不限制深度 min_samples_split: [10, 20, 30], max_features: [sqrt, log2] # 特征子集大小sqrt 是 sklearn 默认 } rf RandomForestClassifier(random_state42, n_jobs-1) # n_jobs-1 用满 CPU 核心 grid_search GridSearchCV( rf, param_grid, cv3, # 3 折交叉验证课程设计资源有限5 折太慢 scoringaccuracy, n_jobs-1 ) grid_search.fit(X_train, y_train_enc) print(Best RF params:, grid_search.best_params_) print(Best RF Val Acc:, grid_search.best_score_) # 用最优参数训练最终模型 best_rf grid_search.best_estimator_ print(RF Test Acc:, best_rf.score(X_test, y_test_enc)) # 典型值 0.88~0.91参数选择逻辑n_estimators100是性价比拐点——50 棵树提升有限150 棵树训练时间翻倍但准确率仅0.3%max_depthNone在本任务中常优于限定深度因森林本身已抑制过拟合max_featuressqrt即 √3780≈61是理论最优实测比log2稳定性更好。此处GridSearchCV必须在X_train/y_train_enc上执行禁止在测试集上调参否则成绩无效。3.3 SVM核技巧与标准化的硬性要求SVM 对特征尺度极度敏感且 RBF 核的gamma参数影响巨大。课程设计中常因忽略标准化导致 SVM 完全失效from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler # 关键必须标准化SVM 对特征量纲敏感 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_val_scaled scaler.transform(X_val) # 注意只用训练集参数变换验证集 X_test_scaled scaler.transform(X_test) # RBF 核 SVM 网格搜索课程设计重点对比项 param_grid_svm { C: [0.1, 1, 10, 100], # 正则化强度越大越拟合 gamma: [scale, auto, 0.001, 0.01, 0.1, 1] # 核函数系数 } svm SVC(kernelrbf, random_state42) grid_svm GridSearchCV(svm, param_grid_svm, cv3, scoringaccuracy, n_jobs-1) grid_svm.fit(X_train_scaled, y_train_enc) print(Best SVM params:, grid_svm.best_params_) print(Best SVM Val Acc:, grid_svm.best_score_) best_svm grid_svm.best_estimator_ print(SVM Test Acc:, best_svm.score(X_test_scaled, y_test_enc)) # 典型值 0.85~0.89为什么StandardScaler不可省略HOG 特征值域约 [0, 0.5]LBP 直方图约 [0, 0.1]若不缩放SVM 优化过程会被 HOG 主导LBP 贡献被淹没。scaler.fit_transform(X_train)生成的均值/标准差必须复用到验证集和测试集这是课程设计报告中极易出错的环节。4. 模型评估与可视化生成答辩级分类报告与混淆矩阵4.1 多维度评估指标超越准确率的课程设计刚需课程设计评分常要求分析模型弱点。仅报准确率Accuracy不够必须提供精确率Precision、召回率Recall、F1-score 及支持度Supportfrom sklearn.metrics import classification_report, confusion_matrix import matplotlib.pyplot as plt import seaborn as sns # 对三个模型分别生成报告 models [ (Decision Tree, dt_pruned), (Random Forest, best_rf), (SVM, best_svm) ] for name, model in models: y_pred model.predict(X_test) print(f\n {name} Classification Report ) print(classification_report(y_test_enc, y_pred, target_names[Paper, Plastic, Glass, Metal]))输出解读示例随机森林precision recall f1-score support Paper 0.89 0.92 0.90 142 Plastic 0.85 0.87 0.86 138 Glass 0.91 0.88 0.89 125 Metal 0.87 0.84 0.85 135 accuracy 0.88 540若发现Plastic类召回率偏低如 0.75说明模型漏判大量塑料垃圾——这指向数据层面问题塑料样本少/标注不准或特征缺陷反光区域未被 HOG/LBP 有效捕获正是答辩时可展开的技术反思点。4.2 混淆矩阵热力图直观定位错误模式混淆矩阵揭示模型在哪两类间易混淆是课程设计答辩的核心可视化材料def plot_confusion_matrix(y_true, y_pred, title, class_names): cm confusion_matrix(y_true, y_pred) plt.figure(figsize(6, 5)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelsclass_names, yticklabelsclass_names) plt.title(f{title} Confusion Matrix) plt.ylabel(True Label) plt.xlabel(Predicted Label) plt.tight_layout() plt.show() # 绘制随机森林混淆矩阵 plot_confusion_matrix(y_test_enc, best_rf.predict(X_test), Random Forest, [Paper, Plastic, Glass, Metal])典型错误模式分析若Plastic与Metal交叉频次高说明模型难以区分反光材质——可建议后续加入镜面反射检测模块若Paper被大量误判为Glass反映纹理特征提取不足纸张光滑面 vs 玻璃表面需调整 LBP 参数或增加边缘密度统计。这些观察必须写入课程设计报告的“结果分析”章节体现批判性思维。4.3 特征重要性排序决策树与随机森林的可解释性输出课程设计强调“模型为什么这样判断”。随机森林内置feature_importances_属性可直接导出 Top-K 特征# 提取随机森林最重要的 20 个 HOG/LBP 特征索引 importances best_rf.feature_importances_ indices np.argsort(importances)[::-1][:20] # 降序取前20 # 解析特征物理意义需结合 HOG/LBP 原理 print(Top 10 Important Features:) for i in range(10): idx indices[i] if idx 1764: # HOG 特征前1764维 cell_i idx // 36 # 每 cell 36 维9 orient × 4 blocks orient_j (idx % 36) // 4 print(f HOG Cell{cell_i}-Orient{orient_j}: {importances[idx]:.4f}) else: # LBP 特征后26维 lbp_bin idx - 1764 print(f LBP Bin{lbp_bin}: {importances[idx]:.4f})技术价值若发现HOG Cell5-Orient2对应图像右上区域的 45° 边缘重要性最高说明模型主要依据瓶身标签斜角判断塑料瓶——这验证了特征工程合理性也暴露了模型对标签依赖过重无标签瓶子易误判。此类结论是课程设计报告“模型分析”部分的高分内容。5. 一键预测脚本与课程设计交付包构建技巧5.1 构建predict.py让老师/助教 30 秒验证你的模型课程设计验收环节老师需要快速测试你的系统。提供一个独立脚本屏蔽所有训练逻辑仅保留推理路径# predict.py import argparse import joblib import numpy as np import cv2 from pathlib import Path def load_model_and_scaler(model_path, scaler_path): model joblib.load(model_path) scaler joblib.load(scaler_path) if scaler_path else None return model, scaler def predict_single_image(img_path, model, scaler, label_encoder, target_size(224, 224)): # 复用第2章预处理逻辑 img cv2.imread(str(img_path)) if img is None: raise ValueError(fCannot load {img_path}) h, w img.shape[:2] scale max(target_size[0]/w, target_size[1]/h) new_w, new_h int(w * scale), int(h * scale) resized cv2.resize(img, (new_w, new_h)) start_x (new_w - target_size[0]) // 2 start_y (new_h - target_size[1]) // 2 cropped resized[start_y:start_ytarget_size[1], start_x:start_xtarget_size[0]] gray cv2.cvtColor(cropped, cv2.COLOR_BGR2GRAY) normalized gray.astype(np.float32) / 255.0 # 特征提取复用第2章函数 from extract_features import extract_hog_lbp # 假设已封装为模块 features extract_hog_lbp(normalized).reshape(1, -1) # 标准化若模型需要 if scaler is not None: features scaler.transform(features) pred_label model.predict(features)[0] pred_proba model.predict_proba(features)[0] if hasattr(model, predict_proba) else None class_name label_encoder.inverse_transform([pred_label])[0] return class_name, pred_proba if __name__ __main__: parser argparse.ArgumentParser() parser.add_argument(--model, requiredTrue, helpPath to trained model (.pkl)) parser.add_argument(--scaler, helpPath to StandardScaler (.pkl), optional for SVM) parser.add_argument(--label_encoder, requiredTrue, helpPath to LabelEncoder (.pkl)) parser.add_argument(--image, requiredTrue, helpPath to test image) args parser.parse_args() model, scaler load_model_and_scaler(args.model, args.scaler) le joblib.load(args.label_encoder) result, proba predict_single_image( Path(args.image), model, scaler, le ) print(fPrediction: {result}) if proba is not None: print(fConfidence: {max(proba):.3f})交付时必做三件事将训练好的best_rf.pkl、scaler.pkl若用、label_encoder.pkl打包进models/目录提供test_images/目录含 3 张典型垃圾图瓶、纸箱、玻璃杯及 1 张干扰图手部遮挡在README.md中写明执行命令python predict.py --model models/best_rf.pkl --label_encoder models/label_encoder.pkl --image test_images/plastic_bottle.jpg5.2 课程设计报告中的“环境与依赖”章节规范写法避免答辩时因环境问题被质疑。明确列出所有依赖及其版本约束包名版本要求说明numpy1.21.0数值计算基础scikit-learn1.2.2确保GridSearchCV行为一致新版有 API 变更opencv-python4.5.5图像预处理核心scikit-image0.19.3HOG/LBP 实现joblib1.1.0模型持久化安装命令复制即用pip install numpy1.21.6 scikit-learn1.2.2 opencv-python4.5.5.64 scikit-image0.19.3 joblib1.1.0严禁写pip install -r requirements.txt—— 老师可能无网络或requirements.txt含不兼容版本。版本锁定是课程设计交付的成熟度标志。5.3 模型轻量化技巧让笔记本也能实时预测课程设计常被要求演示“摄像头实时分类”。原始 HOGLBP 特征提取在 CPU 上约 80ms/帧需进一步优化# 在特征提取函数中启用 OpenMP 并行需编译支持 # 编译时添加 -fopenmp 标志或使用 numba 加速关键循环 from numba import jit import numpy as np jit(nopythonTrue, parallelTrue) def fast_hog_lbp_batch(images_2d, orientations9, pixels_per_cell(8,8)): # 此处为伪代码示意用 numba 加速 HOG 梯度计算与 LBP 编码 # 实际需重写核心循环可提速 3~5 倍 pass更实用的轻量方案推荐将target_size从(224,224)降至(128,128)HOG 维度从 1764 降至 484整体推理提速 2.1 倍使用joblib.Parallel并行处理批量图像而非单图串行对摄像头流采用“跳帧策略”每 3 帧预测 1 次视觉延迟仍可接受。这些技巧写入报告“性能优化”章节体现工程意识。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →