Yolov5 v7.0目标检测——详细记录环境配置、自定义数据处理、模型训练与常用错误解决方法(数据集为河道漂浮物)

1. Yolov5

YOLOv5是是YOLO系列的一个延伸,其网络结构共分为:input、backbone、neck和head四个模块,yolov5对yolov4网络的四个部分都进行了修改,并取得了较大的提升,在input端使用了Mosaic数据增强、自适应锚框计算、自适应图片缩放; 在backbone端使用了Focus结构与CSP结构;在neck端添加了FPN+PAN结构;在head端改进了训练时的损失函数,使用GIOU_Loss,以及预测框筛选的DIOU_nms。

YOLOv5是一种单阶段目标检测算法,该算法在YOLOv4的基础上添加了一些新的改进思路,使其速度与精度都得到了极大的性能提升。主要的改进思路如下所示:

  • input:Mosaic数据增强、自适应锚框计算、自适应图片缩放;
  • backbone:Focus结构与CSP结构;
  • neck:添加了FPN+PAN结构;
  • head:改进了训练时的损失函数,使用GIOU_Loss,以及预测框筛选的DIOU_nms。

1.1 网络结构

在这里插入图片描述yolov5的网络结构如上图所示,yolo系列的算法基本可以分为四个模块,input、neck和head。下面对着4个模块依次进行分析。

1.2 input

输入端主要对输入的图片进行预处理。该网络的输入图像大小为608×608,预处理主要是将输入图像缩放到网络的输入大小,并进行归一化等操作。在网络训练阶段,YOLOv5使用Mosaic数据增强操作提升模型的训练速度和网络的精度;并提出了一种自适应锚框计算自适应图片缩放方法。

Mosaic数据增强:Mosaic数据增强方法采用了4张图片,按照随机缩放、随机裁剪和随机排布的方式进行拼接而成,这种增强方法可以将几张图片组合成一张,这样不仅可以丰富数据集的同时极大的提升网络的训练速度,而且可以降低模型的内存需求。

自适应锚框计算:在YOLO系列算法中,针对不同的数据集,都需要设定特定长宽的Anchor。在网络训练阶段,模型在初始锚点框的基础上输出对应的预测框,计算其与真实框之间的差距,并执行反向更新操作,从而更新整个网络的参数,因此设定初始锚点框也是比较关键的一环。YOLOv5模型在每次训练时,根据数据集的名称自适应的计算出最佳的锚点框。

自适应图片缩放:传统的缩放方式都是按原始比例缩放图像并用黑色填充至目标大小,由于在实际的使用中的很多图片的长宽比不同,因此缩放填充之后,两端的黑边大小都不相同,然而如果填充的过多,则会存在大量的信息冗余,从而影响整个算法的推理速度。为了进一步提升YOLOv5算法的推理速度,该算法提出一种方法能够自适应的添加最少的黑边到缩放之后的图片中。具体的实现步骤如下所述:

  1. 根据原始图片大小与输入到网络图片大小计算缩放比例;
  2. 根据原始图片大小与缩放比例计算缩放后的图片大小;
  3. 计算黑边填充数值,该黑边数值不要求一定使图像缩放至指定大小,而是自适应模型中卷积和池化的大小。

1.3 backbone

主干网络部分主要引入了focus结构CSP结构

focus结构

Focus重要的是切片操作,如下图所示,4x4x3的图像切片后变成2x2x12的特征图。
在这里插入图片描述
在yolov5网络模型中,原始608x608x3的图像输入Focus结构,采用切片操作,先变成304x304x12的特征图,再经过一次32个卷积核的卷积操作,最终变成304x304x32的特征图。

CSP结构
yolov4网络结构中,借鉴了CSPNet的设计思路,仅仅在主干网络中设计了CSP结构。而yolov5中设计了两种CSP结构,CSP1_X结构应用于主干网络中,另一种CSP2_X结构则应用于Neck网络中。

neck

yolov5的Neck网络仍然使用了FPN+PAN结构,但是在它的基础上做了一些改进操作,yolov4的Neck结构中,采用的都是普通的卷积操作。而YOLOv5的Neck网络中,采用借鉴CSPnet设计的CSP2结构,从而加强网络特征融合能力。

