基于深度学习的电子垃圾与混合材料图像分类系统实战:ResNet-50迁移学习+Django部署+三种识别入口完整方案

计算机毕设指导师

⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。

⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!也可以在主页上或文末下与博主交流~~

⚡⚡Java、Python、小程序、大数据实战项目集](https://blog.csdn.net/2301_80395604/category_12487856.html)

⚡⚡文末获取源码

温馨提示:文末有CSDN平台官方免费提供的博客联系方式!

温馨提示:文末有CSDN平台官方免费提供的博客联系方式!

温馨提示:文末有CSDN平台官方免费提供的博客联系方式!

电子垃圾图像分类系统-简介

这套电子垃圾图像分类系统是纯Python技术栈做的:后端是Django框架,前端是Vue2,中间靠接口通信,属于典型的前后端分离毕设项目。它要做的事情是把图片里的东西分到17个类别里,10类电子设备加7类混合材料,比如电池、键盘、微波炉、手机、鼠标、电路板、打印机、电视机、洗衣机是一组,纸板、玻璃、金属、有机物、纸张、塑料、其他垃圾是另一组。数据集有6782张图,来自Kaggle公开数据集,每类样本量都在395到400张之间,分布很均衡。数据这一步做得比较细:先对全量图片做了校验和画像,统计了分辨率、色彩模式、损坏率这些指标,又用工具查出了重复图和疑似错标的样本;划分训练、验证、测试集的时候按7比1.5比1.5来,重复的图片会被归到同一个集合里,避免测试指标虚高。模型训练用的是ResNet-50做迁移学习,开标签平滑来容忍数据里少量噪声,配合早停机制,65轮左右就收敛了,测试集上Macro-F1到0.96左右。训好的模型导出成ONNX文件,网站后端加载它来推理,推理时还配了能量分数和KNN两道门做域外判断,遇到训练集里没见过的东西会给出提示而不是硬分类。网页端给了图片、视频、摄像头三种识别方式,每次识别的记录都会落库,历史页面支持搜索、分页、看详情,管理员还能管理用户。首页的数据大屏用ECharts画了六张图,识别总量和各类别分布一目了然。

电子垃圾图像分类系统-核心功能

  1. 图片识别
    上传一张或多张图片,后端预处理后交给模型推理,返回TopK分类结果和置信度,页面上能看到每张图识别成了什么、把握有多大。
  2. 视频识别
    本地选一个视频播放,系统在关键帧位置自动抽帧送模型识别,适合演示一段画面里不同物品陆续出现的过程。
  3. 摄像头实时识别
    打开电脑摄像头定时抓帧识别,拿着实物对着镜头就能看到识别结果实时变化,是答辩演示环节最直观的一个功能。
  4. 识别历史管理
    每次识别自动落库,历史页面支持条件搜索、分页浏览,点进详情能看到原图、识别类别和完整字段信息,不想要的记录可以删除。
  5. 数据大屏
    用ECharts画了六张图,加上识别总数统计,把系统运行以来的识别情况汇总展示,深色主题视觉效果也不错。
  6. 用户与权限
    分管理员和普通用户两种角色,支持注册登录,管理员可以管理用户账号,普通用户有自己的个人中心和修改密码入口,两边看到的菜单不一样。

电子垃圾图像分类系统-视频

基于深度学习的电子垃圾与混合材料图像分类系统实战

电子垃圾图像分类系统-图片展示

电子垃圾图像分类系统-代码

python 复制代码
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("EwasteClassificationStats").master("local[*]").getOrCreate()
# ========== 核心功能1:图像识别推理处理(图片上传 -> 预处理 -> ONNX推理 -> 域外判断 -> 落库) ==========
def ai_predict(request):
    upload = request.FILES.get('image')
    if upload is None:
        return JsonResponse({'code': 1, 'msg': '未收到图片文件'})
    save_dir = os.path.join(settings.MEDIA_ROOT, 'detection')
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)
    file_name = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f') + os.path.splitext(upload.name)[1]
    file_path = os.path.join(save_dir, file_name)
    with open(file_path, 'wb') as fp:
        for chunk in upload.chunks():
            fp.write(chunk)
    img = Image.open(file_path).convert('RGB')
    proto = json.load(open('models/resnet50/preprocess.json', encoding='utf-8'))
    img = img.resize((proto['size'], proto['size']), Image.BILINEAR)
    arr = np.asarray(img, dtype=np.float32) / 255.0
    arr = (arr - np.array(proto['mean'], dtype=np.float32)) / np.array(proto['std'], dtype=np.float32)
    arr = arr.transpose(2, 0, 1)[np.newaxis, ...]
    session = get_inference_session()
    logits = session.run(None, {session.get_inputs()[0].name: arr})[0][0]
    probs = softmax(logits)
    energy = float(-np.log(np.sum(np.exp(logits) + 1e-9)))
    ood_cfg = json.load(open('models/resnet50/inference_config.json', encoding='utf-8'))
    knn_score = query_feat_bank(arr, ood_cfg)
    if energy > ood_cfg['energy_threshold'] and knn_score < ood_cfg['knn_threshold']:
        return JsonResponse({'code': 3, 'msg': '疑似域外对象,已拒识', 'energy': energy})
    labels_zh = json.load(open('models/resnet50/labels_zh.json', encoding='utf-8'))
    topk_idx = np.argsort(-probs)[:5]
    topk = [{'class_id': int(i), 'name': labels_zh[str(i)], 'prob': round(float(probs[i]), 4)} for i in topk_idx]
    detected = topk[0]['name']
    detectionrecord.objects.create(
        user_id=request.session.get('uid'), task_type='image',
        image_path='media/detection/' + file_name,
        detected_classes=detected, confidence=topk[0]['prob'],
        topk_json=json.dumps(topk, ensure_ascii=False), is_deleted=False)
    return JsonResponse({'code': 0, 'data': {'topk': topk, 'energy': round(energy, 4)}})
