mouceMice智能垃圾分类系统

news2024/11/16 11:51:45

mouceMice智能垃圾分类系统

1.成员名称和任务分配

成员认领任务
陈曦实现登录、注册、检索垃圾类型和前端部分实现、连接树莓派实现socket通信传输图片
杨雨佳需求分析和总体进展监督
郑博文部分前端页面实现及其优化
李睿初步实现深度学习算法、树莓派连接和算法效率提升
范兴宇项目测试

2、项目简介,涉及技术

自19年垃圾分类政策试行,全国从46个垃圾分类试点城市实行开始,垃圾分类就变成了城市生活中的该同志们的一个重要需求。垃圾分类有助于该同志们日常生活的清洁方便,同样也有助于垃圾回收的高效利用。但对于许多人来说,如何甄别垃圾类型并正确投放是一件比较困难的事情。在大城市生活的人们日常的时间精力已经被生活所压榨殆尽,没有更多的时间和意愿去系统的学习垃圾分类的专业知识。智能垃圾分类系统可以省去人们学习专业知识的时间,并尽可能减少人为误差,做到全民普及的垃圾精准分类识别。

涉及技术:

微服务框架及其中间键:springCloudAlibabaspringredisnacosribbongateway

数据库:mysqlmybatis plus

机器学习:Pythochresnet18随机森林

前端:HTMLcssjavaScriptVue

树莓派:raspberry pisocket

测试工具:postmanjmeter

3、本项目的git地址

https://github.com/xiudian7/LitterSortSystem

4、项目git提交记录截图

image-20240611203231611

5、前期调查

5.1 功能需求

(1)数据收集:收集大量垃圾图像数据,并进行标记分类,建立训练所需的数据集。

(2)特征提取:使用图像处理技术提取垃圾图像的特征,如颜色、形状、纹理等,以便于机器学习模型识别。

(3)模型选择与训练:选择合适的机器学习模型,如卷积神经网络(CNN),进行训练以实现图像分类任务。

(4)模型优化与评估:通过交叉验证、超参数调优等方法优化模型性能,并使用测试集评估模型准确率和泛化能力。

(5)系统集成:将训练好的模型集成到垃圾分类系统中,实现实时监测和自动分类功能。

(6)用户界面设计:设计用户友好的界面,使用户可以轻松地与系统交互和操作。

5.2 限制条件

垃圾分类目前还停留在人工识别分类上,智能分类的普及度不高。

系统应该能够适应不同的屏幕大小和分辨率,以便用户在不同的设备上使用。

5.3 目标用户

垃圾分类智能监测的目标市场主要包括城市管理部门、垃圾处理企业和居民社区等。 垃圾分类智能监测系统的应用将帮助城市管理部门更加高效地监测和管理垃圾分类工作,提高垃圾分类的准确率和效率,从而解决垃圾问题,促进城市的可持续发展。 垃圾处理企业也是垃圾分类智能监测的重要用户。

6.项目代码结构图

image-20240611203948217

本次的实验我们分为了几个模块来写,首先第一个模块是机器学习模型训练模块model_code,其次是后端微服务的模块,有sort_commonsort_gateway等等模块,最后是前端的模块sort_website

7.项目运行截图

QQ2024611-213553

树莓派拍摄图片:

image-20240611215200195

image-20240611215015254

image-20240611215119167

8.项目关键代码分模块描述

8.1 前端模块

login.html

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>用户登录</title>
    <link href="/styles/base.css" rel="stylesheet" type="text/css">
    <link href="/styles/login.css" rel="stylesheet" type="text/css">
    <script src="/js/plugins/js-cookie/js.cookie.min.js"></script>
    <script src="/js/vue/md5.js"></script>
    <script src="/js/jquery/jquery.js"></script>
    <script src="/js/vue/common.js"></script>
    <script src="/js/vue/vue.min.js"></script>
