Qpython+Flask监控添加发送语音中文信息功能

对Qpython+Flask实现对小孩学习的监控-CSDN博客中html页面进行改造,利用Ajax,提交一段文字,发送到数据库,再在服务器,发送该段文件给手机端,然手机端TTS朗读出来,增加了父母监控小孩学习,自定义提醒小孩的功能。

一、index.html的更改。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>实时**学习情况图</title>
    <script type="text/javascript">
        // 设置定时器,每20秒(20000毫秒)刷新一次页面
        setInterval(function(){ 
            location.reload(); 
        }, 20000);
    </script>    
    <script>
        function submitForm() {
            // 获取文本输入框的值
            var text = document.getElementById('textInput').value;

            // 创建一个XMLHttpRequest对象
            var xhr = new XMLHttpRequest();

            // 配置请求:POST方法,请求的URL,以及是否异步
            xhr.open("POST", "/submit", true);

            // 设置请求头,指定内容类型为表单数据
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

            // 定义当请求完成并成功时的回调函数
            xhr.onreadystatechange = function () {
                if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
                    // 解析并处理服务器的响应
                    var response = xhr.responseText;
                    document.getElementById('response').innerText = response;
                }
            };

            // 编码表单数据并发送
            var formData = "textInput=" + encodeURIComponent(text);
            xhr.send(formData);

            // 阻止表单的默认提交行为
            return false;
        }
    </script>
</head>
<body>
    <h1>学习情况,每20秒刷新一次页面</h1>
    <div>
        <img src="{
  
  { image_url }}" alt="Latest Image">
    </div>
    <h1>状态:{
  
  { qk }} </h1>
    <form onsubmit="return submitForm();">
        <label for="textInput">输入文字发给手机说:</label><br><br>
        <textarea id="textInput" name="textInput" rows="1" required></textarea><br><br>
        <input type="submit" value="提交">
    </form>
    <p id="response"></p>
<p>
<a href="http://192.168.99.235:5000/qk" target="_self">查看实时学习情况</a>
</p>
</body>
</html>

二、flask服务器端

# -*- coding: utf-8 -*-
"""
Created on Wed Jan 15 22:39:02 2025

@author: Ybk
"""
from flask import Flask, jsonify, send_from_directory, render_template, request
import time
import os
from pathlib import Path
import sqlite3
import datetime
import torch
import torch.nn as nn
from torchvision import transforms, models
from PIL import Image
import broadlink
import plotly.graph_objects as go
# 加载模型
# 加载模型并设置为评估模式
model = models.resnet18(pretrained=False)  # 假设使用的是resnet18
num_ftrs = model.fc.in_features  # 获取输入特征数量
model.fc = nn.Linear(num_ftrs, 6)  # 将输出特征数量改为4
model.load_state_dict(torch.load('best66_resnet18_model.pth'))  # 加载模型参数
model.to('cuda' if torch.cuda.is_available() else 'cpu')  # 移动到设备上
model.eval()  # 设置为评估模式