# ========== 核心功能2:识别历史分页查询与条件搜索(归属校验+软删过滤+关键词匹配) ==========
def detectionrecord_page(request):
    page = int(request.POST.get('page', 1))
    limit = int(request.POST.get('limit', 10))
    keyword = request.POST.get('search_keyword', '').strip()
    task_type = request.POST.get('task_type', '').strip()
    role = request.session.get('role')
    uid = request.session.get('uid')
    if role != '管理员' and not uid:
        return JsonResponse({'code': 1, 'msg': '登录状态失效,请重新登录'})
    queryset = detectionrecord.objects.filter(is_deleted=False)
    if role != '管理员':
        queryset = queryset.filter(user_id=uid)
    if task_type in ('image', 'video', 'camera'):
        queryset = queryset.filter(task_type=task_type)
    if keyword:
        queryset = queryset.filter(Q(detected_classes__icontains=keyword) | Q(image_path__icontains=keyword))
    total = queryset.count()
    rows = queryset.order_by('-create_time')[(page - 1) * limit: page * limit]
    data_list = []
    for row in rows:
        item = {
            'id': row.id, 'task_type': row.task_type, 'image_path': row.image_path,
            'detected_classes': row.detected_classes, 'confidence': float(row.confidence),
            'create_time': row.create_time.strftime('%Y-%m-%d %H:%M:%S')}
        img_abs = os.path.join(settings.BASE_DIR, row.image_path)
        if os.path.exists(img_abs):
            with open(img_abs, 'rb') as fp:
                item['thumb_base64'] = 'data:image/jpeg;base64,' + base64.b64encode(make_thumb(fp.read())).decode()
        data_list.append(item)
    return JsonResponse({'code': 0, 'data': {'total': total, 'list': data_list, 'page': page, 'limit': limit}})
