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

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
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Apache Flink CDC 3.1.0版本知识学习

Apache Flink CDC 3.1.0版本知识学习 一、Flink CDC 3.1 快速预览二、Transformation 支持三、分库分表合并支持四、使用 Kafka Pipeline Sink 高效写入 Canal/Debezium 格式数据五、更高效地实时入湖 Paimon六、其他改进七、Flink CDC 3.1 版本兼容性 一、Flink CDC 3.1 快速预…

[深入理解DDR5] 2-1 封装与引脚

3500字&#xff0c;依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解DDR》 1 DDR5 颗粒 X4 X8 X16 这里的 X8 or X16&#xff0c; 可以理解为一个DRAM芯片有几个存储阵列。“X几”。进行列寻址时会同时从几个阵列的同一个坐标位置读出数据bit来&a…

博客系统(Servlet实现)

目录 1.准备工作 2.数据库设计 2.1表设计 2.2封装数据库操作代码 2.3创建 Blog 类 和 User 类 2.4创建 BlogDao 类和 UserDao 类 3.读取博客列表功能 3.1约定前后端交互接口 3.2实现服务器代码 3.3实现客户端代码 4.实现博客详情 4.1约定前后端交互接口 4.2实现服…

网站流量统计分析

网站流量统计分析&#xff1a;洞悉用户行为的关键 在当今数字化时代&#xff0c;网站流量统计分析已经成为了企业成功的关键因素之一。通过深入了解用户的行为和偏好&#xff0c;企业可以更好地调整其营销策略、优化用户体验以及提高转化率。本文将探讨网站流量统计分析的重要性…

av_dump_format经验分析,FFmpeg获取媒体文件总时长(FLV获取总时长的误区)

播放器有个功能&#xff0c;当用户打开视频时&#xff0c;需要读取媒体文件的总时长等信息&#xff0c;不巧的时&#xff0c;获取FLV时总失败&#xff0c;下面来具体分析下FLV和MP4获取总时长的原因和区别&#xff1a; 播放器有个获取MediaInfo的接口&#xff0c;功能如下&am…

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

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

Linux基础入门和帮助-第二篇

马哥教育 Linux SRE 学习笔记 用户登录信息查看命令 whoami: 显示当前登录有效用户 [rootrocky8 ~]$whoami rootwho: 系统当前所有的登录会话 [rootrocky8 ~]$who root pts/0 2024-05-24 12:55 (10.0.0.1)w: 系统当前所有的登录会话及所做的操作 [rootrocky8 ~]…

Springboot开发 -- Postman 使用指南

引言 在 Spring Boot 应用开发过程中&#xff0c;接口测试是必不可少的一环。Postman 作为一款强大的 API 开发和测试工具&#xff0c;可以帮助开发者轻松构建、测试和管理 HTTP 请求。本文将为大家介绍如何在 Spring Boot 开发中使用 Postman 进行接口测试。 一、准备工作 安…

【算法】分治 - 快速排序

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、颜色分类二、排序数组三、数组中的第k个数四、最小的k个数总结 引言 本节主要介绍快速排序&#xf…

机器学习实验------Adaboost算法

第1关:什么是集成学习 任务描述 本关任务:根据本节课所学知识完成本关所设置的选择题。 第2关: Boosting 任务描述 本关任务:根据本节课所学知识完成本关所设置的选择题。 第3关:Adaboost算法流程 任务描述 本关任务:用Python实现Adaboost,并通过鸢尾花数据集…

聚观早报 | 华为畅享 70S真机图赏;vivo Y200 GT开售

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 5月25日消息 华为畅享 70S真机图赏 vivo Y200 GT开售 一加13部分细节曝光 马斯克谈AI未来 三星Galaxy Z Fold6将…

使用SDL_QT直接播放渲染YUV格式文件

0.前要 下载一个文件&#xff0c;名字为 400_300_25.mp4&#xff0c;我们用ffmplay.exe将其转化为yuv文件&#xff0c;具体操作如下&#xff1a; 进入cmd控制台&#xff0c;进入ffmplay.exe文件的目录下&#xff0c;输入ffmpeg -i 文件名.mp4 文件名.yuv 回车&#xff0c;会生…

每日练习之数学——砝码和天平

砝码和天平 题目描述 运行代码 #include<iostream> using namespace std; int main() {int w,m,T;cin>>T;while(T--){cin>>w>>m;while(m){if((m-1)%w0)m(m-1)/w;else if((m1)%w0)m(m1)/w;else if(m%w0)m/w;else break;}if(!m)cout<<"YES&…

检测头篇 | YOLOv8改进之添加小目标检测头 / 添加大目标检测头 / 减少检测头

前言:Hello大家好,我是小哥谈。本文首先给大家展示原始YOLOv8的网络结构图,然后再对其进行改变,即增加小目标检测头、增加大目标检测头和减少检测头。🌈 目录 🚀1.网络结构图

10.2.k8s的附加组件-Metrics-server组件与hpa资源pod水平伸缩

目录 一、概述 二、安装部署Metrics-Server组件 1.下载Metrics-Server资源清单 2.编辑Metrics-Server的资源清单 3.验证Metrics-Server是否成功安装 4.使用top命令测试是否管用 三、hpa资源实现pod水平伸缩&#xff08;自动扩缩容&#xff09; 1.编写deploy资源清单 2.…

什么是创造力?如何判断自己的创造力?

创造力&#xff0c;主要表现为创新思想、发现和创造新事物的能力&#xff0c;是知识&#xff0c;智力和能力的综合能力&#xff0c;尤其是在职业发展方面&#xff0c;创造力具有重要的意义&#xff0c;企业的核心竞争力就来源于创造力&#xff0c;这就需要具有创造力的员工来推…

HCIP-Datacom-ARST自选题库__OSPF单选【80道题】

1.OSPFV2是运行在IPV4网络的IGP&#xff0c;OSPFV3是运行在IPV6网络的ICP&#xff0c;OSPFV3与OSPFv2的报文类型相同&#xff0c;包括Hello报文、DD报文、LSR报文、LSU报文和LSAck报文。关于OSPFv3报文&#xff0c;以下哪个说法是正确的 OSPFv3使用报文头部的认证字段完成报文…

.DS_store文件

感觉mac里的这个.DS_store文件烦人&#xff0c;老是莫名其妙的出现&#xff0c;然后造成困扰 处理方式如下&#xff1a; import os pic_list os.listdir("./mask_pic/") print(len(pic_list)) # 从文件夹中删掉 if(".DS_Store" in pic_list):print(&quo…

如何关闭或者减少屏蔽 CloudFlare 的真人检测

经常浏览境外网站的应该常碰到一个真人检测的提示(如下图所示)。最近,明月就收到了一个知乎上的付费咨询:问我如何去掉这个提示,由此明月也特别的研究了一下这个“真人检测”,这算是 CloudFlare 的一个特色了,基本上大家看到站点访问有这个提示的几乎都是用了 CloudFlar…