head

在head部分,yolov5改进了损失函数,采用GIoU_Lossounding box的损失函数并添加了预测框筛选的DIOU_nms,这两个点并不是yolov5的原创内容,如果想深入了解可以参考相关论文,这里不再赘述。

而v7.0版本最重要的更新是增加了对实例分割的支持,主要的更新了实例分割的代码,提高了分割的精度与速度。这个版本也许是Yolov5的最后一次更新了,就目前的消息,YOLOv5团队已经转向了YOLOv8的更新,因此,7.0版本大概率是YOLOv5的最终稳定版。

整个代码与数据下载地址:https://download.csdn.net/download/matt45m/89215063

2.环境安装

2.1 创建虚拟环境

我这里使用Anaconda创建虚拟环境,conda可以从清华源下载。下载自己想要的版本,这里是我用的版本:
在这里插入图片描述
安装完成之后创建环境:

conda create --name yolov5 python==3.10
activate yolov5

这里建议单独安装pytorch,torch要对应自己电脑的cuda版本进行安装,我这里使用的cuda是11.7,cudnn 8.5,单独安装torch的命令可以在torch官网可以获取:
在这里插入图片描述

conda install pytorch==2.0.0 torchvision==0.15.0 torchaudio==2.0.0 pytorch-cuda=11.7 -c pytorch -c nvidia

2.2 下载源码

在激活的环境下把源码拉取,如果拉取不了,可以直接下载源码包:
在这里插入图片描述

git clone https://github.com/ultralytics/yolov5.git

然后更改yolov5源码里面的requirements.txt文件,把这两行注掉:
在这里插入图片描述
安装所需的依赖:

cd yolov5
pip install -r requirements.txt

哪里安装过程中出错,就查看安装错误库,单独安装或者使用源码安装。

3.数据集处理

这里使用的数据是河道水面的漂浮物,数据总共有5000多张,使用的标注工具是Labelme。
在这里插入图片描述

3.1数据标注

标注的格式可以选voc或者是yolo格式,如果选择voc的格式,则要转换,这里使用的voc数据格式,标注如下:
在这里插入图片描述

在这里插入图片描述

3.2 数据转换

数据如果是xml格式,则要把数据转换成txt格式,在yolov5目录下,创建一个dataset目录,然后把标注好的数据集的数像和xml标签文件在这个目录下:
在这里插入图片描述

然后在yolov5目录下创建一个xml_txt.py文件,脚本代码如下:

import os
import glob
import argparse
import random
import xml.etree.ElementTree as ET
from PIL import Image
from tqdm import tqdmdef get_all_classes(xml_path):xml_fns = glob.glob(os.path.join(xml_path, '*.xml'))class_names = []for xml_fn in xml_fns:tree = ET.parse(xml_fn)root = tree.getroot()for obj in root.iter('object'):cls = obj.find('name').textclass_names.append(cls)return sorted(list(set(class_names)))def convert_annotation(img_path, xml_path, class_names, out_path):output = []im_fns = glob.glob(os.path.join(img_path, '*.jpg'))for im_fn in tqdm(im_fns):if os.path.getsize(im_fn) == 0:continuexml_fn = os.path.join(xml_path, os.path.splitext(os.path.basename(im_fn))[0] + '.xml')if not os.path.exists(xml_fn):continueimg = Image.open(im_fn)height, width = img.height, img.widthtree = ET.parse(xml_fn)root = tree.getroot()anno = []xml_height = int(root.find('size').find('height').text)xml_width = int(root.find('size').find('width').text)if height != xml_height or width != xml_width:print((height, width), (xml_height, xml_width), im_fn)continuefor obj in root.iter('object'):cls = obj.find('name').textif cls not in class_names:continuecls_id = class_names.index(cls)# print(cls_id)xmlbox = obj.find('bndbox')xmin = int(xmlbox.find('xmin').text)ymin = int(xmlbox.find('ymin').text)xmax = int(xmlbox.find('xmax').text)ymax = int(xmlbox.find('ymax').text)cx = (xmax + xmin) / 2.0 / widthcy = (ymax + ymin) / 2.0 / heightbw = (xmax - xmin) * 1.0 / widthbh = (ymax - ymin) * 1.0 / heightanno.append('{} {} {} {} {}'.format(cls_id, cx, cy, bw, bh))if len(anno) > 0:output.append(im_fn)with open(im_fn.replace('.jpg', '.txt'), 'w') as f:f.write('\n'.join(anno))# random.shuffle(output)# train_num = int(len(output) * 0.9)# with open(os.path.join(out_path, 'train.txt'), 'w') as f:#     f.write('\n'.join(output[:train_num]))# with open(os.path.join(out_path, 'val.txt'), 'w') as f:#     f.write('\n'.join(output[train_num:]))def parse_args():parser = argparse.ArgumentParser('generate annotation')parser.add_argument('--img_path', default='dataset/Trash/images', type=str, help='input image directory')parser.add_argument('--xml_path', default='dataset/Trash/xml',type=str, help='input xml directory')parser.add_argument('--out_path',default='Trash/', type=str, help='output directory')args = parser.parse_args()return argsif __name__ == '__main__':args = parse_args()class_names = get_all_classes(args.xml_path)convert_annotation(args.img_path, args.xml_path, class_names, args.out_path)