# ========== 核心功能3:识别数据大屏聚合统计(六图数据+总数对账,Spark侧做分组汇总) ==========
def recognition_dash(request):
    uid = request.session.get('uid')
    if not uid:
        return JsonResponse({'code': 1, 'msg': '登录状态失效,请重新登录'})
    role = request.session.get('role')
    df = spark.read.jdbc(url=SPARK_JDBC_URL, table='detectionrecord', properties=SPARK_PROPS)
    df = df.filter((df.is_deleted == False) & (df.detected_classes.isNotNull()))
    if role != '管理员':
        df = df.filter(df.user_id == uid)
    total = df.count()
    class_pdf = df.groupBy('detected_classes').count().orderBy(F.desc('count')).toPandas()
    type_pdf = df.groupBy('task_type').count().toPandas()
    df = df.withColumn('day', F.substring('create_time', 1, 10))
    trend_pdf = df.groupBy('day').count().orderBy('day').toPandas()
    conf_pdf = df.groupBy('detected_classes').agg(F.round(F.avg('confidence'), 4).alias('avg_conf')).toPandas()
    hour_pdf = df.withColumn('hour', F.substring('create_time', 12, 2)).groupBy('hour').count().orderBy('hour').toPandas()
    rank_pdf = df.groupBy('detected_classes').agg(F.count('id').alias('times')).orderBy(F.desc('times')).limit(5).toPandas()
    charts = {
        'class_bar': {'categories': class_pdf['detected_classes'].tolist(), 'values': class_pdf['count'].tolist()},
        'type_pie': [{'name': r['task_type'], 'value': int(r['count'])} for _, r in type_pdf.iterrows()],
        'trend_line': {'days': trend_pdf['day'].tolist(), 'values': trend_pdf['count'].tolist()},
        'conf_bar': {'categories': conf_pdf['detected_classes'].tolist(), 'values': conf_pdf['avg_conf'].tolist()},
        'hour_bar': {'hours': hour_pdf['hour'].tolist(), 'values': hour_pdf['count'].tolist()},
        'top_rank': [{'name': r['detected_classes'], 'value': int(r['times'])} for _, r in rank_pdf.iterrows()]}
    chart_total = sum(len(v) if isinstance(v, list) else len(v.get('values', [])) for v in charts.values())
    return JsonResponse({'code': 0, 'data': {'total': total, 'charts': charts, 'reconcile': chart_total}})

电子垃圾图像分类系统-结语

不少同学私信问毕设选题和这个系统的细节,回复不过来啦。想深入了解这套电子垃圾图像分类系统的同学,可以去我主页看看,那边能联系到技术员,很多问题聊两句就清楚了。觉得内容有用的话,顺手点个赞、收藏一下,关注不迷路,后面还会更新别的毕设项目。有疑问也欢迎在评论区留言,看到都会回,大家一起把毕设这关稳稳过掉。

实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!

如果遇到具体的技术问题或其他需求,你也可以问我,我会尽力帮你分析和解决问题所在,支持我记得点赞、收藏,再点个关注,学习不迷路!~~

相关推荐
lucas_AI1 小时前
PyTorch、JAX 全中招:Softmax 藏了两个数值 Bug,DeepMind 用十余行代码修好了
深度学习
外收内放1 小时前
FastAPI猜字谜实战(5):会话管理
开发语言·python·学习·fastapi
垆边人似月.1 小时前
选型与快速跑通(Tesseract / EasyOCR / PaddleOCR)
前端·python
Carl_奕然1 小时前
【智能体】Loop 的四种设计模式之:Verification Loop(2026 最新版)
人工智能·python·设计模式
茉莉玫瑰花茶1 小时前
线性代数 [ 矩阵乘法与线性变换复合的联系 ]
python·线性代数·math
garmin Chen1 小时前
Rag引入
python·agent·rag
小oo呆6 小时前
【学习心得】Python多线程
python
happylifetree9 小时前
Python70:核心语法-函数进阶-案例2
python
王中阳Go10 小时前
两个入口答案不一致先别调模型:6 行入口口径对账表(附脚本)
人工智能·后端·python·大语言模型·1024程序员节