# 定义预处理步骤
preprocess = transforms.Compose([
    transforms.Resize(224),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
app = Flask(__name__)
db_filepath = Path(__file__).joinpath("../jk.db").resolve()

# 设置上传文件的目录和允许的文件扩展名
now = datetime.datetime.now()
date_str = now.strftime("%Y%m%d")
UPLOAD_FOLDER = fr'd:\upload\{date_str}'
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

# 创建上传目录如果不存在
if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)
def insertdb(sj,furl,xl,zt,qk): #插入一行数据zt1为有人0为无人
    conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
    c = conn.cursor()
    insert_query = "INSERT INTO jkme(sj,furl,xl,zt,qk) VALUES(?,?,?,?,?);"
    insert_data = (sj,furl,xl,zt,qk)
    c.execute(insert_query,insert_data)
    conn.commit()
    c.close()
    conn.close    
def insertmsg(msg): #插入一行数据zt1为有人0为无人
    conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
    c = conn.cursor()
    insert_query = "INSERT INTO jkmsg(sj,msg,zt) VALUES(?,?,0);"
    now = datetime.datetime.now()
    sj = now.strftime("%Y-%m-%d %H:%M:%S")
    insert_data = (sj,msg)
    c.execute(insert_query,insert_data)
    conn.commit()
    c.close()
    conn.close 
# 检查文件是否是允许的类型
def allowed_file(filename):
    # 检查文件名是否包含点,并且文件扩展名(转换为小写后)是否在允许的扩展名集合中
    if '.' in filename:
        # 获取文件扩展名,并转换为小写
        file_extension = filename.rsplit('.', 1)[-1].lower()
        # 检查扩展名是否在允许的集合中
        return file_extension in ALLOWED_EXTENSIONS
    else:
        # 如果文件名不包含点,则扩展名不存在或不合法
        return False

def sc_xxqkpng():    
    conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
    c = conn.cursor()
    #lastxxid,bsj,esj
    cursor = c.execute("SELECT id,sj FROM jkme WHERE qk = 4 and sj > datetime('now', 'localtime', '-120 minute') order by id desc")
    row = cursor.fetchone()
    if row:
        lastxxid = row[0]
        lastxxsj = row[1]
        cursor = c.execute(f"SELECT count(id) FROM jkme WHERE id > {lastxxid}")
        row = cursor.fetchone()
        if row[0] > 50:
            fig = go.Figure()
            # 定义颜色列表
            colors = ['cyan','blue','yellow', 'green']
            cursor = c.execute(f"SELECT qk FROM jkme WHERE id > {lastxxid}")
            rows = cursor.fetchall()
            list0 = [row[0] for row in rows]
            # 初始化一个空列表来存储结果
            result = []    
            # 初始化变量来跟踪当前数字及其起始位置
            current_number = None
            start_index = None    
            alltime=0
            rztime=0
            lktime=0
            # 遍历数字序列
            for i, number in enumerate(list0):
                # 如果当前数字与之前的数字不同(或者是第一个数字)
                if number == 0:
                    lktime = lktime + 1
                if number in (1,2):
                    alltime = alltime + 1
                    if number == 1:
                        rztime = rztime + 1
                if current_number is None or number != current_number:
                    # 如果之前已经有过数字,则记录其范围
                    if current_number is not None:
                        result.append([current_number, start_index, i - 1])
                    # 更新当前数字和起始位置
                    current_number = number
                    start_index = i
            
            # 处理序列中的最后一个数字范围
            if current_number is not None:
                result.append([current_number, start_index, len(list0) - 1])
            all_data_tj = len(list0)
            for xlist in result:    
                # print(xlist)
                # 添加矩形   
                # 添加一个矩形形状,没有边框
                fig.add_shape(
                    type="rect",
                    x0=1+xlist[1]*2,  # 矩形左下角的x坐标
                    y0=1,  # 矩形左下角的y坐标
                    x1=1+(xlist[2]+1)*2,  # 矩形右上角的x坐标
                    y1=6,  # 矩形右上角的y坐标        
                    fillcolor=colors[xlist[0]],  # 矩形的填充颜色
                    line=dict(width=0)  # 设置边框宽度为0,即没有边框
                )
                i = i + 1
            
            xxtime = int(alltime / 6)
            rztime = round(rztime / alltime * 100,2)
            lktime = round(lktime / all_data_tj * 100,2)
            all_time = int(all_data_tj / 6)
            # 设置图的标题和坐标轴的限制
            cursor = c.execute(f"SELECT sj FROM jkme WHERE id > {lastxxid} order by id asc")
            row = cursor.fetchone()
            bsj = row[0]
            cursor = c.execute("SELECT sj FROM jkme order by id desc")
            row = cursor.fetchone()
            esj = row[0]
            sjstr = bsj.split()[0] + ' ' + bsj.split()[1] + '-' + esj.split()[1]

            # 设置布局以隐藏背景和坐标轴
            # 更新图形的布局,隐藏坐标轴和背景
            fig.update_layout(
                xaxis=dict(
                    range=[0,(all_data_tj+1)*2],
                    showgrid=False,  # 隐藏网格线
                    zeroline=False,  # 隐藏零轴线
                    visible=False    # 隐藏x轴
                ),
                yaxis=dict(
                    range=[0,5],
                    showgrid=False,  # 隐藏网格线
                    zeroline=False,  # 隐藏零轴线
                    visible=False    # 隐藏y轴
                ),
                plot_bgcolor='white',  # 设置背景颜色为透明
                paper_bgcolor='white',   # 设置整个图形的背景颜色为透明
                
                title=dict(
                    text=f'{sjstr} 学习情况图',  # 标题文本
                    font=dict(
                            size=16,  # 字体大小
                            color='black'  # 字体颜色
                        ),
                    x=0.5,  # 标题水平居中
                    xanchor='center',  # 相对于x位置的锚点设置为中心
                    y=0.8,  # 标题的垂直位置(可选,根据需要调整)
                    yanchor='top'  # 相对于y位置的锚点设置为顶部
                ),
                annotations=[
                    dict(
                        text=f'总{all_time}分钟,学习{xxtime}分钟,认真学习时间占{rztime}%,离开学习占总时间{lktime}%',  # 注释的文本内容
                        x=0.5,  # 注释的水平位置(相对于图表宽度的比例)
                        y=-0.2,  # 注释的垂直位置(相对于图表高度的比例,负值表示在图表下方)
                        xref='paper',  # 参照物为整个图表区域('paper')而非数据坐标('x')
                        yref='paper',  # 参照物为整个图表区域('paper')而非数据坐标('y')
                        showarrow=False,  # 不显示箭头
                        font=dict(
                            size=14,  # 字体大小
                            color='black'  # 字体颜色
                        ),
                        align='center'  # 文本对齐方式
                    )
                ],
                width=800,     # 设置图表宽度(可选)
                height=240     # 设置图表高度(可选)
            )
            pngfilename = esj.replace('-','').replace(' ','').replace(':','') 
            # 显示图表
            # fig.show()
            fig.write_image(rf'D:\sb\xx\{pngfilename}.png')
            insert_query = "INSERT INTO qkpng(url) VALUES(?);"
            insert_data = (rf'D:\sb\xx\{pngfilename}.png',)
            c.execute(insert_query,insert_data)
            conn.commit()

            print(rf'D:\sb\xx\{pngfilename}.png')
            c.close()
            conn.close()
            return f'学习{xxtime}分钟,认真学习时间占{rztime}%'
        else:
            c.close()
            conn.close()
            return '学习情况不能统计!'
    else:
        c.close()
        conn.close()
        return '学习情况不能统计!'
    
    
def getprexl(): #获取最后一个xl
    conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
    c = conn.cursor()
    cursor = c.execute("select xl from jkme order by id desc limit 0,1;")
    row = cursor.fetchone()
    if row:
        xl = row[0]
    else:
        xl = 0
    c.close()
    conn.close
    return xl
def turntolight(turn):#turn=true为开灯,turn=false为关灯    
    try:
        device = broadlink.sp4(host=('192.168.99.50',80), mac=bytearray.fromhex('E81656CA934B'), devtype=32021)
        device.auth()
        state = device.check_power()
        if turn:
            if state == True:
                print(" ON pass")
            elif state == False:
                device.set_power(True)
                print(" ON")
        else:
            if state == False:
                print(" OFF pass")
            elif state == True:
                device.set_power(False)
                print(" OFF")
    except Exception as e:
        print(e)
# turntolight(False)
@app.route('/upload', methods=['POST'])
def upload_file():
    now = datetime.datetime.now()
    # 检查请求中是否包含'description'参数
    description = request.form.get('description')
    if not description:
        return jsonify({'error': 'No description provided'}), 400

    # 检查是否有文件在请求中
    if 'file' not in request.files:
        return jsonify({'error': 'No file part in the request'}), 400
    
    file = request.files['file']
    
    # 如果用户没有选择文件,返回错误
    if file.filename == '':
        return jsonify({'error': 'No selected file'}), 400
    
    # 如果文件合法,尝试保存文件
    if file and allowed_file(file.filename):
        filename = file.filename
        filepath = os.path.join(app.config['UPLOAD_FOLDER'], description.replace(' ','').replace('-','').replace(':','') + '.' + filename.rsplit('.', 1)[-1])
        file.save(filepath)
        res = 'ok'
        xl = 0
        tj = 0
        tjx = 0
        qkz = 0
        msg = ''
        if filepath:
            img = Image.open(filepath)  # 加载图片
            img_tensor = preprocess(img)  # 预处理图片
            img_tensor = img_tensor.unsqueeze(0)  # 增加batch维度
            img_tensor = img_tensor.to('cuda' if torch.cuda.is_available() else 'cpu')  # 移动到设备上
            # 进行推理
            with torch.no_grad():
                outputs = model(img_tensor)
                _, predicted = torch.max(outputs, 1)
            # 解释结果
            result = int(predicted.item())
            if result == 0:
                res = '**没在学习'
            elif result == 1:
                res = 'ok'
            elif result == 2:
                res = '**要认真学习'
            elif result == 3:
                res = '是**'
            elif result == 4:
                res = '是爸爸'
            elif result == 5:
                res = '是其他人'
            if result > 2:
                result = 3
            #正常情况
            xl = 0 
            zt = 0
            #如果26分钟内1和2,已经超过138个,那么设置为2,2    
            conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
            c = conn.cursor()
            cursor = c.execute("SELECT count(*) FROM jkme WHERE zt = 0 and (qk > 0 and qk < 4) and sj > datetime('now', 'localtime', '-26 minute')")
            row = cursor.fetchone()
            tj = row[0]
            print(f'学习统计={tj}个10秒')
            if tj > 137 or getprexl() == 2:
                xl = 2 
                zt = 2
                result = 4
                
                if tj == 138:
                    res = sc_xxqkpng()
                    turntolight(True)
            #如果6分钟内2,2已经超过30个,那么设置为0,0
            cursor = c.execute("SELECT count(*) FROM jkme WHERE xl = 2 and zt = 2 and sj > datetime('now', 'localtime', '-6 minute')")
            row = cursor.fetchone()
            tjx = row[0]
            print(f'休息统计={tjx}个10秒')
            if tjx > 30:
                xl = 0 
                zt = 0
                res = '休息时间完了。'
                if tjx == 31:
                    turntolight(False)
            #如果上一个为2,这一个也是2,那么设置为1,0
            cursor = c.execute("SELECT qk FROM jkme order by id desc limit 0,1;")
            row = cursor.fetchone()
            qkz = row[0]
            print(f'上一个={qkz}')
            if qkz == 2:
                xl = 1 #1为提醒响铃
                zt = 0  
            if result == 0 and zt != 2:
                xl = 3 #3为警报响铃
            cursor = c.execute("SELECT id,msg FROM jkmsg WHERE zt = 0 limit 0,1;")
            row = cursor.fetchone()
            if row:
                msg = row[1]
                mid = row[0]
                c.execute(f"UPDATE jkmsg SET zt = 1 WHERE id = {mid}")
                conn.commit()
            c.close()
            conn.close
            insertdb(now.strftime("%Y-%m-%d %H:%M:%S"),filepath,xl,zt,result)
            # 返回包含接收到的描述和文件路径的响应
            if result == 4:
                res = 'ok'
        if int(now.strftime("%H")) in (12,13,14):
            res = 'ok'
        if msg != '':
            res = msg
        return jsonify({
            'message': f'学习={tj},' + f'休息={tjx},' + f'上个={qkz}。' + f'{msg}',
            'speak': res,
            'sj': now.strftime("%Y-%m-%d %H:%M:%S"),
            'xl': xl
        }), 201
    else:
        return jsonify({'error': 'Allowed file types are png, jpg, jpeg, gif'}), 400

@app.route('/')
def index():
    # 获取最新的图片
    conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
    c = conn.cursor()
    cursor = c.execute("select furl,qk from jkme order by id desc limit 0,1;")
    row = cursor.fetchone()
    upic = row[0]
    result = row[1]
    res = 0
    if result == 0:
        res = '没在学习'
    elif result == 1:
        res = '认真学习'
    elif result == 2:
        res = '没有认真学习'
    elif result == 3:
        res = '是其他人'
    elif result == 4:
        res = '休息时间'
    c.close
    conn.close
    furl = os.path.basename(upic)
    image_url = f'http://192.168.99.235:5000/static/upimages/{furl}'
    return render_template('index.html', image_url=image_url, qk = res)

@app.route('/qk')
def index0():
    urls = []
    conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
    c = conn.cursor()
    cursor = c.execute("SELECT url FROM qkpng order by id desc limit 0,5;")
    rows = cursor.fetchall()
    for row in rows:
        urls.append(os.path.basename(row[0]))
    c.close()
    conn.close
    return render_template('index0.html', image_urls=urls)

@app.route('/static/images/<path:filename>')
def custom_static(filename):
    return send_from_directory(r'D:\sb\xx', filename)

@app.route('/static/upimages/<path:filename>')
def custom_static_gz(filename):
    now = datetime.datetime.now()
    date_str = now.strftime("%Y%m%d")
    return send_from_directory(fr'D:\upload\{date_str}', filename)

@app.route('/submit', methods=['POST'])
def handle_form_submit():
    # 从POST请求中获取名为'textInput'的参数
    text_input = request.form.get('textInput')
    insertmsg(text_input)
    # 处理接收到的数据(这里只是简单地返回它)
    response = {
        'status': 'success',
        'receivedText': text_input
    }    
    # 返回JSON格式的响应
    return jsonify(response)
 

@app.route('/get_data', methods=['GET'])
def get_data():
    # 在这里,你可以根据需要动态生成数据
    # 例如,从数据库查询、调用其他API等
    conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
    c = conn.cursor()
    cursor = c.execute("SELECT sj,furl,xl,zt,qk FROM jkme order by id desc limit 0,1")
    row = cursor.fetchone()
    sj = row[0]
    url = row[1]
    xl = row[2]
    zt = row[3]
    getqk = row[4]
    c.close
    conn.close
    if getqk == 0:
        qk = '无人'
    elif getqk == 1:
        qk = '认真'
    elif getqk == 2:
        qk = '不认真'
    else:
        qk = '其他情况'
    furl = os.path.basename(url)
    data = {
    'sj':sj,
    'image_url': f'http://192.168.99.235:5000/static/upimages/{furl}',
    'str_value': qk,
    'xl': xl,
    'zt': zt,
    'qk': getqk
    }
    # 返回JSON响应
    return jsonify(data)

if __name__ == '__main__':
    app.run(host='192.168.99.235')

三、数据库:

CREATE TABLE jkmsg (
    id  INTEGER PRIMARY KEY AUTOINCREMENT,
    sj  TEXT,
    msg TEXT,
    zt  INTEGER
);

运行效果:

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

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

相关文章

【note】MCTS

MCTS survey 参考 http://arxiv.org/abs/2103.04931 基本概念 MDP 可以表示为一个四元组 ( S , A S , P a , P w ) (S,A_S,P_a,P_w) (S,AS​,Pa​,Pw​)&#xff1a; S S S&#xff1a;状态空间 A s A_s As​&#xff1a;状态 s s s 下的可行动作集合 P a ( s , s ′ ) P_…

Couchbase UI: Server

在 Couchbase UI 中的 Server&#xff08;服务器&#xff09;标签页主要用于管理和监控集群中的各个节点。以下是 Server 标签页的主要内容和功能介绍&#xff1a; 1. 节点列表 显示集群中所有节点的列表&#xff0c;每个节点的详细信息包括&#xff1a; 节点地址&#xff1…

顶刊JFR|ROLO-SLAM:首个针对不平坦路面的车载Lidar SLAM系统

摘要 基于激光雷达&#xff08;LiDAR&#xff09;的同步定位与地图构建&#xff08;SLAM&#xff09;被认为是在恶劣环境中提供定位指导的一种有效方法。然而&#xff0c;现成的基于激光雷达的SLAM方法在经过不平坦地形时&#xff0c;尤其是在垂直方向相关的部分&#xff0c;会…

枪支消音器的 CFD 模拟

探索应用于枪支消音器的计算流体动力学的迷人世界。 了解枪支消音器 枪支消音器&#xff0c;也称为抑制器&#xff0c;是安装在枪支枪管上的装置&#xff0c;用于降低子弹发射时产生的噪音。消音器的作用是减缓和冷却子弹离开枪管时迅速膨胀的热气体。这一过程有助于降低声音…

Object类(1)

大家好&#xff0c;今天我们来学习一个常用类-Object类&#xff0c;这个类可以说是所有类的父类&#xff0c;因此它的重要性不言而喻&#xff0c;那么话不多说&#xff0c;来看。 大家可能会有一个疑问&#xff0c;java中不是只能继承一个类吗&#xff0c;那么我们继承了Objec…

【数据资产】数据资产管理概述

导读&#xff1a;数据资产管理在企业的数字化转型和业务发展中扮演着至关重要的角色。它直接关系到企业的决策效率、运营优化、业务创新以及风险防控等多个方面。数据资产作为企业的重要战略资源&#xff0c;能够为企业带来经济利益&#xff0c;其价值可能来自于数据本身的稀缺…

Qt监控系统辅屏预览/可以同时打开4个屏幕预览/支持5x64通道预览/onvif和rtsp接入/性能好

一、前言说明 在监控系统中&#xff0c;一般主界面肯定带了多个通道比如16/64通道的画面预览&#xff0c;随着电脑性能的增强和多屏幕的发展&#xff0c;再加上现在监控摄像头数量的增加&#xff0c;越来越多的用户希望在不同的屏幕预览不同的实时画面&#xff0c;一个办法是打…

51单片机开发:独立键盘实验

实验目的&#xff1a;按下键盘1时&#xff0c;点亮LED灯1。 键盘原理图如下图所示&#xff0c;可见&#xff0c;由于接GND&#xff0c;当键盘按下时&#xff0c;P3相应的端口为低电平。 键盘按下时会出现抖动&#xff0c;时间通常为5-10ms&#xff0c;代码中通过延时函数delay…

【翻转硬币——莫比乌斯函数、分块、卷积、埃氏筛】

题目 暴力代码&#xff0c;官网过55% #include <bits/stdc.h> using namespace std; int main() {int n;cin >> n;vector<bool> a(n 1);a[1] 1;int res 1;for (int i 2; i < n; i){if (a[i] 0){for (int j i; j < n; j i)a[j] a[j] ^ 1;res;}…

Hive:内部表和外部表,内外转换

内部表和外部表 内部表示例 给表添加数据 外部表示例 给表添加数据 外部表示例 用location指定表目录位置,那么表的位置在实际指定的位置,但是可以被映射 外部表和内部表的区别 删除表后使用show tables in shao; 已经没有被删除的表,说明元数据已经被删除(mysql里面存放),但是…

算法题(49):反转链表II

审题&#xff1a; 需要我们对指定范围的链表进行反转&#xff0c;并返回反转后链表的头结点 思路&#xff1a; 方法一&#xff1a;vector法 我们先遍历一次链表&#xff0c;并把数据对应的存在数组中&#xff0c;然后利用数组的reverse方法进行反转数据&#xff0c;最后再遍历一…

Unreal Engine 5 C++ Advanced Action RPG 十一章笔记

第十一章 In Game Widgets 本章节就是做UI2-Template Button Widget 这章节创建不同的UI 结束UI胜利UI暂停菜单主菜单加载UI新建一个按钮小组件作为模版 3-Pause Menu Template Button 继续做更多模版UI 4-Lose Screen(游戏失败UI) 做失败的UI 之前按钮模版的调度程序就在这起…

基于OpenCV实现的答题卡自动判卷系统

一、图像预处理 🌄 二、查找答题卡轮廓 📏 三、透视变换 🔄 四、判卷与评分 🎯 五、主函数 六、完整代码+测试图像集 总结 🌟 在这篇博客中,我将分享如何使用Python结合OpenCV库开发一个答题卡自动判卷系统。这个系统能够自动从扫描的答题卡中提取信…

Go:基于Go实现一个压测工具

文章目录 写在前面整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理 客户端模块Http客户端处理Grpc客户端处理Websocket客户端处理 连接处理模块GrpcHttp 统计数据模块统计原理实现过程 写在前面 本篇主要是基于Go来实现一个压测的工具&#xff0c;关于压测的内…

ES6 简单练习笔记--变量申明

一、ES5 变量定义 1.在全局作用域中 this 其实就是window对象 <script>console.log(window this) </script>输出结果: true 2.在全局作用域中用var定义一个变量其实就相当于在window上定义了一个属性 例如: var name "孙悟空" 其实就相当于执行了 win…

2025数学建模美赛|赛题翻译|E题

2025数学建模美赛&#xff0c;E题赛题翻译 更多美赛内容持续更新中...

Android AOP:aspectjx

加入引用 在整个项目的 build.gradle 中&#xff0c;添加 classpath "com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10" 可以看到测试demo的 gradle 版本是很低的。 基于 github 上的文档&#xff0c;可以看到原版只支持到 gradle 4.4 。后续需要使…

【SpringBoot教程】Spring Boot + MySQL + HikariCP 连接池整合教程

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 在前面一篇文章中毛毛张介绍了SpringBoot中数据源与数据库连接池相关概念&#xff0c;今天毛毛张要分享的是关于SpringBoot整合HicariCP连接池相关知识点以及底层源码…

GIS 中的 SQLAlchemy:空间数据与数据库之间的桥梁

利用 SQLAlchemy 在现代应用程序中无缝集成地理空间数据导言 地理信息系统&#xff08;GIS&#xff09;在管理城市规划、环境监测和导航系统等各种应用的空间数据方面发挥着至关重要的作用。虽然 PostGIS 或 SpatiaLite 等专业地理空间数据库在处理空间数据方面非常出色&#…

计算机的错误计算(二百二十三)

摘要 利用大模型化简计算 实验表明&#xff0c;大模型不仅给出了不精确的结论&#xff0c;而且有些表述是错误的。 例1. 计算摘要中算式。 下面是与一个大模型的对话。 点评&#xff1a; &#xff08;1&#xff09;16位的正确值是 0.9999999999051034e-11&#xff08;ISRe…