运行完成之后,会在images目录下生成与图像同名的.txt文件:
在这里插入图片描述

4.数据处理

4.1 数据分割

训练之后要对数据集进行分割,一般都要分为训练集,验证集,测试集,一般按8:1:1的分法。在yolov5根目录下创建data_splitting.py脚本,脚本代码如下:

import os
import random
from shutil import move# 指定原始目录
source_dir = 'dataset/Trash/images'# 创建子目录:训练集、验证集和测试集
sub_dirs = ['train', 'val', 'test']
for sub_dir in sub_dirs:os.makedirs(os.path.join(source_dir, sub_dir), exist_ok=True)# 收集所有.jpg和对应的.txt文件
jpg_files = {f for f in os.listdir(source_dir) if f.lower().endswith('.jpg')}
txt_files = {f[:-4] + '.txt' for f in jpg_files}  # 假设.txt文件名是去掉.jpg后缀的.jpg文件名# 将.jpg和.txt文件映射成字典,以.jpg文件名为键
all_files = jpg_files.union(txt_files)
file_dict = {f: os.path.join(source_dir, f) for f in all_files}# 随机打乱文件列表
random.shuffle(list(file_dict.keys()))# 根据给定的比例分配文件到不同的目录
total_files = len(file_dict)
split1 = int(total_files * 0.8)  # 训练集的文件数量
split2 = int(total_files * 0.9)  # 验证集的文件数量# 训练集
train_files = list(file_dict.keys())[:split1]
# 验证集
val_files = list(file_dict.keys())[split1:split2]
# 测试集
test_files = list(file_dict.keys())[split2:]# 移动文件到相应的子目录
for files, sub_dir in ((train_files, 'train'), (val_files, 'val'), (test_files, 'test')):for file in files:source_path = file_dict[file]dest_dir = os.path.join(source_dir, sub_dir)dest_path = os.path.join(dest_dir, file)# 确保目标子目录中包含对应的.jpg和.txt文件if file.endswith('.jpg'):move(source_path, dest_path)  # 移动.jpg文件txt_file = file[:-4] + '.txt'if txt_file in file_dict:txt_source_path = file_dict[txt_file]move(txt_source_path, dest_dir)  # 移动对应的.txt文件print("文件分配完成。")

运行完成之后,会下images下生成三个目录:
在这里插入图片描述
目录里面有对应的图像与txt标签文件:
在这里插入图片描述

4.2 处理数据

在dataset/Trash目录下创建一个lables文件,然后把上面生成三个目录train, val, test复制一份到labels目录里面:
在这里插入图片描述
把images下的三个目录里面的.txt文件删掉,只保留.jpg文件。
然后再把labels下的三个目录里面的.jpg文件删除掉只保留.txt文件。

4.3 创建数据配置文件

在yolov5/data目录下创建一个trash_data.yaml
添加以下内容:

