图片分类模型训练及Web端可视化预测(下)——Web端实现可视化预测

news2025/1/13 17:25:47

Web端实现可视化预测

基于Flask搭建Web框架,实现HTML登录页面,编写图片上传并预测展示页面。后端实现上一篇文章所训练好的模型,进行前后端交互,选择一张图片,并将预测结果展示到页面上。

文章目录

  • Web端实现可视化预测
    • 1. 配置Flask环境
    • 2. 登录页面
    • 3. 预测页面
    • 4. 分类模型、权重及类别
    • 5. 主程序搭建及运行
      • 5.1 主程序
      • 5.2 运行
    • 6. 项目打包

1. 配置Flask环境

进入上一篇所创建的环境

conda activate pyweb
pip install flask
pip install flask_cors

下载static文件,并按以下文件夹列表进行放置
链接:https://pan.baidu.com/s/1_c6pIk8RTN-46QFm6W_O8g
提取码:i2kd
在这里插入图片描述

2. 登录页面

login.html,并放置到templates文件夹里

<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
    <meta charset="utf-8">
    <link href="../static/css/style.css" rel='stylesheet' type='text/css' />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script type="application/x-javascript"> addEventListener("load", function() { setTimeout(hideURLbar, 0); }, false); function hideURLbar(){ window.scrollTo(0,1); } </script>
</head>
<body>
    <!-----start-main---->
    <div class="main">
        <div class="login-form">
            <h1>登录</h1>
            <div class="head">
                <img src="../static/images/user.png" alt=""/>
            </div>
            <form action="/login" method="get"> <!-- 添加 action 属性并设置为登录路由 -->
                <input type="text" class="text" name="username" value="USERNAME" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'USERNAME';}" >
                <input type="password" name="password" value="Password" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'Password';}">
                <div class="submit">
                    <input type="submit" onclick="myFunction()" value="LOGIN" >
                </div>
                <p><a href="#">Forgot Password ?</a></p>
            </form>
        </div>
        <!--//End-login-form-->
        <!-----start-copyright---->
        <div class="copy-right">
            <p>HHXC浩瀚星辰<a target="_blank" href=""></a></p>
        </div>
        <!-----//end-copyright---->
    </div>
    <!-----//end-main---->

<div style="display:none"><script src='http://v7.cnzz.com/stat.php?id=155540&web_id=155540' language='JavaScript' charset='gb2312'></script></div>
</body>
</html>

效果如下:
在这里插入图片描述

3. 预测页面

predict.html,同样放置到templates文件夹中

<!DOCTYPE html>
<html>
<head>
    <title>Web上传图片并进行预测</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script src="{{ url_for('static', filename='js/jquery.min.js') }}"></script>
</head>
<body>
<div style="text-align: center">
        <h1 class="hfont">图像分类模型预测及可视化</h1>
    </div>
<!--<h3>请选择图片文件:PNG/JPG/JPEG/SVG/GIF</h3>-->
<div style="text-align: left;margin-left:500px;margin-top:100px;" >

    <div style="float:left;">
        <a href="javascript:;" class="file">选择文件
            <input type="file" name="file" id="file0"><br>
        </a>
        <img src="" id="img0" style="margin-top:20px;width: 35rem;height: 30rem;">
    </div>
    <div style="float:left;margin-left:50px;">
        <select id="modelSelect">
            <option value="AlexNet">AlexNet</option>
            <option value="MobileNetV2">MobileNetV2</option>
            <option value="DenseNet121">DenseNet121</option>
            <option value="ResNet34">ResNet34</option>
        </select>
        <input type="button" id="b0" onclick="test()" value="预测">
        <pre  id="out" style="width:320px;height:50px;line-height: 50px;margin-top:20px;"></pre>
    </div>
</div>