</head>
<body>
<div class="wrapper"  id="app" v-cloak>
    <div class="container container-login">
        <a href="javascript:;" title="返回首页" class="logo">老鼠爱大米</a>
        <div class="signup-forms flip">
            <div class="login-box" id="_j_login_box">
                <div class="inner inner_v2 clearfix">
                    <div class="inner_v2_left">
                        <form id="_j_login_form" method="post" >
                            <div class="form-field">
                                <input name="username" type="text" placeholder="您的手机号" autocomplete="off"
                                       data-verification-name="帐号"  value="13700000000">
                                <div class="err-tip"></div>
                            </div>
                            <div class="form-field">
                                <input name="password" type="password" placeholder="您的密码" autocomplete="off" data-verification-name="密码"
                                       class="verification[required,minSize[4],maxSize[50]]" value="1111">
                                <div class="err-tip"></div>
                            </div>
                            <div class="form-link"><a href="javascript:;">忘记密码</a></div>
                            <div class="submit-btn">
                                <button @click="login" type="button">登 录</button>
                            </div>
                        </form>
                        <div class="connect">
                            <p class="hd">用合作网站账户直接登录</p>
                            <div class="bd">
                                <a href="javascript:;" class="weibo"><i></i>新浪微博</a>
                                <a href="javascript:;" class="qq"><i></i>QQ</a>
                                <a href="javascript:;" class="weixin"><i></i>微信</a>
                                <div class="clear"></div>
                            </div>
                        </div>                        </div>
                    <div class="inner_v2_right">
                        <img src="/images/xiudian.jpg">
                        <p>欢迎来到老鼠爱大米智能垃圾分类系统</p>
                    </div>
                </div>
                <div class="bottom-link">
                    还没有帐号?<a href="/regist.html">马上注册</a>
                </div>
            </div>
        </div>

    </div>
</div>
<div class="fullscreen-bg"
     style="background-image: url(images/34.jpg);">
    <img src="images/34.jpg" style="width: auto; height: 657px; margin-top: -213px;">
</div>
</body>
<script src="js/vue/system/userinfo/login.js"></script>
</html>

regist.html

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>用户注册</title>
    <link href="/styles/base.css" rel="stylesheet" type="text/css">
    <link href="/styles/regist.css" rel="stylesheet" type="text/css">
    <script type="text/javascript" src="/js/jquery/jquery.js"></script>
    <script src="/js/plugins/js-cookie/js.cookie.min.js"></script>
    <script type="text/javascript" src="/js/vue/common.js"></script>
    <script src="/js/vue/vue.min.js"></script>

</head>
<body>
<div class="wrapper"  id="app" v-cloak>
    <div class="container container-login">
        <a href="javascript:;" title="返回首页" class="logo">老鼠爱大米</a>
        <div class="signup-forms flip">
            <div class="login-box" id="_j_login_box">
                <div class="inner inner_v2 clearfix">
                    <div class="inner_v2_left">
                        <form id="_j_login_form" action="javascript:;">
                            <div class="form-field">
                                <input id="inputPhone" type="text" placeholder="您的手机号" autocomplete="off"  value="">
                                <div class="err-tip"></div>
                            </div>
                            <div class="submit-btn">
                                <button id="_js_loginBtn" @click="phoneCheck">立即注册</button>
                            </div>
                        </form>
                        <div class="agreement">
                            注册视为同意<a target="_blank" href="javascript:;">《老鼠爱大米用户使用协议》</a>
                        </div>
                        <div class="connect">
                            <p class="hd">用合作网站账户直接登录</p>
                            <div class="bd">
                                <a href="javascript:;" class="weibo"><i></i>新浪微博</a>
                                <a href="javascript:;" class="qq"><i></i>QQ</a>
                                <a href="javascript:;" class="weixin"><i></i>微信</a>
                                <div class="clear"></div>
                            </div>
                        </div>                        </div>
                    <div class="inner_v2_right">
                        <img src="/images/xiudian.jpg">
                        <p>我是老鼠爱吃大米</p>
                    </div>
                </div>
            </div>
            <div class="signup-box" style="display: none;">
                <div class="add-info">
                    <div class="hd">账号注册</div>
                    <form  method="post" id="editForm">
                        <input type="hidden" name="phone" value="" id="phone">
                        <div class="form-field m-t-10">
                            <input name="gender" type="text" placeholder="您的性别 0:男 1:女" >
                            <div class="err-tip"></div>
                        </div>
                        <div class="form-field">
                            <input name="password" type="password" placeholder="您的密码">
                            <div class="err-tip"></div>
                        </div>
                        <div class="form-field">
                            <input name="rpassword" type="password" placeholder="确认密码" >
                            <div class="err-tip"></div>
                        </div>

                        <div class="form-field">
                            <div class="clearfix">
                                <a href="#" class="vcode-send sms-code-send" @click="sendCode($event)">获取验证码</a>
                                <input name="verifyCode" type="text" placeholder="短信验证码" autocomplete="off"class="vcode-input">
                            </div>
                            <div class="err-tip clearfix"></div>
                        </div>
                        <div class="submit-btn">
                            <button type="button" @click="regist">立即注册</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