path: ./dataset/Trash # dataset root dir
train: images/train # train images (relative to 'path') 128 images
val: images/val # val images (relative to 'path') 128 images
test: test# Classes
names:0: trash

最终数据目录结构如下:
在这里插入图片描述

5.模型训练

5.1 模型训练

训练代码配置:

def parse_opt(known=False):"""Parses command-line arguments for YOLOv5 training, validation, and testing."""parser = argparse.ArgumentParser()parser.add_argument("--weights", type=str, default=ROOT / "yolov5s.pt", help="initial weights path")parser.add_argument("--cfg", type=str, default="", help="model.yaml path")parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="dataset.yaml path")parser.add_argument("--hyp", type=str, default=ROOT / "data/hyps/hyp.scratch-low.yaml", help="hyperparameters path")parser.add_argument("--epochs", type=int, default=100, help="total training epochs")parser.add_argument("--batch-size", type=int, default=16, help="total batch size for all GPUs, -1 for autobatch")parser.add_argument("--imgsz", "--img", "--img-size", type=int, default=640, help="train, val image size (pixels)")parser.add_argument("--rect", action="store_true", help="rectangular training")parser.add_argument("--resume", nargs="?", const=True, default=False, help="resume most recent training")parser.add_argument("--nosave", action="store_true", help="only save final checkpoint")parser.add_argument("--noval", action="store_true", help="only validate final epoch")parser.add_argument("--noautoanchor", action="store_true", help="disable AutoAnchor")parser.add_argument("--noplots", action="store_true", help="save no plot files")parser.add_argument("--evolve", type=int, nargs="?", const=300, help="evolve hyperparameters for x generations")parser.add_argument("--evolve_population", type=str, default=ROOT / "data/hyps", help="location for loading population")parser.add_argument("--resume_evolve", type=str, default=None, help="resume evolve from last generation")parser.add_argument("--bucket", type=str, default="", help="gsutil bucket")parser.add_argument("--cache", type=str, nargs="?", const="ram", help="image --cache ram/disk")parser.add_argument("--image-weights", action="store_true", help="use weighted image selection for training")parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu")parser.add_argument("--multi-scale", action="store_true", help="vary img-size +/- 50%%")parser.add_argument("--single-cls", action="store_true", help="train multi-class data as single-class")parser.add_argument("--optimizer", type=str, choices=["SGD", "Adam", "AdamW"], default="SGD", help="optimizer")parser.add_argument("--sync-bn", action="store_true", help="use SyncBatchNorm, only available in DDP mode")parser.add_argument("--workers", type=int, default=8, help="max dataloader workers (per RANK in DDP mode)")parser.add_argument("--project", default=ROOT / "runs/train", help="save to project/name")parser.add_argument("--name", default="exp", help="save to project/name")parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment")parser.add_argument("--quad", action="store_true", help="quad dataloader")parser.add_argument("--cos-lr", action="store_true", help="cosine LR scheduler")parser.add_argument("--label-smoothing", type=float, default=0.0, help="Label smoothing epsilon")parser.add_argument("--patience", type=int, default=100, help="EarlyStopping patience (epochs without improvement)")parser.add_argument("--freeze", nargs="+", type=int, default=[0], help="Freeze layers: backbone=10, first3=0 1 2")parser.add_argument("--save-period", type=int, default=-1, help="Save checkpoint every x epochs (disabled if < 1)")parser.add_argument("--seed", type=int, default=0, help="Global training seed")parser.add_argument("--local_rank", type=int, default=-1, help="Automatic DDP Multi-GPU argument, do not modify")# Logger argumentsparser.add_argument("--entity", default=None, help="Entity")parser.add_argument("--upload_dataset", nargs="?", const=True, default=False, help='Upload data, "val" option')parser.add_argument("--bbox_interval", type=int, default=-1, help="Set bounding-box image logging interval")parser.add_argument("--artifact_alias", type=str, default="latest", help="Version of dataset artifact to use")# NDJSON loggingparser.add_argument("--ndjson-console", action="store_true", help="Log ndjson to console")parser.add_argument("--ndjson-file", action="store_true", help="Log ndjson to file")return parser.parse_known_args()[0] if known else parser.parse_args()