<script type="text/javascript">
    {#监听 file0 按钮, 并获取文件的URL #}
    $("#file0").change(function(){
        var objUrl = getObjectURL(this.files[0]) ;//获取文件信息
        console.log("objUrl = "+objUrl);
        {#将获取的图片显示到img0中#}
        if (objUrl) {
            $("#img0").attr("src", objUrl);
        }
    });

    function test() {
        var fileobj = $("#file0")[0].files[0];
        console.log(fileobj);

        var model = $("#modelSelect").val(); // 获取选择的模型名称

        var form = new FormData();
        form.append("file", fileobj);
        form.append("model", model); // 将选择的模型名称添加到form对象中

        var out='';
        var flower='';
        $.ajax({
            type: 'POST',
            url: "predict",
            data: form,
            async: false,       //同步执行
            processData: false, // 告诉jquery要传输data对象
            contentType: false, //告诉jquery不需要增加请求头对于contentType的设置
            success: function (arg) {
                console.log(arg)
                out = arg.result;
                {#console.log("out:--"+out)#}
            },error:function(){
                console.log("后台处理错误");
            }
        });

        out.forEach(e=>{
            flower+=`<div style="border-bottom: 1px solid #CCCCCC;line-height: 60px;font-size:16px;">${e}</div>`
        });
        //   out.slice(0,1).forEach(e=>{
        //     flower+=`<div style="border-bottom: 1px solid #CCCCCC;line-height: 60px;font-size:16px;">${e}</div>`
        // }); 只显示最大概率的类别

        document.getElementById("out").innerHTML=flower;

    }

    function getObjectURL(file) {
        var url = null;
        if(window.createObjectURL!=undefined) {
            url = window.createObjectURL(file) ;
        }else if (window.URL!=undefined) { // mozilla(firefox)
            url = window.URL.createObjectURL(file) ;
        }else if (window.webkitURL!=undefined) { // webkit or chrome
            url = window.webkitURL.createObjectURL(file) ;
        }
        return url ;
    }
</script>
<style>
    .hfont{
			font-size: 50px; // 大小
			font-weight: 400; // 加粗
			font-family: Miscrosoft Yahei; // 字体
        }
    .file {
        position: relative;
        /*display: inline-block;*/
        background: #CCC ;
        border: 1px solid #CCC;
        padding: 4px 4px;
        overflow: hidden;
        text-decoration: none;
        text-indent: 0;
        width:100px;
        height:30px;
        line-height: 30px;
        border-radius: 5px;
        color: #333;
        font-size: 13px;

    }
    .file input {
        position: absolute;
        font-size: 13px;
        right: 0;
        top: 0;
        opacity: 0;
        border: 1px solid #333;
        padding: 4px 4px;
        overflow: hidden;
        text-indent: 0;
        width:100px;
        height:30px;
        line-height: 30px;
        border-radius: 5px;
        color: #FFFFFF;

    }
    #b0{
        background: #1899FF;
        border: 1px solid #CCC;
        padding: 4px 10px;
        overflow: hidden;
        text-indent: 0;
        width:60px;
        height:28px;
        line-height: 20px;
        border-radius: 5px;
        color: #FFFFFF;
        font-size: 13px;
    }

    /*.gradient{*/

        /*filter:alpha(opacity=100 finishopacity=50 style=1 startx=0,starty=0,finishx=0,finishy=150) progid:DXImageTransform.Microsoft.gradient(startcolorstr=#fff,endcolorstr=#ccc,gradientType=0);*/
        /*-ms-filter:alpha(opacity=100 finishopacity=50 style=1 startx=0,starty=0,finishx=0,finishy=150) progid:DXImageTransform.Microsoft.gradient(startcolorstr=#fff,endcolorstr=#ccc,gradientType=0);!*IE8*!*/
        /*background:#1899FF; !* 一些不支持背景渐变的浏览器 *!*/
        /*background:-moz-linear-gradient(top, #fff, #1899FF);*/
        /*background:-webkit-gradient(linear, 0 0, 0 bottom, from(#fff), to(#ccc));*/
        /*background:-o-linear-gradient(top, #fff, #ccc);*/
    /*}*/
</style>
</body>
</html>

效果如下:
在这里插入图片描述

4. 分类模型、权重及类别

将上一篇训练好的模型权重,及模型代码和类别文件放置到models文件夹中

  • class_indices.json
  • mobilenet_v2.py
  • MobileNetV2.pth

如下:
在这里插入图片描述

5. 主程序搭建及运行

5.1 主程序

main.py

import os
import io
import json
import torch
import torchvision.transforms as transforms
from PIL import Image
from models.mobilenet_v2 import MobileNetV2
from flask import Flask, jsonify, request, render_template, redirect, url_for, session
from flask_cors import CORS

app = Flask(__name__)
CORS(app)  # 解决跨域问题
app.secret_key = 'super_secret_key'  # 设置一个密钥用于 session 加密


@app.route("/", methods=["GET", "POST"])
def root():
    return render_template("login.html")


@app.route("/login", methods=["GET"])
def login():
    print(request.args)
    username = request.args.get('username')
    password = request.args.get('password')

    # 简单验证用户名和密码
    if username == "admin" and password == "123456":
        return render_template("predict.html")
    else:
        return "用户名或者密码错误!重新操作!!!"


# select device
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
class_json_path = "models/class_indices.json"
# load class info
json_file = open(class_json_path, 'rb')
class_indict = json.load(json_file)


def load_model(model_name):
    weights_path = "./models/{}.pth".format(model_name)

    assert os.path.exists(weights_path), "weights path does not exist..."
    assert os.path.exists(class_json_path), "class json path does not exist..."

    print(device)
    # create model
    model = MobileNetV2(num_classes=5).to(device)
    # load model weights
    model.load_state_dict(torch.load(weights_path, map_location=device))

    return model


def transform_image(image_bytes):
    my_transforms = transforms.Compose([transforms.Resize(255),
                                        transforms.CenterCrop(224),
                                        transforms.ToTensor(),
                                        transforms.Normalize(
                                            [0.485, 0.456, 0.406],
                                            [0.229, 0.224, 0.225])])
    image = Image.open(io.BytesIO(image_bytes))
    if image.mode != "RGB":
        raise ValueError("input file does not RGB image...")
    return my_transforms(image).unsqueeze(0).to(device)


def get_prediction(image_bytes, model_name):
    try:
        model = load_model(model_name)
        model.eval()
        tensor = transform_image(image_bytes=image_bytes)
        outputs = torch.softmax(model.forward(tensor).squeeze(), dim=0)
        prediction = outputs.detach().cpu().numpy()
        template = "class:{:<15} probability:{:.3f}"
        index_pre = [(class_indict[str(index)], float(p)) for index, p in enumerate(prediction)]
        # sort probability
        index_pre.sort(key=lambda x: x[1], reverse=True)
        text = [template.format(k, v) for k, v in index_pre]
        return_info = {"result": text}
    except Exception as e:
        return_info = {"result": [str(e)]}
    return return_info


@app.route("/predict", methods=["POST"])
@torch.no_grad()
def predict():
    image = request.files["file"]
    model_name = request.form.get('model')

    img_bytes = image.read()
    info = get_prediction(image_bytes=img_bytes, model_name=model_name)
    return jsonify(info)


if __name__ == '__main__':
    app.run(debug=True)

5.2 运行

python main.py

输入用户名: admin
密码: 123456
注:这个可以在main.py中进更改,代码中又注释
在这里插入图片描述
选择图片
在这里插入图片描述
点击预测
在这里插入图片描述
预测结果展示
在这里插入图片描述

6. 项目打包

PyWeb整体项目已打包,获取方式如下:关注回复 PyWeb
在这里插入图片描述

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

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

相关文章

前端基于word模板导出word文档

项目环境 vue2 js vue-cli等 依赖包都可以在npm官网找到对应文档 npm官网(英文) 1、依赖 安装依赖 docxtemplater npm i docxtemplaterfile-saver npm i file-saverjszip-utils npm i jszip-utilsjszip npm i jszip在对应页面或模块中引入依赖 import Docxtemplater …

探索AI写作工具:五款推荐

在现实生活中&#xff0c;除了专业的文字工作者&#xff0c;各行各业都避免不了需要写一些东西&#xff0c;比如策划案、论文、公文、讲话稿、总结计划……等等。而随着科技的进步&#xff0c;数字化时代的深入发展&#xff0c;AI已经成为日常工作中必不可少的工具了&#xff0…

智慧之选:开源与闭源大模型的未来探索

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

有一个3x4的矩阵,要求编写程序求出其中值最大的那个元素,以及其所在的行号和列号

解题思路&#xff1a; 先考虑解此问题的思路。从若干数中求最大数的方法很多&#xff0c;现在采用"打擂台"的算法。如果有若干人比武&#xff0c;先有一人站在台上&#xff0c;再上去一人与其交手&#xff0c;败者下台&#xff0c;胜者留在台上。第3个人再上…

selenium安装出错

selenium安装步骤&#xff08;法1&#xff09;&#xff1a; 安装失败法1 第一次实验&#xff0c;失败 又试了一次&#xff0c;失败 安装法2-失败&#xff1a; ERROR: Could not install packages due to an EnvironmentError: [WinError 5] 拒绝访问。: c:\\programdata\\a…

【C++题解】1697. 请输出n~1之间所有的整数

问题:1697. 请输出n~1之间所有的整数 类型&#xff1a;循环 题目描述&#xff1a; 从键盘读入一个整数 n &#xff0c;请输出 n∼1 之间所有的整数&#xff0c;每行输出 1 个。 比如&#xff0c;假设读入 n5 &#xff0c;输出结果如下&#xff1a; 5 4 3 2 1 输入&#xff1…

UE5 像素流与web 交互

总结下虚幻与网页的交互&#xff0c;这里将ue5 与js 交互传递参数记录下&#xff0c;其它的博主写的就是缺胳膊少腿的要么就是封闭收费&#xff0c;这个是在官方可以查询到。这里记录下&#xff1a; 点个关注不迷路&#xff1a; 具体的使用如下&#xff1a; 在你的游戏玩家类…

推荐几款新手学习编程的网站

免费在线开发平台 介绍一款编程平台&#xff0c;专为学生和开发者量身打造&#xff01;平台拥有近4000道编程题目&#xff0c;支持多种编程语言&#xff08;包括C、C、JavaScript、TypeScript、Go、Rust、PHP、Java、Ruby、Python3和C#&#xff09;&#xff0c;为您提供全面的学…

【Oracle篇】rman标准化全库备份策略:完整备份or增量备份(第三篇,总共八篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

YoloV8改进策略:蒸馏改进|CWDLoss|使用蒸馏模型实现YoloV8无损涨点|特征蒸馏

摘要 在本文中&#xff0c;我们成功应用蒸馏策略以实现YoloV8小模型的无损性能提升。我们采用了CWDLoss作为蒸馏方法的核心&#xff0c;通过对比在线和离线两种蒸馏方式&#xff0c;我们发现离线蒸馏在效果上更为出色。因此&#xff0c;为了方便广大读者和研究者应用&#xff…

Kubernetes Service 之原理与 ClusterIP 和 NodePort 用法

Kubernetes Service 之原理与 ClusterIP 和 NodePort 用法 Service 定义 在 Kubernetes 中&#xff0c;由于Pod 是有生命周期的&#xff0c;如果 Pod 重启它的 IP 可能会发生变化以及升级的时候会重建 Pod&#xff0c;我们需要 Service 服务去动态的关联这些 Pod 的 IP 和端口…

六个免费的AI制图网站的介绍

六个免费的AI制图网站的介绍 以下是六个免费的AI制图网站的介绍&#xff0c;包括官网、特点、缺点以及使用时的注意事项&#xff1a; 海鲸AI 官网&#xff1a;AI绘画创作平台 - 海鲸AI | 智能艺术生成器特点&#xff1a;支持PC和移动端&#xff0c;集成了Midjourney AI模型&am…

【Spring】SSM介绍_SSM整合

1、SSM介绍 1.1简介 SSM&#xff08;Spring SpringMVC MyBatis&#xff09;整合是一种流行的Java Web应用程序框架组合&#xff0c;它将Spring框架的核心特性、SpringMVC作为Web层框架和MyBatis作为数据访问层框架结合在一起。这种整合方式提供了从数据访问到业务逻辑处理再…

jmeter之测试计划

一、测试计划作用 测试计划是jmeter的默认控件所有线程组都是测试计划的下级控件测试计划可以配置用户自定义的变量测试计划可以配置线程组的串行或并行 二、查看界面 名称&#xff1a;可以修改自定义的名称注释&#xff1a;解释测试计划是用来做什么的用户自定义的变量&…

【Jmeter】使用Jmeter进行接口测试、跨线程组获取参数

Jmeter接口测试 Jmeter设置成中文实操练习-跨线程组提取参数&#xff0c;使用值HTTP请求默认值&HTTP信息头管理器 相信打算从事测试工程师的同学们&#xff0c;肯定对Jmeter是耳熟能详的。使用Jmeter可以进行接口测试、性能测试、压力测试等等&#xff1b;这个章节介绍如何…

在使用LabVIEW控制多个串口设备进行数据读取时,读取时间过长

在使用LabVIEW控制多个串口设备进行数据读取时&#xff0c;如果发现数据更新时间超过5秒&#xff0c;可以从以下几个方面进行分析和解决&#xff1a; 1. 串口配置与通信参数 确保每个串口的通信参数&#xff08;波特率、数据位、停止位、校验位等&#xff09;配置正确&#x…

百度软件测试面试经历,期望薪资27K

一面 1、 请为百度搜索框设计测试用例&#xff1f; 2、百度设计框上线前需要进行那些测试&#xff1f; 界面测试&#xff0c;功能测试&#xff0c;性能测试&#xff0c;安全性测试&#xff0c;易用性测试&#xff0c;兼容性测试&#xff0c;UI测试。 3、如何查看http状态码…

23. 【Java教程】接口

本小节我们将学习 Java 接口&#xff08;interface&#xff09;&#xff0c;通过本小节的学习&#xff0c;你将了解到什么是接口、为什么需要接口、如何定义和实现接口&#xff0c;以及接口的特点等内容。最后我们也将对比抽象类和接口的区别。 1. 概念 Java 接口是一系列方法的…

感恩父母的短视频:成都科成博通文化传媒公司

感恩父母的短视频&#xff1a;情深意重&#xff0c;温馨传递 在这个快节奏、信息化的时代&#xff0c;短视频以其独特的方式&#xff0c;迅速成为了人们表达情感、分享生活的重要工具。成都科成博通文化传媒公司而当我们把镜头对准父母&#xff0c;用短视频的形式记录下对他们…

【面试干货】矩阵对角线元素之和

【面试干货】矩阵对角线元素之和 1、实现思想2、代码实现 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 1、实现思想 创建一个3x3的二维数组来表示输入的矩阵。通过嵌套循环读取输入的矩阵元素&#xff0c;并将其保存到数组中。再次嵌套循…