基于YOLO模型的目标检测与识别实现在ESP32-S3 EYE上全流程部署

前言

文章首发于 基于YOLO模型的目标检测与识别实现在ESP32-S3 EYE上全流程部署

文章目录

    • 前言
    • 项目环境安装
      • ESP-IDF安装
      • 开发环境
      • 运行环境
    • 训练数据集准备
      • 添加自定义数据集
    • 下载预训练模型
    • 训练 YOLO 模型
    • 模型量化和格式转换
    • 模型结果评估
      • 训练损失
      • 评估指标
      • 模型推理
    • 模型部署
      • 部署环境
      • 导入模型
      • 烧录模型
      • 结果展示
        • Swift YOLO Tiny Nano
        • Swift YOLO Tiny
    • 总结
    • References

项目环境安装

ESP-IDF安装

ESP-IDF 5.0+ 的版本有较大改动,在部署过程中会出现一些问题,建议使用 4.4 版本的进行安装。
基于 Windows 平台的软件安装,可以参考 https://dl.espressif.com/dl/esp-idf/. 按照流程完成安装即可。

开发环境

本项目整体开发环境主要基于训练框架,以及对应esp32的模型部署框架,具体如下:

  1. 训练、转换模型: Model Assistant
  2. 模型部署: sscma-example-esp32(1.0.0)

运行环境

python3.10 + CUDA11.7 + esp-idf 4.4
# 主要按照 ModelAssistant/requirements_cuda.txt 进行安装
torch                        2.0.0+cu117
torchaudio                   2.0.1+cu117
torchvision                  0.15.1+cu117
yapf                         0.40.2
typing_extensions            4.5.0
tensorboard                  2.13.0
tensorboard-data-server      0.7.2
tensorflow                   2.13.0
keras                        2.13.1
tensorflow-estimator         2.13.0
tensorflow-intel             2.13.0
tensorflow-io-gcs-filesystem 0.31.0
sscma                        2.0.0rc3
setuptools                   60.2.0
rich                         13.4.2
Pillow                       9.4.0
mmcls                        1.0.0rc6
mmcv                         2.0.0
mmdet                        3.0.0
mmengine                     0.10.1
mmpose                       1.2.0
mmyolo                       0.5.0

conda 的环境依赖主要见上面各种库的版本,其中

  • mmcv 库安装
    mmcv 库的安装需要对应 cuda 版本、torch 版本以及 python 版本,具体说明:cu117,torch2.0.0,python3.10可以参考
    https://download.openmmlab.com/mmcv/dist/cu117/torch2.0.0/index.html,对应其中主要根据操作系统选择性安装,./mmcv-2.0.1-cp310-cp310-manylinux1_x86_64.whl./mmcv-2.0.1-cp310-cp310-win_amd64.whl 文件,具体如下,
    mmcv库安装

训练数据集准备

添加自定义数据集

主要的数据集可以从开源的 Roboflow Universe 搜集,比如我们需要识别某些类别,可以在该网站上下载对应的数据集,下载格式选择 COCO 格式,如下图所示:
数据集下载示例

将下载的数据集压缩包放置在 data/collection 目录下面,对各个类别数据集加压并重命名为类别名称,例如 “face”, “phone”,即类别标签。

挑选多个类别数据集后(这里选取 “face, phone”),需要对其进行合并,利用下述代码进行合并(主要合并 json 文件,并拷贝各类别数据集的图像文件):