更改yolov5/models/yolov5s.yaml文件,把nc类别改成自己数据类别数目,这里只有一个类别,所以是1:

# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license# Parameters
nc: 1 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
anchors:- [10, 13, 16, 30, 33, 23] # P3/8- [30, 61, 62, 45, 59, 119] # P4/16- [116, 90, 156, 198, 373, 326] # P5/32# YOLOv5 v6.0 backbone
backbone:# [from, number, module, args][[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2[-1, 1, Conv, [128, 3, 2]], # 1-P2/4[-1, 3, C3, [128]],[-1, 1, Conv, [256, 3, 2]], # 3-P3/8[-1, 6, C3, [256]],[-1, 1, Conv, [512, 3, 2]], # 5-P4/16[-1, 9, C3, [512]],[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32[-1, 3, C3, [1024]],[-1, 1, SPPF, [1024, 5]], # 9]# YOLOv5 v6.0 head
head: [[-1, 1, Conv, [512, 1, 1]],[-1, 1, nn.Upsample, [None, 2, "nearest"]],[[-1, 6], 1, Concat, [1]], # cat backbone P4[-1, 3, C3, [512, False]], # 13[-1, 1, Conv, [256, 1, 1]],[-1, 1, nn.Upsample, [None, 2, "nearest"]],[[-1, 4], 1, Concat, [1]], # cat backbone P3[-1, 3, C3, [256, False]], # 17 (P3/8-small)[-1, 1, Conv, [256, 3, 2]],[[-1, 14], 1, Concat, [1]], # cat head P4[-1, 3, C3, [512, False]], # 20 (P4/16-medium)[-1, 1, Conv, [512, 3, 2]],[[-1, 10], 1, Concat, [1]], # cat head P5[-1, 3, C3, [1024, False]], # 23 (P5/32-large)[[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)]

运行命令:

python train.py --img 640 --batch 8 --epochs 150 --data ./data/trash_data.yaml --cfg ./models/yolov5s.yaml --weights yolov5s.pt
  • –img 640 #训练图像大小
  • –batch 8 #批次大小,如果GPU够大,可以改成更大,这里2的倍数,如果报显存报错,则改小
  • –epochs 150 #迭代次数
  • –data ./data/trash_data.yaml #数据配置文件
  • –cfg ./models/yolov5s.yaml #模型配置文件
  • –weights yolov5s.pt #第一次运动会下载这个权重文件,如果下载其间报错,可以手动下载放到指定目录,然后指定模型路径

手动模型下载地址

在这里插入图片描述
开始训练:
在这里插入图片描述

5.2 训练结果

训练完成之后,会在yolov5/run目录下看找到训练的结果:
在这里插入图片描述
可以看到验证结果:
在这里插入图片描述

7.常见错误解决

7.1 解决错误:RuntimeError: result type Float can‘t be cast to the desired output type __int64

原因:
原因是新版本的torch无法自动执行转换,旧版本torch可以。

解决方法:
将utils/loss.py中gain = torch.ones(7, device=targets.device)改为gain = torch.ones(7, device=targets.device).long()即可。

7.2 AttributeError: module ‘numpy‘ has no attribute ‘float‘

原因:
这是numpy版本过高的原因,降低numpy版本就可以

解决方法:

pip uninstall numpy
pip install numpy==1.23.5

7.3 AssertionError:Label class 1 exceeds nc=1 in yolo/dataset.ymal Possible class labels are 0-0

原因:
这是因为训练类型只有一个的原因。

解决方法:
找到train.py文件中这一行代码,注释掉。

assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}'

注释后:

#assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}'

assert nf > 0 or not augment, f’{prefix}No labels found in {cache_path}, can not start training. {HELP_URL}’
AssertionError: train: No labels found in

7.4 No labels found in (Done) 或者 Exception: Dataset not found

原因:
这是数据目录没有对上的原因。就是代码无法找到lables目录里面的文件。

解决方法:
​数据集详细参考4.3节的格式。

7.5 Could not run ‘torchvision::nms’ with arguments from the ‘CUDA’ backend (Done)

原因:

因为CUDA与torch版本不匹配造成的,当前版本:

环境、工具版本
CUDA11.3
torch1.13.1+cu116
torchvision0.14.1

解决方法:
降低torch版本解决。

pip install torch==1.9.0+cu111 torchvision==0.10.0+cu111 torchaudio===0.9.0 -f https://download.pytorch.org/whl/torch_stable.html -i https://pypi.douban.com/simple

更换版本后的各个环境工具版本:

环境、工具版本
CUDA11.3
torch1.9.0+cu111
torchvision0.10.0+cu111

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

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

相关文章

C++ 二叉搜索树

文章目录 二叉搜索树的概念二叉搜索树的性质二叉搜索树的模拟实现封装框架添加操作查找操作删除操作 二叉搜索树的概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都…

PD虚拟机和Crossover软件有什么不同?谁更强大?

PD虚拟机&#xff08;Parallels Desktop&#xff09;和Crossover软件都是为Mac用户提供在macOS上运行Windows应用程序的能力&#xff0c;但它们在设计理念、功能和使用场景上存在一些差异。 PD虚拟机&#xff08;Parallels Desktop&#xff09;的特点&#xff1a; 1. 全面的虚…

MySQL中的并发控制,读写锁,和锁的粒度

MySQL中的并发控制&#xff0c;读写锁&#xff0c;和锁的粒度 并发控制的概述 在数据库系统中&#xff0c;并发控制是一种用于确保当多个用户同时访问数据库时&#xff0c;系统能够提供数据的一致性和隔离性的机制。MySQL支持多种并发控制技术&#xff0c;其中包括锁机制、多…

用友 GRP-U8 fastjson远程代码执行漏洞复现(XVE-2024-8863)

0x01 产品简介 用友GRP-U8R10行政事业内控管理软件是用友公司专注于国家电子政务事业,基于云计算技术所推出的新一代产品,是我国行政事业财务领域最专业的政府财务管理软件。 0x02 漏洞概述 用友 GRP-U8 R10系列版本 VerifyToken 接口存在低版本fastjson反序列化漏洞,未经…

用户请求经过哪些处理(公网)

DNS服务器之间协作&#xff1a; 递归DNS查询&#xff1a;用户的请求首先发送到递归DNS服务器。 查询根DNS服务器&#xff1a;递归DNS服务器查询根DNS服务器&#xff0c;以找到管理.com顶级域的TLD DNS服务器。 查询TLD DNS服务器&#xff1a;根DNS服务器响应带有TLD DNS服务器…

centos7.6上安装mysql7.6 完整过程

安装过程&#xff1a; 参考&#xff1a;https://blog.csdn.net/qq_45103475/article/details/123151050 查找mysql [rootbogon ~]# whereis mysql mysql: /usr/lib64/mysql /usr/share/mysql 删除目录 [rootbogon ~]# rm -rf /usr/lib64/mysql [rootbogon ~]# whereis mysql m…

计算机服务器中了devicdata勒索病毒怎么处理,devicdata勒索病毒解密工具流程

随着网络技术的不断发展与应用&#xff0c;越来越多的企业离不开网络&#xff0c;通过网络可以开展各项工作业务&#xff0c;网络也为企业的生产运营提供各类极大便利&#xff0c;大大提高了生产效率&#xff0c;但网络在为企业提供便利的同时&#xff0c;也为企业的数据安全带…

AJAX——案例

1.商品分类 需求&#xff1a;尽可能同时展示所有商品分类到页面上 步骤&#xff1a; 获取所有的一级分类数据遍历id&#xff0c;创建获取二级分类请求合并所有二级分类Promise对象等待同时成功后&#xff0c;渲染页面 index.html代码 <!DOCTYPE html> <html lang&qu…

探索SAVI:土壤调整植被指数的意义与应用

​随着遥感技术的不断发展&#xff0c;植被指数成为了评估地表植被覆盖和健康状况的重要工具之一。其中&#xff0c;SAVI&#xff08;Soil Adjusted Vegetation Index&#xff0c;土壤调整植被指数&#xff09;作为一种针对土壤表面反射率进行调整的植被指数&#xff0c;在土地…

Python 基础、流程、容器、函数