<div class="fullscreen-bg"
     style="background-image: url('images/27.jpg');">
    <img src="images/27.jpg" style="width: auto; height: 657px; margin-top: -213px;">
</div>
</body>
<script src="js/vue/system/userinfo/regist.js"></script>
</html>

识别垃圾模块index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>狼行天下</title>
    <link href="/styles/base.css" rel="stylesheet" type="text/css">
    <link href="/styles/index.css" rel="stylesheet" type="text/css">
    <link href="/js/plugins/jqPaginator/jqPagination.css" rel="stylesheet" type="text/css">
    <script type="text/javascript" src="/js/jquery/jquery.js"></script>
    <script type="text/javascript" src="/js/plugins/jquery-form/jquery.form.js"></script>
    <script type="text/javascript" src="/js/plugins/jqPaginator/jq-paginator.min.js"></script>
    <script src="/js/vue/md5.js"></script>
    <script src="/js/plugins/js-cookie/js.cookie.min.js"></script>
    <script type="text/javascript" src="/js/vue/common.js"></script>
    <script type="text/javascript" src="/js/system/index/index.js"></script>
    <script src="./js/vue/vue.min.js"></script>
    <script src="/js/vue/system/index/index.js"></script>
    <style>
        button {
            margin: 20px;
        }
        .frame{
            height: 100vh;
            width: 100%;
            justify-content: center;
            display: flex;
            align-items: center;
        }
        .custom-btn {
            width: 200px;
            height: 100px;
            color: #fff;
            border-radius: 5px;
            padding: 10px 25px;
            font-family: 'Lato', sans-serif;
            font-weight: 1000;
            font-size: large;
            background: transparent;
            cursor: pointer;
            transition: all 0.3s ease;
            position: relative;
            display: inline-block;
            box-shadow: inset 2px 2px 2px 0px rgba(255, 255, 255, .5),
            7px 7px 20px 0px rgba(0, 0, 0, .1),
            4px 4px 5px 0px rgba(0, 0, 0, .1);
            outline: none;
        }
        /* 9 */
        .btn-9 {
            border: none;
            transition: all 0.3s ease;
            overflow: hidden;
            margin: 0 auto;
        }

        .btn-9:after {
            position: absolute;
            content: " ";
            z-index: -1;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: #1fd1f9;
            background-image: linear-gradient(315deg, #1fd1f9 0%, #b621fe 74%);
            transition: all 0.3s ease;
        }

        .btn-9:hover {
            background: transparent;
            box-shadow: 4px 4px 6px 0 rgba(255, 255, 255, .5),
            -4px -4px 6px 0 rgba(116, 125, 136, .2),
            inset -4px -4px 6px 0 rgba(255, 255, 255, .5),
            inset 4px 4px 6px 0 rgba(116, 125, 136, .3);
            color: #fff;
        }

        .btn-9:hover:after {
            -webkit-transform: scale(2) rotate(180deg);
            transform: scale(2) rotate(180deg);
            box-shadow: 4px 4px 6px 0 rgba(255, 255, 255, .5),
            -4px -4px 6px 0 rgba(116, 125, 136, .2),
            inset -4px -4px 6px 0 rgba(255, 255, 255, .5),
            inset 4px 4px 6px 0 rgba(116, 125, 136, .3);
        }
    .loading {
        width: 100px;
        height: 100px;
        background: url("../images/loading.png") no-repeat;
        background-size: 100% 100%;
        display: none;
        animation: rotating 3s infinite linear;
    }
        @keyframes rotating {
            0% {
                transform: rotate(0deg) /*动画起始位置为旋转0度*/
            }

            to {
                transform: rotate(1turn) /*动画结束位置为旋转1圈*/
            }
        }

    </style>
</head>
<body>
<div id="navbar">
    <!--导航栏-->
    <script>
        var currentNav = "index";
        $('#navbar').load('/views/common/navbar.html');
    </script>
</div>

<div class="frame">
    <button class="custom-btn btn-9" @click="identifyClick">点我分类!</button>
    <div class="loading"></div>
</div>

</body>
<!--<script src="./js/vue/system/index/index.js"></script>-->
<script>
    $('.btn-9').click(function (){
        console.log(1111)
        console.log('执行click')
        const formData = new FormData()
        $('.btn-9').hide()
        $('.loading').show()
        console.log('user', user)
        formData.append('token', token)
        formData.append('user', JSON.stringify(user))
        fetch("http://localhost:8082/functions/identify", {
            method: "POST",
            headers:{
                "token":getToken()
            },
            body: formData
        })
            .then(response => {
                $('.btn-9').show()
                $('.loading').hide()
                if (!response.ok) {
                    throw new Error('网络错误,请稍后再试!');
                }
                return response.json(); // 解析后端返回的JSON数据
            })
            .then(data => {
                // 输出后端返回的data值
                if(data.code == 200){
                    console.log('后端返回的data值:', data);
                    popup("垃圾类型为:"+data.data)
                }
                else{
                    popup(data.msg)
                }

            });
    })
</script>
</html>
8.2 后端代码模块
8.2.1 鉴定模块
public String identify() {
        String substring = UUID.randomUUID().toString().substring(0, 6);
        String imagePath="D:\\CodePractice\\litter_sort_system\\model_code\\images\\"+substring+".jpg";
        takePhoto(imagePath);
        int res=sendIdentifyMsg("images/"+substring+".jpg");
        //int i = identifyResult(substring+".jpg");
        //数字标识:class_labels = ["glass", "paper", "cardboard", "plastic", "metal", "trash"]
        String []information={"玻璃","纸张","纸皮","塑料","金属","废料"};
        System.out.println(information[res]);
        return information[res];
    }
8.2.2 请求连接树莓派,并且拍照
public void takePhoto(String filePath) {
        // 配置连接参数
        final String ip = "192.168.60.193";
        final int port = 4567;
        // 获取当前工作目录
        String workingDirectory = System.getProperty("user.dir");
        // 打印工作目录
        System.out.println("当前工作目录: " + workingDirectory);
        // 创建文件并加载流
        File file = new File(filePath);
        if(!file.exists()) {
            try {
                if (file.createNewFile()) {
                    System.out.println("文件已创建: " + filePath);
                } else {
                    System.out.println("文件创建失败: " + filePath);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        try(Socket socket = new Socket(ip, port);
            FileOutputStream fos=new FileOutputStream(filePath)
        ) {
            System.out.println("已连接到服务器端口,准备接收图片...");

            InputStream inputStream = socket.getInputStream();
            // 定义缓存数组,每次只读1024字节
            byte[] buf = new byte[1024];
            int len = 0;
            while((len = inputStream.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
8.2.3 树莓派socketServer
package edu.jmu;

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
import java.util.concurrent.*;

public class SocketServer {
    // 配置连接参数
    public final static int port = 4567;

    // 执行拍照,返回图片路径
    public static String getPhoto() throws IOException, InterruptedException {
        String substring = UUID.randomUUID().toString().substring(0, 6);
        Process process = Runtime.getRuntime().exec("ffmpeg -i /dev/video0 -frames:v 1 -f image2 "+substring+".jpg");
        process.waitFor(); //等待拍照完成
        return "/home/xiudian/mouseMice/"+substring+".jpg";
    }

    // 发送图片
    public static void send(Socket socket, String filePath) throws IOException {
        // 加载图片
        FileInputStream fis = new FileInputStream(filePath);
        // 获取自己的输出流
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
        // 设置缓存数组
        byte[] buf = new byte[1024];
        int len = 0;
        // 发送图片
        while ((len = fis.read(buf)) != -1) {
            bufferedOutputStream.write(buf, 0, len);
        }
        // 通知, 数据发送完毕
        bufferedOutputStream.flush();
        // 关闭资源
        socket.shutdownOutput();
        bufferedOutputStream.close();
    }

    public static void main(String[] args) throws IOException {
        ExecutorService executorService = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(5, true),
                Executors.defaultThreadFactory());

        ServerSocket server = null;
        try {
            server = new ServerSocket(port);
            System.out.println("服务器启动成功");
            Socket socket = null;
            int count = 0; // 统计客户端的数量
            while (true) {
                socket = server.accept();
                count++;
                String clientIp = socket.getInetAddress().getHostAddress();
                System.out.println("第 " + count + " 个客户端成功连接,IP 地址: " + clientIp);
                final Socket clientSocket = socket;
                executorService.execute(() -> {
                    try {
                        String filePath = getPhoto();
                        send(clientSocket, filePath);
                        clientSocket.close(); //关闭Socket
                    } catch (IOException | InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                });
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (server != null) {
                server.close(); //关闭ServerSocket
            }
        }
    }
}

8.2.4 调用http请求,请求使用python封装的识别垃圾的代码
 public int sendIdentifyMsg(String path) {
        int prediction = -1;
        try {

            // 创建 URL 对象
            URL url = new URL("http://localhost:5000");

            // 打开连接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            // 设置请求方法为 POST
            connection.setRequestMethod("POST");

            // 设置请求头
            connection.setRequestProperty("Content-Type", "application/json; utf-8");
            connection.setRequestProperty("Accept", "application/json");

            // 允许写入
            connection.setDoOutput(true);

            // 创建 JSON 请求体
            String jsonInputString = String.format("{\"imagePath\": \"%s\"}", path);

            // 将请求体写入到连接的输出流中
            try (OutputStream os = connection.getOutputStream()) {
                byte[] input = jsonInputString.getBytes("utf-8");
                os.write(input, 0, input.length);
            }

            // 获取响应码
            int code = connection.getResponseCode();
            System.out.println("Response Code: " + code);

            // 读取响应内容
            StringBuilder response = new StringBuilder();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"))) {
                String responseLine;
                while ((responseLine = br.readLine()) != null) {
                    response.append(responseLine.trim());
                }
            }

            // 解析 JSON 响应
            JSONObject jsonResponse = JSON.parseObject(response.toString());
            prediction = jsonResponse.getIntValue("prediction");
            System.out.println(prediction);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return prediction;
    }

这一步是提升运行效率的关键一步,在alpha阶段我们使用jpython使用java调用python的代码,每次调用代码的时候都得重新启动,效率极低,一次的鉴定结果大概需要4-5s,而这次我们将python代码直接打包成一个web服务,我们直接使用http端口请求,时间大概为1-2s,效率大幅提升。

8.2.5 训练模型

使用Resnet18提取图像特征,随机森林作为分类器

model = models.resnet50(pretrained=True)
feature_extractor = FeatureExtractor(model)
feature_extractor.eval()

# 使用GPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
feature_extractor = feature_extractor.to(device)

print("特征提取器加载完成")

# 将数据集加载到特征提取器中
def extract_features(data_loader):
    features = []
    labels = []
    with torch.no_grad():
        for images, label in data_loader:
            images = images.to(device)
            output = feature_extractor(images)
            features.append(output.cpu().numpy())
            labels.append(label.numpy())
    features = np.vstack(features)
    labels = np.concatenate(labels)
    return features, labels

# 定义训练和验证函数
def train_and_evaluate(epochs):
    best_val_accuracy = 0.0
    for epoch in range(epochs):
        print(f"Epoch {epoch + 1}/{epochs}")

        # 提取训练、验证和测试集的特征
        print("开始提取训练集特征...")
        train_features, train_labels = extract_features(train_loader)
        print("训练集特征提取完成")

        print("开始提取验证集特征...")
        val_features, val_labels = extract_features(val_loader)
        print("验证集特征提取完成")

        print("开始提取测试集特征...")
        test_features, test_labels = extract_features(test_loader)
        print("测试集特征提取完成")

        # 训练随机森林分类器
        print("开始训练随机森林分类器...")
        random_forest = RandomForestClassifier(n_estimators=100)
        random_forest.fit(train_features, train_labels)
        print("随机森林分类器训练完成")

        # 验证随机森林分类器
        print("开始验证随机森林分类器...")
        val_preds_rf = random_forest.predict(val_features)
        val_accuracy_rf = accuracy_score(val_labels, val_preds_rf)
        print(f"随机森林验证集准确率: {val_accuracy_rf * 100:.2f}%")

        if val_accuracy_rf > best_val_accuracy:
            best_val_accuracy = val_accuracy_rf
            best_random_forest = random_forest

    # 保存最好的随机森林分类器
    joblib.dump(best_random_forest, 'best_random_forest.pkl')
    print("最好的随机森林分类器已保存")

    # 测试最好的随机森林分类器
    print("开始测试最好的随机森林分类器...")
    test_preds_rf = best_random_forest.predict(test_features)
    test_accuracy_rf = accuracy_score(test_labels, test_preds_rf)
    print(f"随机森林测试集准确率: {test_accuracy_rf * 100:.2f}%")

# 训练和评估模型
epochs = 5
train_and_evaluate(epochs)
8.2.6 将模型通过HTTP提供服务

这是python的Web服务端,客户端在8.2.4有请求示例

import torch
import torch.nn as nn
from torchvision import transforms, models
from PIL import Image
import joblib
from flask import Flask, request, jsonify

torch.hub.set_dir('./modelCache')
# 定义特征提取器
class FeatureExtractor(nn.Module):
    def __init__(self, model):
        super(FeatureExtractor, self).__init__()
        self.features = nn.Sequential(*list(model.children())[:-1])

    def forward(self, x):
        x = self.features(x)
        x = torch.flatten(x, 1)
        return x


model = models.resnet50(pretrained=True)
feature_extractor = FeatureExtractor(model)
feature_extractor.eval()

# 使用GPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
feature_extractor = feature_extractor.to(device)

# print("特征提取器加载完成")

# 数据转换
transform = transforms.Compose([
    transforms.Resize((512, 384)),
    transforms.ToTensor(),
])

# 加载保存的模型
random_forest = joblib.load('best_random_forest.pkl')

# print("模型加载完成")

def classify_image(image_path, model):
    image = Image.open(image_path)
    image = transform(image)
    image = image.unsqueeze(0).to(device)

    with torch.no_grad():
        feature = feature_extractor(image).cpu().numpy()

    prediction = model.predict(feature)
    return prediction[0]


# 创建Flask应用
app = Flask(__name__)


@app.route('/', methods=['POST'])
def classify():
    data = request.json
    if 'imagePath' not in data:
        return jsonify({'error': 'No imagePath provided'}), 400

    imagePath = data['imagePath']
    try:
        prediction = classify_image(imagePath, random_forest)
        return jsonify({'prediction': int(prediction)}), 200
    except Exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

9.项目测试

步骤编号测试步骤预测结果测试结果
LitterSort-1登录账号为空提示账号为空Pass
LitterSort-2登录账号格式错误提示格式错误Pass
LitterSort-3登录密码为空提示密码为空Pass
LitterSort-4登录密码错误提示密码错误Pass
LitterSort-5登入账号密码正确提示账号密码正确并跳转Pass
LitterSort-6未登录上传图片鉴别提示请先登录Pass
LitterSort-7上传图片鉴别结果输出垃圾类型Pass
LitterSort-8照片中有些杂物准确识别Fail
LitterSort-9鉴定代码后端控制台返回正确结果Pass
LitterSort-10页面正确显示点击每个按键有回应Pass
LitterSort-11页面参数正确传送到后台后台正确接受参数Pass
LitterSort-12账号已经被注册提示账号已经被注册Pass
LitterSort-13发送验证码正确发送验证码并给出提示Pass
LitterSort-14注册账号格式错误提示账号格式错误Pass
LitterSort-15注册时两次密码不一致提示两次密码不一致Pass
LitterSort-16正确填写信息注册成功数据库添加代码并且跳转登录界面Pass
LitterSort-17使用拍照功能进行图片识别输出输出垃圾类型Pass

对鉴定垃圾模块进行压力测试(点击50次,间隔1ms)

image-20240611210356713

10.项目总结

从我们的调查结果和使用反馈来看,我们的系统做的还是相对比较成功的,识别垃圾的准确率能达到80%左右,在这个项目中,我们使用一些目前比较流行的中间键和主流的框架,也基本达到了项目代码简洁和注释清楚的要求。用户也对我们的系统提出了挺多的意见,虽然我们的识别速度相对于alpha阶段已经有了很大的提升,从4-5s的识别时间提升到了1-2s,但是用户对于这些时间还是比较敏感的,所以我们后续还得继续对机器学习的准确度和效率进行改进提升,当然当我们所拍摄的图片中有一些杂物的话,系统还是不能很准确的显示出垃圾类型,也需要进行改进。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1812718.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【AI法官】人工智能判官在线判案?

概述 AI法官是一款为用户提供专业法律分析和判决建议的智能体应用。用户只需简要描述案情&#xff0c;AI法官便会利用其强大的法律知识和逻辑推理能力&#xff0c;快速且准确地梳理出判决结果。该应用的目标是为用户提供高效、准确、合法的判决建议。 角色任务 任务描述 作为…

【CS.SE】2024年,你应该选择计算机专业吗?详细分析与未来展望

文章目录 1. 引言1.1 背景介绍 2. 计算机相关专业的现状与挑战2. 计算机相关专业的现状与挑战2.1 行业内的就业趋势2.1.1 现有就业数据2.1.2 行业需求变化 2.2 市场饱和度与竞争2.2.1 毕业生数量增长2.2.2 薪资与职业发展 2.3 技术创新与行业发展2.3.1 新兴技术的发展2.3.2 全球…

TinyHttpd源码精读(三)

在上一章中我们一起看了如何实现静态的网页&#xff0c;在这里我们一起看Tinyhttpd最后的一部分&#xff0c;动态网页的实现&#xff1a;在这里首先声明下因为cgi脚本的支持问题&#xff0c;所以我会新建一个简单的cgi脚本然后将路径导向到这个脚本&#xff1a; 0.perl的配置&…

2024年建筑、水利交通与工程管理国际学术会议(ICAWRTEM 2024)

全称&#xff1a;2024年建筑、水利交通与工程管理国际学术会议&#xff08;ICAWRTEM 2024&#xff09; 会议网址:http://www.icawrtem.com会议地点: 广州投稿邮箱&#xff1a;icawrtemsub-conf.com 投稿标题&#xff1a;ICAWRTEM 2024ArticleTEL。投稿时请在邮件正文备注&#…

MySQL之高级特性(一)

高级特性 外键约束 InnoDB是目前MySQL中唯一支持外键的内置存储引擎&#xff0c;所以如果需要外键支持那选择就不多了。使用外键是有成本的。比如外键通常都要求每次在修改数据时都要在另一张表中多执行一次查找操作。虽然InnoDB强制外键使用索引&#xff0c;但还是无法消除这…

一夜之间,苹果杀死无数AI工具创业公司!GPT-4o深度整合进苹果

就在刚刚&#xff0c;苹果发布会WWDC2024官宣了一系列AI相关的重磅升级。 由于这一波AI升级攒的太大了&#xff0c;苹果甚至索性创造了一个新的概念——苹果智能&#xff08;Apple Intelligence&#xff09;。 如果你认为 苹果智能 Siri升级&#xff0c;那你就大错特错了。 …

分层解耦

三层架构 controller:控制层&#xff0c;接收前端发送的请求&#xff0c;对请求进行处理&#xff0c;并响应数据&#xff0c; service:业务逻辑层&#xff0c;处理具体的业务逻辑。 dao:数据访问层(Data Access Object)(持久层)&#xff0c;负责数据访问操作&#xff0c;包括数…

动态规划(多重背包问题+二进制优化)

引言 多重背包&#xff0c;相对于01背包来说&#xff0c;多重背包是每个物品会有相应的个数&#xff0c;最多可以选那么多个&#xff0c;因而对于朴素多重背包&#xff0c;需要在01背包的基础上&#xff0c;再加一层物品的循环 朴素多重背包例题 P2347 [NOIP1996 提高组] 砝…

【Affine / Perspective Transformation】

文章目录 仿射变换介绍仿射变换 python 实现——cv2.warpAffine透视变换透视变换 python 实现——cv2.warpPerspective牛刀小试各类变换的区别与联系仿射变换和单应性矩阵透视变换和单应性矩阵 仿射变换介绍 仿射变换&#xff08;Affine Transformation&#xff09;&#xff0…

【话题】评价GPT-4o:从革命性技术到未来挑战

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读小5的系列文章&#xff0c;这是《话题》系列文章 目录 引言技术原理应用领域实际案例优势挑战局限性未来展望文章推荐 引言 在人工智能领域&#xff0c;自然语言处理&#xff08;NLP&#xff09;技术的进步一直是推动技术革…

odoo15升级odoo16遇到的问题及解决过程

odoo15升级odoo16遇到的问题 PyMuPDF 档案管理整理时,从15升级16出现如下错误: File "f:\od162306\dms\dmssp\models\shenqb.py", line 136, in doc_fj_pdf doc.SaveAs(ftem, FileFormat=17) # input_file.replace(".docx", ".pdf") F…

鸿蒙开发文件管理:【@ohos.environment (目录环境能力)】

目录环境能力 该模块提供环境目录能力&#xff0c;获取内存存储根目录、公共文件根目录的JS接口。 说明&#xff1a; 本模块首批接口从API version 8开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。本模块接口为系统接口&#xff0c;三方应用不支…

Pythone 程序打包成 exe

1.安装pyinstaller # 安装 pip install pyinstaller # 查看版本 pyinstaller -v2.更新pyinstaller 版本 # 更新 pip install --upgrade pyinstaller # 查看版本 pyinstaller -v3.切换到 py文件所在目录 #切换到.py所在的目录 E: cd cd E:\x-svn_x-local\04PythoneProjects\A…

滴滴出行 大数据研发实习生【继任】

大数据研发实习生JD 职位描述 1、负责滴滴核心业务的数据建设&#xff0c;设计并打造适应滴滴一站式出行平台业务特点的数仓体系。 2、负责抽象核心业务流程&#xff0c;沉淀业务通用分析框架&#xff0c;开发数仓中间层和数据应用产品。 3、负责不断完善数据治理体系&#xff…

远程链接服务 ssh

① 指定用户身份登录 ssh root10.36.105.100 ssh jim10.36.105.100 ② 不登陆远程执行命令 ssh root10.36.105.100 ls /opt ③ 远程拷贝 scp -r // 拷贝目录 -p // 指定端口 将本地文件拷贝给远程主机 scp -r /opt/test1 10.36.105.100:/tmp/// 将本…

使用 ML.NET CLI 自动进行模型训练

ML.NET CLI 可为 .NET 开发人员自动生成模型。 若要单独使用 ML.NET API(不使用 ML.NET AutoML CLI),需要选择训练程序(针对特定任务的机器学习算法的实现),以及要应用到数据的数据转换集(特征工程)。 每个数据集的最佳管道各不相同,从所有选择中选择最佳算法增加了复…

轻兔推荐 —— NeatDownloadManager

via&#xff1a;轻兔推荐 - https://app.lighttools.net/ 简介 NeatDownloadManager简称NDM&#xff0c;跟IDM同样出名的网络下载器&#xff0c;安装对应的浏览器器扩展后&#xff0c;可接管浏览器下载 - 软件体积非常小&#xff0c;Windows版900KB&#xff0c;很难想象当今的…

UE5 渲染性能优化 学习笔记

主要考虑三个点&#xff1a; 1、灯光 2、半透明物体 3、后处理 1、Game&#xff1a;CPU对游戏代码的处理工作 2、Draw&#xff1a;CPU为GPU准备数据所做的工作 3、GPU Time&#xff1a;就是GPU所渲染需要花的时间 UE5的命令行指令 里面说明了某个指令有什么用处 以及启动…

隐私计算(1)数据可信流通

目录 1. 数据可信流通体系 2. 信任的基石 3.数据流通中的不可信风险 可信链条的级联失效&#xff0c;以至于崩塌 4.数据内循环与外循环&#xff1a;传统数据安全的信任基础 4.1内循环 4.2外循环 5. 技术信任 6. 密态计算 7.技术信任 7.1可信数字身份 7.2 使用权跨域…

【大数据·hadoop】项目实践:IDEA实现WordCount词频统计项目

一、环境准备 1.1&#xff1a;在ubuntu上安装idea 我们知道&#xff0c;在hdfs分布式系统中&#xff0c;MapReduce这部分程序是需要用户自己开发&#xff0c;我们在ubuntu上安装idea也是为了开发wordcount所需的Map和Reduce程序&#xff0c;最后打包&#xff0c;上传到hdfs上…