import os
import json
import shutil# Save paths
train_path = 'datasets/collection/train'
valid_path = 'datasets/collection/valid'# Create directories if not exist
if not os.path.exists(train_path):os.makedirs(train_path)
if not os.path.exists(valid_path):os.makedirs(valid_path)def Add_Class_COCO_Data(dataset_path, classname, dataset, dataset_info):with open(os.path.join(dataset_path, '_annotations.coco.json'), 'r') as file:class_data = json.load(file)# check if the class already exists in the train dataclass_exist, class_id = False, Nonefor item in dataset['categories']:if item['name'] == classname:class_exist, class_id = True, item['id']if class_exist is False:class_id = dataset_info['category_id']dataset['categories'].append({'id': class_id, 'name': classname})dataset_info['category_id'] += 1# add the class images for the train dataimage_id = dataset_info['img_id']for image in class_data['images']:image_info = {'id': dataset_info['img_id'], 'file_name': image['file_name'], 'width': image['width'], 'height': image['height']}dataset['images'].append(image_info)dataset_info['img_id'] += 1# add the class annotations for the train datafor ann in class_data['annotations']:ann_info = {'id': dataset_info['ann_id'], 'image_id': image_id+ann['image_id'], 'category_id': class_id, 'bbox': ann['bbox'],'area': ann['area'], 'iscrowd': ann['iscrowd']}dataset['annotations'].append(ann_info)dataset_info['ann_id'] += 1def Copy_Files(src_dir, dst_dir, skip_files=['_annotations.coco.json']):"""Copy the files from source directory to the destination directory."""os.makedirs(dst_dir, exist_ok=True)for file_name in os.listdir(src_dir):# skip some filesif file_name in skip_files:continuesrc_file = os.path.join(src_dir, file_name)dst_file = os.path.join(dst_dir, file_name)if os.path.isfile(src_file):shutil.copy(src_file, dst_file)print(f"Copied: {src_file} -> {dst_file}")else:print(f"Skipping directory: {src_file}")# training classes
classes = ["face", "phone"]# store the combined data
category_id = 0
train_data = {'categories': [], 'images': [], 'annotations': []}
train_info = {'category_id': 0, 'img_id': 0, 'ann_id': 0}valid_data = {'categories': [], 'images': [], 'annotations': []}
valid_info = {'category_id': 0, 'img_id': 0, 'ann_id': 0}class_data_root = './data/collection'
for cls_name in classes:class_train_path = os.path.join(class_data_root, cls_name, 'train')class_valid_path = os.path.join(class_data_root, cls_name, 'valid')Add_Class_COCO_Data(class_train_path, cls_name, train_data, train_info)Add_Class_COCO_Data(class_valid_path, cls_name, valid_data, valid_info)Copy_Files(class_train_path, train_path)Copy_Files(class_valid_path, valid_path)# Save data to file
with open(os.path.join(train_path, '_annotations.coco.json'), 'w') as f:json.dump(train_data, f, indent=4)with open(os.path.join(valid_path, '_annotations.coco.json'), 'w') as f:json.dump(valid_data, f, indent=4)print(f">>> length of categories: {len(train_data['categories'])}")
print(f">>> length of train_data: {len(train_data['images'])}")
print(f">>> length of valid_data: {len(valid_data['images'])}")

合并后的统一的训练和验证数据集全部放在了 datasets/collection 目录下面,以便于后续模型训练使用。

下载预训练模型

参考 Face Detection - Swift-YOLO 下载预训练模型权重文件 pretrain.pth,然后保存在 ModelAssistant/checkpoints 文件夹下。

训练 YOLO 模型

在 ModelAssistant 项目下,采用的是仓库提供的 Swift YOLO 模型,作者解释说明该模型具有优化的端侧运行性能:“We implemented a lightweight object detection algorithm called Swift YOLO, which is designed to run on low-cost hardware with limited computing power. The visualization tool, model training and export command-line interface has refactored now”.

采用 swift_yolo_tiny_1xb16_300e_coco 的配置文件进行训练,训练命令如下:

# training the yolo model
python tools/train.py configs/swift_yolo/swift_yolo_tiny_1xb16_300e_coco.py \
--cfg-options \work_dir=work_dirs/collection \num_classes=2 \epochs=300 \height=96 \width=96 \data_root=datasets/collection/ \load_from=checkpoints/pretrain.pth

模型量化和格式转换

训练完毕后,还需要对模型进行权重量化以及格式转换,这样才能够让模型成功在 ESP32S3 主板上运行。在工作目录 work_dirs/collection 下,找到最好的 bbox_mAP 的模型,例如这里是 best_coco_bbox_mAP_epoch_300.pth,采用以下命令导出模型:

# export the model
python tools/export.py configs/swift_yolo/swift_yolo_tiny_1xb16_300e_coco.py ./work_dirs/collection/best_coco_bbox_mAP_epoch_300.pth --cfg-options  \work_dir=work_dirs/collection \num_classes=2 \epochs=300  \height=96 \width=96 \data_root=datasets/collection/ \load_from=checkpoints/pretrain.pth