一、基础语法 1.1 前言 1.1.1 Python简介 Python是一门编程语言&#xff0c;Python的作者是Guido van Rossum&#xff08;龟叔&#xff09; Python优点&#xff1a;简单易学 Python与嵌入式、集成电路行业 强大的库和工具生态系统&#xff1a;Python拥有广泛而强大的库和…

深入理解高级加密标准(Advanced Encryption Standard)

title: 深入理解高级加密标准&#xff08;Advanced Encryption Standard&#xff09; date: 2024/4/23 20:04:36 updated: 2024/4/23 20:04:36 tags: AES概述加密原理优势特点算法详解安全性应用实践案例分析 第一章&#xff1a;AES概述 AES的历史和背景 历史&#xff1a; 高…

MySQL数据库精讲001——概述

MySQL数据库精讲001——概述 文章目录 MySQL数据库精讲001——概述1.1 安装1.1.1 版本1.1.2 安装一、下载二、解压三、配置1. 添加环境变量2. 初始化MySQL3. 注册MySQL服务4. 启动MySQL服务5. 修改默认账户密码 四、登录MySQL五、卸载MySQL 1.1.3 连接1.1.4 企业使用方式(了解)…

华为数通方向HCIP-DataCom H12-821题库(多选题:321-340)

第321题 关于OSPF的命令描述,不正确的是: A、stub区域和totally stub区域配置了no-summary参数 B、OSPFv2和OSPF v3配置接口命令的区别是OSPF V2可以使用network命令,而OSPFv3直接 C、在接口上使能stubrouter命令用来配置次路由器为stub路由器,stub路由器可以与非stub路由 …

mac安装nvm管理node(手残流,git下载)

1. 准备 首先电脑里得有brew、git、vscode&#xff0c;看这里安装brew、git&#xff0c;看这里安装vscode。 我本人比较low&#xff0c;mac命令也记不熟&#xff0c;本篇就是git下载nvm&#xff0c;vscode看配置&#xff0c;省心不动脑子就可以了。 2. 清理node 如果mac里没…

javaScript中的作用域和作用域链

作用域&#xff08;Scope&#xff09; 什么是作用域 作用域是在运行时代码中的某些特定部分中变量、对象和函数的可访问性。 换句话说&#xff0c;作用域决定了代码区块中变量和其他资源的可见性。 示例&#xff1a; function outFun2() {var inVariable "内层变量2…

边缘计算是什么?

一、边缘计算是什么&#xff1f; 边缘计算是一种分布式计算范式&#xff0c;它将计算任务和数据存储从中心化的云端推向网络的边缘&#xff0c;即设备或终端&#xff0c;以提高响应速度和降低网络带宽需求。在边缘计算中&#xff0c;数据在源头附近进行处理和分析&#x…

OKR已死?是中华田园KPI?

近年来&#xff0c;关于OKR&#xff08;Objectives and Key Results&#xff0c;目标与关键成果&#xff09;和KPI&#xff08;Key Performance Indicators&#xff0c;关键绩效指标&#xff09;的讨论不绝于耳。有人宣称OKR已死&#xff0c;认为KPI才是更符合中国企业的绩效管…

Unity3d的海盗王地图

一直以来&#xff0c;都想将海盗王的地图搬到手游unity3d上面。 经过漫长时间的研究&#xff0c;终于实现了当初的想法。

网络编程-libuv介绍

官网 https://libuv.org/ 概要 libuv是一个强大的跨平台异步I/O库&#xff0c;主要用于构建高性能、可扩展的网络应用程序。它最初是为Node.js开发的&#xff0c;用于处理Node.js的异步I/O操作&#xff0c;但随着时间的推移&#xff0c;它也被广泛应用于其他系统&#xff0…

【声呐仿真】学习记录0-服务器配置docker、ros环境

【声呐仿真】学习记录0-服务器配置docker、ros环境 前言一、~~0.设置mobaXterm~~1.拉取镜像2.服务器开启xhost&#xff0c;可视化&#xff08;rviz、gazebo&#xff09;3.创建容器&#xff0c;挂载数据卷4.测试宿主机与容器数据是否同步5.测试5.0测试xclock5.1测试ros小乌龟5.2…