导出的模型会保存在 work_dirs/collection 文件夹下,生成 best_coco_bbox_mAP_epoch_300_int8.tflite 文件,这是量化到 Int8 格式的 tflite 文件,可以用于后续模型的部署。

模型结果评估

训练损失

在整个 300 epoches 的训练过程中,对应的类别损失以及目标检测损失的变化如下图所示:
类别损失
目标检测损失

评估指标

在该项目中,主要测定了 Swift YOLO Tiny 结构以及 Swift YOLO Tiny Nano 结构(一种高度紧凑的深卷积神经网络,用于使用人机协同设计策略设计的嵌入式目标检测),主要的评估指标如下所示:
mAP 评估指标

考虑到部署到端侧设备上时,更关注于目标检测的置信度,因此下面主要从置信度、平均推理时间的角度进行评估。

ModelPrecisionClassConfidenceInfer_Time(ms)Size(MB)
Swift YOLO TinyFloat32Face69.57 %6.443.63
Swift YOLO TinyFloat32Phone54.86 %6.443.63
Swift YOLO TinyFloat32[Face, Phone]62.21 %6.443.63
Swift YOLO TinyInt8Face68.75 %6.691.05
Swift YOLO TinyInt8Phone55.18 %6.691.05
Swift YOLO TinyInt8[Face, Phone]61.97 %6.691.05
Swift YOLO Tiny NanoFloat32Face73.62 %8.029.13
Swift YOLO Tiny NanoFloat32Phone55.76 %8.029.13
Swift YOLO Tiny NanoFloat32[Face, Phone]64.69 %8.029.13
Swift YOLO Tiny NanoInt8Face74.62 %12.862.49
Swift YOLO Tiny NanoInt8Phone55.62 %12.862.49
Swift YOLO Tiny NanoInt8[Face, Phone]65.12 %12.862.49
  • 可以看到,模型量化压缩后在能够维持较高的精度的情况下,模型大小显著减小,但是推理时间并没有降低,甚至约有增加;
  • Swift YOLO Tiny Nano 的精度更高,但是模型大小更大,推理时间更长,在 ESP32S3-EYE 设备上牺牲的代价就是帧率较低;
  • 整体而言,模型的置信度都已经比较高以及推理速度能比较不错,能够满足实际应用需求。

此外,我还尝试了保持原图像尺寸,即对于Swift YOLO Tiny配置而言,设置模型处理的图像宽高都是640,具体如下:

# training the yolo model
python tools/train.py configs/swift_yolo/swift_yolo_tiny_1xb16_300e_coco.py \
--cfg-options \work_dir=work_dirs/collection_640 \num_classes=2 \epochs=300 \height=640 \width=640 \data_root=datasets/collection/ \load_from=checkpoints/pretrain.pth

训练后模型的评估指标如下所示:

ModelPrecisionClassConfidenceInfer_Time(ms)Size(MB)
Swift YOLO Tiny WH640Float32Face74.83 %54.083.88
Swift YOLO Tiny WH640Float32Phone65.47 %54.083.88
Swift YOLO Tiny WH640Float32[Face, Phone]70.15 %54.083.88
Swift YOLO Tiny WH640Int8Face75.52 %71.871.20
Swift YOLO Tiny WH640Int8Phone65.46 %71.871.20
Swift YOLO Tiny WH640Int8[Face, Phone]70.49 %71.871.20

虽然整体的精度有所提升,但是推理时间显著增加,模型虽然大小基本维持不变,但是推理时间增大了将近10倍,处理图像的分辨率所带来的开销远远超过了模型识别的精度。事实上,Swift YOLO Tiny WH640 在 ESP32S3-EYE 设备上已经没办法运行,实际中会出现数据存储栈溢出的问题,摄像头采集的图像分辨率太高导致栈空间不足。

模型推理

主要是观测量化后模型对验证集的推理结果,具体如下:

模型部署

部署环境

部署环境为 ESP32-S3 EYE 开发板,没判断错的话,它有 4MB Flash,我们烧录的模型也主要存储在这个区域,当然它也附带了 SD 卡功能,可以从 SD 卡中加载模型。4 MB 的 Flash 分配主要在 partitions.csv 文件中,具体如下:

# Name	   Type	 SubType	 Offset	  Size	 Flags
# Note: if you change the phy_init or app partition offset	 make sure to change the offset in Kconfig.projbuild				
factory	 app	  factory	 0x010000	2048K
nvs	     data	 nvs	0x3D0000	 64K
fr	      data	   	      0x3E0000	 128K

默认 app 分区最多有 2048K 即 2MB 的大小,但是由于地址空间还很充裕,例如从 0x0100000x3D0000 的大小,最多可以分配 3MB 的空间,足够上述量化后的模型存储。此外,分区表主要以 64KB 为单位分配的,所以偏移地址后四位都为0. 可以在项目中通过 idf.py build 查看输出信息,其中包含了对分区大小是否合适以及剩余空间的判断。

对于 Swift YOLO Tiny Nano 配置,需要将分区表中的 app 分区增大到 3MB 即 3072K.

导入模型

对于烧录程序而言,需要将 tflite 格式模型转换为 c 语言格式,具体在项目 sscma-example-esp32-1.0.0 中,通过 tools/tflite2c.py 文件进行转换,但是为了能够在显示屏上同步显示检测的类别名称,需要修改其中的代码,即将 classes 换成字符串,然后通过分词找到各个类别,并将其转换为字符串列表,其中每个字符串都是一个类别名称,具体如下:

import sys
import os
import binascii
import argparsedef parse_args():parser = argparse.ArgumentParser(description='Convert tflite to c or cpp file')parser.add_argument('--input', help='input tflite file')parser.add_argument('--output_dir', help='output directory')parser.add_argument('--name', help='model name')parser.add_argument('--cpp', action='store_true',default=True, help='output cpp file')parser.add_argument('--classes', type=str, help='classes name')args = parser.parse_args()return argsif __name__ == '__main__':args = parse_args()input = args.inputname = args.nameoutput_dir = args.output_dirclasses = args.classesif classes != None:classes = list(classes.split(','))if not os.path.exists(input):print('input file not exist')sys.exit(1)if name == None:name = input.split('/')[-1].split('.')[0]output_h = os.path.join(output_dir, name + '_model_data.h')if args.cpp:output_c = os.path.join(output_dir, name + '_model_data.cpp')else:output_c = os.path.join(output_dir, name + '_model_data.c')with open(input, 'rb') as f_input:data = f_input.read()if data[4:8] != b'TFL3':print('input file is not tflite')sys.exit(1)data = binascii.hexlify(data)data = data.decode('utf-8')with open(output_h, 'w') as f_output_h:f_output_h.write('#ifndef __%s_MODEL_DATA_H__\r\n' % name.upper())f_output_h.write('#define __%s_MODEL_DATA_H__\r\n' % name.upper())f_output_h.write('\r\n//this file is generated by tflite2c.py\r\n')f_output_h.write('\r\n#include <stdint.h>\r\n')f_output_h.write('extern const unsigned char g_%s_model_data[];\r\n' % name)f_output_h.write('extern const unsigned int g_%s_model_data_len;\r\n' % name)if classes != None:f_output_h.write('extern const char* g_%s_model_classes[];\r\n' % name)f_output_h.write('extern const unsigned int g_%s_model_classes_num;\r\n' % name)f_output_h.write('\r\n#endif\r\n')f_output_h.close()with open(output_c, 'w') as f_output_c:f_output_c.write('#include <stdint.h>\r\n')f_output_c.write('\r\n#include "%s_model_data.h"\r\n\r\n' % name)f_output_c.write('const unsigned char g_%s_model_data[] = {\r\n' % name)for i in range(0, len(data), 2):f_output_c.write('0x')f_output_c.write(data[i])f_output_c.write(data[i+1])f_output_c.write(', ')if i % 36 == 34:f_output_c.write('\r\n')f_output_c.write('};\r\n\r\n')f_output_c.write('const unsigned int g_%s_model_data_len = %d;\r\n' % (name, len(data) // 2))if classes != None:f_output_c.write('const char* g_%s_model_classes[] = {' % name)for i in range(len(classes)):f_output_c.write('"%s", ' % classes[i])f_output_c.write('};\r\n\r\n')f_output_c.write('const unsigned int g_%s_model_classes_num = %d;\r\n' % (name, len(classes)))else:f_output_c.write('const char* g_%s_model_classes[] = {};\r\n' % name)f_output_c.write('const unsigned int g_%s_model_classes_num = 0;\r\n' % name)f_output_c.close()f_input.close()

同时为了能够在显示屏上显示置信度,还需要在 components/modules/algorithm/algo_yolo.cpp 文件中修改相应的代码,具体如下所示:

if (std::distance(_yolo_list.begin(), _yolo_list.end()) > 0)
{int index = 0;found = true;printf("    Objects found: %d\n", std::distance(_yolo_list.begin(), _yolo_list.end()));printf("    Objects:\n");printf("    [\n");for (auto &yolo : _yolo_list){yolo.x = uint16_t(float(yolo.x) / float(w) * float(frame->width));yolo.y = uint16_t(float(yolo.y) / float(h) * float(frame->height));yolo.w = uint16_t(float(yolo.w) / float(w) * float(frame->width));yolo.h = uint16_t(float(yolo.h) / float(h) * float(frame->height));fb_gfx_drawRect2(frame, yolo.x - yolo.w / 2, yolo.y - yolo.h / 2, yolo.w, yolo.h, box_color[index % (sizeof(box_color) / sizeof(box_color[0]))], 4);// fb_gfx_printf(frame, yolo.x - yolo.w / 2, yolo.y - yolo.h/2 - 5, 0x1FE0, 0x0000, "%s", g_yolo_model_classes[yolo.target]);fb_gfx_printf(frame, yolo.x - yolo.w / 2, yolo.y - yolo.h/2 - 5, 0x1FE0, "%s:%d", g_yolo_model_classes[yolo.target], yolo.confidence);printf("        {\"class\": \"%d\", \"x\": %d, \"y\": %d, \"w\": %d, \"h\": %d, \"confidence\": %d},\n", yolo.target, yolo.x, yolo.y, yolo.w, yolo.h, yolo.confidence);index++;}printf("    ]\n");
}

然后具体的转换命令如下所示,这将会在文件夹 components/modules/model 中生成两个文件 yolo_model_data.hyolo_model_data.cpp,其中 yolo_model_data.h 中包含了模型数据的声明,yolo_model_data.cpp 中包含了模型数据的定义。

python tools/tflite2c.py --input ./model_zoo/facephone_96/best_coco_bbox_mAP_epoch_300_int8.tflite --name yolo --output_dir ./components/modules/model --classes "person,phone"

烧录模型

模型准备完毕后,就可以利用乐鑫的 IDF 开发工具链将模型烧录进开发板中,具体过程主要是:

  1. 使用 ESP-IDF 4.4 CMD 进入 sscma-example-esp32-1.0.0 项目的 examples/yolo 目录下;
  2. 使用 idf.py set-target esp32s3 设置目标芯片为 esp32s3
  3. 使用 idf.py build 命令编译项目;
  4. 使用 idf.py flash monitor 命令烧录项目。

结果展示

Swift YOLO Tiny Nano

在 ESP32S3 设备上平均每张图像的处理时间是 628 ms,在端侧设备上出现帧率较低,稍微偏卡顿的效果。但是准确度提高的也不是很多,因此首选还是 Swift YOLO Tiny。
模型端口监控结果

Swift YOLO Tiny

在 ESP32S3 设备上平均每张图像的处理时间是 268 ms,实时监测的帧率非常不错,已经很流畅,准确性而言也是较为不错的,具体结果如下所示:
模型端口监控结果

实际的开发板检测结果如下所示:
单个人脸检测
多个人脸检测
手机检测

总结

本文主要介绍了如何利用 Model Assistant、sscma-example-esp32-1.0.0 项目将 YOLO 模型部署到 ESP32S3 EYE 设备上,并且通过自定义数据集实现训练、导出、转换、导入、部署模型整个流程,也对实际开发板进行了测试,最终得到了较为理想的结果。

本文主要选取了 “face, phone” 两个类别进行训练,如果需要训练更多的类别,可以添加更多的类别,但是会存在目标检测上限以及端侧设备计算性能的限制,需要进一步平衡。

References

  • esp32-s3训练自己的数据进行目标检测、图像分类
  • SenseCraft Model Assistant by Seeed Studio
  • EdgeLab Deployment on Espressif Chipsets
  • Explore the Roboflow Universe

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue中使用ECharts图表中的阈值标记(附源码)

在数据处理和可视化领域&#xff0c;我们经常需要对一系列数据点进行分析。本文将介绍如何在给定的数据点中找到对应于特定Y值的X值&#xff0c;并设置标线起始点标记在ECharts图表中&#xff0c;效果图如下&#xff1a; 实现步骤 1、数据准备 let seriesData [// 提供日期…

如何将 Docker 镜像打包为 ZIP 文件便于分享和转发

在开发和部署中&#xff0c;我们常常需要将 Docker 镜像转发给其他团队成员或部署到不同的环境。如果无法直接访问镜像仓库&#xff08;如 Docker Hub 或私有镜像仓库&#xff09;&#xff0c;可以选择将镜像保存为文件&#xff0c;并通过 ZIP 格式打包后进行分享。 本文将介绍…

岩体力学的材质-力学等属性的自动划分.

#背景: 在力学求解过程中,我们往往会对目标物体进行网格划分, 那么如何做到自动完成这个过程呢? 这里使用岩体力学中的地下岩层进行举例,这里只是简单的导入了4种界面, 复杂的可以一次性导入几十种界面,都可以计算(你能分多细,这个计算方式就可以帮你分层多细) 这里我只是导…

C++打造局域网聊天室第一课:编程环境及准备知识

文章目录 前言一、使用环境二、基础知识1.MFC&#xff08;Microsoft Foundation Class&#xff09;2.API&#xff08;Application Programming Interface&#xff09;3.Unicode编码4.简单的比较5.WinSock6.多线程知识 总结 前言 C打造局域网聊天室第一课&#xff1a;编程环境及…

项目-02-数学学院后台项目开发过程中的问题总结

目录 一、后台&#xff08;pc端&#xff0c;vue2&#xff09;1. dialog对话框被黑色蒙层盖住2. 将前端表格导出为word文档3. 在线查看、下载 .docx、.doc、.pdf文档 一、后台&#xff08;pc端&#xff0c;vue2&#xff09; 1. dialog对话框被黑色蒙层盖住 问题&#xff1a; d…

分类预测 | Matlab实现SO-LSSVM蛇群算法优化最小二乘支持向量机多特征分类预测

分类预测 | Matlab实现SO-LSSVM蛇群算法优化最小二乘支持向量机多特征分类预测 目录 分类预测 | Matlab实现SO-LSSVM蛇群算法优化最小二乘支持向量机多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现Matlab实现SO-LSSVM蛇群算法优化最小二乘支…

两个畸变矩阵相乘后还是一个2*2的矩阵,有四个畸变元素。1、畸变矩阵吸收了法拉第矩阵。2、畸变矩阵也给法拉第旋转角带来模糊(求解有多种可能)

角度一&#xff1b;恢复畸变的时候也把法拉第旋转恢复了 角度二&#xff1a;求解法拉第旋转角的时候 前面乘的复系数的不同也会带来法拉第旋转角和畸变的不同解 注意&#xff1a;无论多少个畸变矩阵相乘&#xff0c;结果都是2*2的矩阵&#xff0c;也就是畸变参数可以减少…

C# WinForm —— 39 40 41 42 DataGridView 介绍与使用

1. 简介 以网格的形式来显示表格数据&#xff0c;一般与数据库交互&#xff0c;将数据库中某一个表格的数据绑定到 UI控件上 并显示出来 网格中的行和列由用户自定义 三个重要对象&#xff1a;行、列、单元格 2. 属性 属性解释(Name)控件ID&#xff0c;在代码里引用的时候…

前端常用缓存技术深度剖析

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

gradle下载慢解决方案2024 /12 /1android studio (Windows环境)

gradle下载慢解决方案2024 /12 /1 默认环境配置好了,环境配置和程序安装请出门右转 打开软件,点击右上角设置,找到如下设置页 选择本地安装并制定好你已经安装好的 gradle 应用保存即可 全局插件环境配置(新版本可以直接在设置中添加了) 找对应位置添加国内源并把前面的内置源…

后端返回前端的数据量过大解决方案

后端返回前端的数据量过大解决方案 性能面板(Performance) chrome调试指南 原因 遇到一个页面有好几个表格&#xff0c;部分表格采用虚拟滚动条 数据量有点大 接近快60s了&#xff0c;看一下是哪里导致的慢 后台请求方法执行并不慢 2024-12-04 15:21:52.889 INFO 69948 …

在服务器上实现本地python文件的依赖

1、在python中&#xff0c;一个python文件就可以视为一个模块进行导入 2、使用import 导入时&#xff0c;若使用pip 下载过可以直接导入 3、假如是自己写的同项目中的文件会去sys.path 中查找 比如说 我现在 test 下有一个 python文件 运行 下面的代码 打印的数据如上图所示p…

Python酷库之旅-第三方库Pandas(255)

目录 一、用法精讲 1206、pandas.tseries.offsets.SemiMonthEnd.is_on_offset方法 1206-1、语法 1206-2、参数 1206-3、功能 1206-4、返回值 1206-5、说明 1206-6、用法 1206-6-1、数据准备 1206-6-2、代码示例 1206-6-3、结果输出 1207、pandas.tseries.offsets.S…

大数据新视界 -- Hive 元数据管理:核心元数据的深度解析(上)(27 / 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

【网络安全】网站常见安全漏洞 - 网站基本组成及漏洞定义

文章目录 引言1. 一个网站的基本构成2. 一些我们经常听到的安全事件3. 网站攻击者及其意图3.1 网站攻击者的类型3.2 攻击者的意图 4. 漏洞的分类4.1 按来源分类4.2 按危害分类4.3 常见漏洞与OWASP Top 10 引言 在当今的数字化时代&#xff0c;安全问题已成为技术领域不可忽视的…

Web 毕设篇-适合小白、初级入门练手的 Spring Boot Web 毕业设计项目:智行无忧停车场管理系统(前后端源码 + 数据库 sql 脚本)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 项目介绍 1.1 项目功能 2.0 用户登录功能 3.0 首页界面 4.0 车辆信息管理功能 5.0 停车位管理功能 6.0 入场登记管理功能 7.0 预约管理功能 8.0 收费规则功能 9.0…

猎板 PCB特殊工艺:铸就电子行业核心竞争力新高度

在当今竞争激烈且技术驱动的电子制造领域&#xff0c;印制电路板&#xff08;PCB&#xff09;作为电子产品的关键基石&#xff0c;其特殊工艺的发展水平直接影响着整个行业的创新步伐与产品品质。猎板 PCB 凭借在厚铜板、孔口铺铜、HDI 板、大尺寸板以及高频高速板等特殊工艺方…

STM32 进阶 定时器3 通用定时器 案例2:测量PWM的频率/周期

需求分析 上一个案例我们输出了PWM波&#xff0c;这个案例我们使用输入捕获功能&#xff0c;来测试PWM波的频率/周期。 把测到的结果通过串口发送到电脑&#xff0c;检查测试的结果。 如何测量 1、输入捕获功能主要是&#xff1a;测量输入通道的上升沿和下降沿 2、让第一个…

Android平台GB28181设备接入模块如何支持GB28181云端录像补录

技术背景 GB28181 的补录功能是一种用于弥补视频数据缺失的重要机制。在实际的视频监控场景中&#xff0c;由于网络不稳定、设备故障等多种因素&#xff0c;可能会导致视频数据在上云或存储过程中出现缺失&#xff0c;无法保证数据的完整性。GB28181 的补录功能就是为了解决这…

如何将python项目导出为docker镜像

如何将python项目导出为docker镜像 前提条件步骤 1: 创建并准备 Python 项目步骤 2: 创建 `setup.py`步骤 3: 打包项目步骤 4: 创建 Dockerfile步骤 5: 构建 Docker 镜像步骤 6: 运行 Docker 容器步骤 7: 保存修改并继续开发总结要将修改后的Python代码导出为 .tar.gz 格式,并…