动物姿态估计:微调 YOLOv8 姿态模型

在这里插入图片描述
动物姿态估计是计算机视觉的一个研究领域,是人工智能的一个子领域,专注于自动检测和分析图像或视频片段中动物的姿势和位置。目标是确定一种或多种动物的身体部位(例如头部、四肢和尾巴)的空间排列。这项技术具有广泛的应用,从研究动物行为和生物力学到野生动物保护和监测。

在这篇博文中,我们将专门处理狗的关键点估计,并向您展示如何微调 Ultralytics 非常流行的 YOLOv8 姿势模型。

微调动物关键点的姿态模型可能具有挑战性,需要微调多个超参数。幸运的是,YOLOv8 在模型微调期间提供了相当多的超参数自定义。准确地说,我们将微调以下 YOLOv8 姿势模型:

YOLOv8m(中)
YOLOv8l(大)
此外,通过比较 YOLOv7 和 MediaPipe 姿态模型之间的推理结果,查看我们深入的人体姿态分析。

1. 斯坦福狗的动物姿势估计数据集
2. 用于动物姿态估计的数据集异常
2.1 处理跨框和关键点的不匹配的地面实况注释,以进行动物姿态估计
3. 为训练和验证数据创建与 YOLOv8 一致的注解
3.1 下载图像数据和关键点元数据
3.2 创建用于动物姿态估计的 YOLO 训练和验证目录
3.3 创建最终的 YOLO 注释文本文件
4 动物姿态估计的超参数设置和微调
4.1 训练配置
4.2 数据配置
4.3 动物姿势估计的微调和训练
5 YOLOv8在动物姿态估计中的评价
6 动物姿势图像预测的可视化
7 结论
8 引用

在这里插入图片描述
斯坦福狗的动物姿势估计数据集
对于我们的动物姿势估计实验,我们将使用斯坦福数据集,该数据集包含 120 个品种的狗,分布在 20,580 张图像中。此外,数据集还包含这些图像的边界框注释。

关键点注释需要通过填写谷歌表单从 StandfordExtra 数据集下载。在 12,538 张图像中提供了 20 个狗姿势关键点的关键点注释(每条腿 3 个,每只耳朵 2 个,尾巴、鼻子和下巴 2 个)。

下载的注释将包含以下结构:

StanfordExtra_V12
├── StanfordExtra_v12.json
├── test_stanford_StanfordExtra_v12.npy
├── train_stanford_StanfordExtra_v12.npy
└── val_stanford_StanfordExtra_v12.npy

训练、验证和测试拆分分别作为原始数据的索引提供,这些数据分别包含 6773、4062 和 1703 图像的注释。StanfordExtra_v12.json

作者还以文件的形式提供了关键点元数据,其中包含动物姿势名称、每个关键点的颜色编码等。但是,它包含 24 个关键点(每个眼睛、喉咙和肩膀各 1 个)的信息。可以使用下图来说明关键点。CSV
需要微调的狗关键点

需要微调的狗关键点

在总共 24 个关键点中,只有 20 个存在注释。对于遗漏的 4 个关键点(2 个用于眼睛、喉咙和凋零),坐标标记为 0。

还有一个额外的布尔可见性标志,它与 20 个关键点相关联:

0:不可见
1:可见
用于动物姿态估计的数据集异常
边界框和关键点的真值注释仅适用于单个对象实例。此外,仍然有相当多的不正确的注释,从下面的示例中可以看出。
数据集异常
边界框和关键点的真值注释仅适用于单个对象实例。此外,仍然有相当多的不正确的注释,从下面的示例中可以看出。

从最左上角的图像中可以看出,边界框和关键点已针对两个不同的对象实例进行了注释。第一行的第二张和第四张图片(从左到右)以及第二行的第一张和第三张图片也反映了这一点。

此外,关键点也被错误地注释了,如第一行的第三张图片所示,下颌和左耳尖被错误地注释。第二行的第一张图像也是如此,其中左耳的尖端被错误标记。第二行的第四张图片中出现了另一个不正确的注释,其中两个耳塞都被贴错了标签。

如前所述,每个图像只有单个实例注释。观察第二行的第二张图片(从左到右),我们只有左边的狗的注释,而有三个狗的实例。

处理跨框和关键点的不匹配的地面实况注释,以进行动物姿态估计
处理不匹配的框和关键点注释的一种直观方法是根据给定的关键点估计矩形。这可以使用实用程序函数来近似给定一组坐标的矩形来完成。请稍等片刻,看看下面的示例。cv2.boundingRect

在这里插入图片描述

处理不匹配的边界框和关键点批注

尽管边界框并不完美,但使用上述方法处理不匹配的边界框和关键点注释可能成本低廉。我们可以运行一个检测模型,如 YOLOv8 来获得更准确的框注释,然后将关键点与最接近的边界框映射。

但是,我们将坚持使用原始 JSON 文件中提供的注释进行实验。
为训练和验证数据创建与 YOLOv8 一致的注解
在准备数据之前,我们需要精通 Ultralytics 的 YOLOv8 姿态模型所接受的关键点检测注释格式。以下几点突出显示了用于微调 Ultralytics 的 YOLOv8 Pose 模型的数据集格式:

用于训练YOLO姿态模型的数据集格式如下:

每张图片一个文本文件:数据集中的每张图片都有一个对应的文本文件,其名称和扩展名与图片相同。.txt
每个对象一行:文本文件中的每一行对应于图像中的一个对象实例。
每行对象信息:每行包含有关对象实例的以下信息:
对象类索引:表示对象类的整数(例如,人、汽车等)。01
对象中心坐标:对象中心的 x 和 y 坐标归一化为 和 。01
对象宽度和高度:对象的宽度和高度被规范化为介于 和 之间。01
对象宽度和高度:对象的宽度和高度被规范化为介于 和 之间。01
此外,可见性标志与关键点坐标相关联。它可以包含以下三个值之一:

0:未标记
1:已标记但不可见
2:已标记且可见。
JSON 注释包含一个额外的布尔可见性标志和前面讨论的关键点坐标。我们将所有可见关键点的标志设置为 。2

Ultralytics 中微调姿态模型的关键点注释对应于以下语法:

0 0.55991 0.503 0.76688 0.918 0.39143 0.91133 2.0 0.44227 0.72467 2.0

条目中的第一项是CLASS_ID,后跟边界框数据(规范化 x中心、y中心、宽度、高度),最后是归一化坐标以及可见性标志(即,对于两个关键点)。[x y]2

下载图像数据和关键点元数据

在开始数据准备之前,我们需要先下载图像数据。让我们定义一个实用程序函数,用于下载和提取包含图像的文件。此外,我们还将下载包含关键点元数据的元数据,例如动物姿势名称、每个关键点的颜色编码等,涵盖所有关键点。images.tarkeypoint_definitions.csv24

def download_and_unzip(url, save_path):
 
    print("Downloading and extracting assets...", end="")
    file = requests.get(url)
    open(save_path, "wb").write(file.content)
 
    try:
        # Extract tarfile.
        if save_path.endswith(".tar"):
            with tarfile.open(save_path, "r") as tar:
                tar.extractall(os.path.split(save_path)[0])

现在让我们指定图像和元数据 URL 并下载它们。

IMAGES_URL = r"http://vision.stanford.edu/aditya86/ImageNetDogs/images.tar"
IMAGES_DIR = "Images"
IMAGES_TAR_PATH = os.path.join(os.getcwd(), f"{IMAGES_DIR}.tar")
 
ANNS_METADATA_URL = r"https://github.com/benjiebob/StanfordExtra/raw/master/keypoint_definitions.csv"
ANNS_METADATA = "keypoint_definitions.csv"
 
# Download if dataset does not exists.
if not os.path.exists(IMAGES_DIR):
    download_and_unzip(IMAGES_URL, IMAGES_TAR_PATH)
    os.remove(IMAGES_TAR_PATH)
 
if not os.path.isfile(ANNS_METADATA):
    download_and_unzip(ANNS_METADATA_URL, ANNS_METADATA)

所有下载的图像都将提取到目录中。它具有以下目录结构:Images

Images/
├── n02085620-Chihuahua
│   ├── n02085620_10074.jpg
│   ├── n02085620_10131.jpg
│   └── ...
├── n02085782-Japanese_spaniel
│   ├── n02085782_1039.jpg
│   ├── n02085782_1058.jpg
│   └── n02085782_962.jpg
└── ...

它指定了所有 120 个类别的狗的图像文件。

创建用于动物姿态估计的 YOLO 训练和验证目录
在为动物姿态估计创建训练和验证数据之前,我们需要有注释 JSON 文件。该目录包含文件以及训练、验证和测试拆分。StanfordExtra_V12StanfordExtra_v12.json

StanfordExtra_V12
├── StanfordExtra_v12.json
├── test_stanford_StanfordExtra_v12.npy
├── train_stanford_StanfordExtra_v12.npy
└── val_stanford_StanfordExtra_v12.npy

现在让我们阅读注释文件。

NN_PATH = "StanfordExtra_V12"
JSON_PATH = os.path.join(ANN_PATH, "StanfordExtra_v12.json")
 
with open(JSON_PATH) as file:
    json_data = json.load(file)

列表中的每个条目都是一个字典,其中包含图像和注释信息。示例实例可以是以下内容:json_data

{'img_path': 'n02091134-whippet/n02091134_3263.jpg',
 'img_width': 360,
 'img_height': 480,
 'img_bbox': [21, 55, 328, 422],
 'is_multiple_dogs': False,
 'joints': [[175.33333333333334, 453.3333333333333, 1],
  [260.0, 367.0, 1],
  [248.0, 296.6666666666667, 1],
  [337.6666666666667, 302.6666666666667, 1],
  [333.0, 265.0, 1],
  [329.3333333333333, 231.33333333333334, 1],
  [48.666666666666664, 415.0, 1],
  [167.0, 340.5, 1],
  [182.66666666666666, 280.3333333333333, 1],
  [0, 0, 0],
  [250.5, 253.0, 0],
  [277.0, 211.0, 0],
  [297.0, 200.5, 0],
  [0, 0, 0],
  [263.0, 117.0, 1],
  [193.66666666666666, 113.33333333333333, 1],
  [238.33333333333334, 182.0, 1],

它具有以下密钥:

img_path:图像文件的路径。
img_width:图像宽度。
img_height:图像高度。
img_box:[x 中的边界框注释分钟、y分钟、宽度、高度] 格式。
is_multiple_dogs:一个布尔值,表示存在单个或多个狗实例。
joints:每个 24 个关键点像素坐标 (x, y) 的列表,每个坐标都与可见性标志 和 相关联。01
seg:运行长度编码 (RLE) 中的分段掩码。
文件:,并由与原始列表相关的训练和验证索引组成。
为简单起见,我们将使用测试数据进行验证。训练集和测试集分别包括 6773 个和 1703 个样本。train_stanford_StanfordExtra_v12.npytest_stanford_StanfordExtra_v12.npyjson_data

                                 "train_stanford_StanfordExtra_v12.npy"))
val_ids = np.load(os.path.join(ANN_PATH, 
                               "test_stanford_StanfordExtra_v12.npy"))

现在,我们将为每个 YOLO 创建训练和验证目录。具体来说,它将具有以下目录结构:

animal-pose-data
├── train
│   ├── images (6773 files)
│   └── labels (6773 files)
└── valid
    ├── images (1703 files)
    └── labels (1703 files)

现在,让我们初始化并创建训练和验证数据的目录路径。

DATA_DIR = "animal-pose-data"
 
TRAIN_DIR         = f"train"
TRAIN_FOLDER_IMG    = f"images"
TRAIN_FOLDER_LABELS = f"labels"
 
TRAIN_IMG_PATH   = os.path.join(DATA_DIR, TRAIN_DIR, TRAIN_FOLDER_IMG)
TRAIN_LABEL_PATH = os.path.join(DATA_DIR, TRAIN_DIR, TRAIN_FOLDER_LABELS)
 
VALID_DIR           = f"valid"
VALID_FOLDER_IMG    = f"images"
VALID_FOLDER_LABELS = f"labels"
 
VALID_IMG_PATH   = os.path.join(DATA_DIR, VALID_DIR, VALID_FOLDER_IMG)
VALID_LABEL_PATH = os.path.join(DATA_DIR, VALID_DIR, VALID_FOLDER_LABELS)

接下来,我们将使用和使用之前获得的图像和注释数据来收集图像和注释数据。train_idsval_idsjson_data

train_json_data = []
for train_id in train_ids:
    train_json_data.append(json_data[train_id])
 
val_json_data = []
for val_id in val_ids:
    val_json_data.append(json_data[val_id])

现在,我们将使用图像路径将图像文件从之前创建的 和 数据复制到相应的文件夹。train_json_dataval_json_dataimagestrainvalid



for data in train_json_data:
    img_file = data["img_path"]
    filename = img_file.split("/")[-1]
    copyfile(os.path.join(IMAGES_DIR, img_file),
             os.path.join(TRAIN_IMG_PATH, filename))
 
 
for data in val_json_data:
    img_file = data["img_path"]
    filename = img_file.split("/")[-1]
    copyfile(os.path.join(IMAGES_DIR, img_file),
             os.path.join(VALID_IMG_PATH, filename))

创建最终的 YOLO 注释文本文件

我们数据准备的最后一项任务是根据 Ultralytics 的 YOLO 创建框和关键点注释。由于我们将处理单个类(即狗),因此我们将类索引设置为 。0

CLASS_ID = 0

鉴于框和地标处于绝对坐标中,我们需要在相对于图像分辨率的范围内对它们进行归一化。[0, 1]

该函数执行以下任务:create_yolo_boxes_kpts

修改关键点的可见性指示器(将标记关键点的可见性设置为 )。2
规范化边界框和关键点相对于图像尺寸的坐标。
将边界框转换为规范化形式。

def create_yolo_boxes_kpts(img_size, boxes, lm_kpts):
 
    IMG_W, IMG_H = img_size
    # Modify kpts with visibilities as 1s to 2s.
    vis_ones = np.where(lm_kpts[:, -1] == 1.)
    lm_kpts[vis_ones, -1] = 2.
 
    # Normalizing factor for bboxes and kpts.
    res_box_array = np.array([IMG_W, IMG_H, IMG_W, IMG_H])
    res_lm_array = np.array([IMG_W, IMG_H])
 
    # Normalize landmarks in the range [0,1].
    norm_kps_per_img = lm_kpts.copy()
    norm_kps_per_img[:, :-1]  = norm_kps_per_img[:, :-1] / res_lm_array
 
    # Normalize bboxes in the range [0,1].
    norm_bbox_per_img = boxes / res_box_array 
 
    # Create bboxes coordinates to YOLO.
    # x_c, y_c = x_min + bbox_w/2. , y_min + bbox_h/2.
    yolo_boxes = norm_bbox_per_img.copy()
    yolo_boxes[:2] = norm_bbox_per_img[:2] + norm_bbox_per_img[2:]/2.
 
    return yolo_boxes, norm_kps_per_img

以下是 的输入参数:create_yolo_boxes_kpts

img_size:指示图像尺寸(宽度、高度)的元组。
boxes:格式中的边界框。[xmin, ymin, width, height]
lm_kpts:具有形状 ( 的 ) 的地标关键点。[24, 3]3[x, y, visibility]
我们最终将根据之前获得的 和 为 YOLO 创建文件。该函数使用上述实用程序函数在 YOLO 中创建所需的注释。txttrain_json_dataval_json_datacreate_yolo_txt_files.txtcreate_yolo_boxes_kpts

def create_yolo_txt_files(json_data, LABEL_PATH):
 
    for data in json_data:
     
        IMAGE_ID = data["img_path"].split("/")[-1].split(".")[0]
     
        IMG_WIDTH, IMG_HEIGHT = data["img_width"], data["img_height"]
         
        landmark_kpts  = np.nan_to_num(np.array(data["joints"], dtype=np.float32))
        landmarks_bboxes = np.array(data["img_bbox"], dtype=np.float32)
         
        bboxes_yolo, kpts_yolo = create_yolo_boxes_kpts(
                                            (IMG_WIDTH, IMG_HEIGHT),
                                            landmarks_bboxes,
                                            landmark_kpts)
         
        TXT_FILE = IMAGE_ID+".txt"
         
        with open(os.path.join(LABEL_PATH, TXT_FILE), "w") as f:
                 
            x_c_norm, y_c_norm, box_width_norm, box_height_norm = round(bboxes_yolo[0],5),\
                                                                  round(bboxes_yolo[1],5),\
                                                                  round(bboxes_yolo[2],5),\
                                                                  round(bboxes_yolo[3],5),\
             
            kps_flattend = [round(ele,5) for ele in kpts_yolo.flatten().tolist()]
            line = f"{CLASS_ID} {x_c_norm} {y_c_norm} {box_width_norm} {box_height_norm} "
            line+= " ".join(map(str, kps_flattend))            
            f.write(line)

家 > 关键点检测 >动物姿态估计:微调 YOLOv8 姿态模型
动物姿态估计:微调 YOLOv8 姿态模型
库纳尔黎明库纳尔黎明
SEPTEMBER 19, 2023 5 评论
关键点检测 关键点估计 姿态估计 YOLO
动物后期估计功能gif
动物姿态估计是计算机视觉的一个研究领域,是人工智能的一个子领域,专注于自动检测和分析图像或视频片段中动物的姿势和位置。目标是确定一种或多种动物的身体部位(例如头部、四肢和尾巴)的空间排列。这项技术具有广泛的应用,从研究动物行为和生物力学到野生动物保护和监测。

在这篇博文中,我们将专门处理狗的关键点估计,并向您展示如何微调 Ultralytics 非常流行的 YOLOv8 姿势模型。

微调动物关键点的姿态模型可能具有挑战性,需要微调多个超参数。幸运的是,YOLOv8 在模型微调期间提供了相当多的超参数自定义。准确地说,我们将微调以下 YOLOv8 姿势模型:

斯坦福狗的动物姿势估计数据集
对于我们的动物姿势估计实验,我们将使用斯坦福数据集,该数据集包含 120 个品种的狗,分布在 20,580 张图像中。此外,数据集还包含这些图像的边界框注释。

关键点注释需要通过填写谷歌表单从 StandfordExtra 数据集下载。在 12,538 张图像中提供了 20 个狗姿势关键点的关键点注释(每条腿 3 个,每只耳朵 2 个,尾巴、鼻子和下巴 2 个)。

下载的注释将包含以下结构:

StanfordExtra_V12
├── StanfordExtra_v12.json
├── test_stanford_StanfordExtra_v12.npy
├── train_stanford_StanfordExtra_v12.npy
└── val_stanford_StanfordExtra_v12.npy

训练、验证和测试拆分分别作为原始数据的索引提供,这些数据分别包含 6773、4062 和 1703 图像的注释。StanfordExtra_v12.json

作者还以文件的形式提供了关键点元数据,其中包含动物姿势名称、每个关键点的颜色编码等。但是,它包含 24 个关键点(每个眼睛、喉咙和肩膀各 1 个)的信息。可以使用下图来说明关键点。CSV

用于动物姿势估计的狗标志点
需要微调的狗关键点
在总共 24 个关键点中,只有 20 个存在注释。对于遗漏的 4 个关键点(2 个用于眼睛、喉咙和凋零),坐标标记为 0。

还有一个额外的布尔可见性标志,它与 20 个关键点相关联:

0:不可见
1:可见
用于动物姿态估计的数据集异常
边界框和关键点的真值注释仅适用于单个对象实例。此外,仍然有相当多的不正确的注释,从下面的示例中可以看出。

动物姿态估计的数据异常
数据集异常
边界框和关键点的真值注释仅适用于单个对象实例。此外,仍然有相当多的不正确的注释,从下面的示例中可以看出。

从最左上角的图像中可以看出,边界框和关键点已针对两个不同的对象实例进行了注释。第一行的第二张和第四张图片(从左到右)以及第二行的第一张和第三张图片也反映了这一点。

此外,关键点也被错误地注释了,如第一行的第三张图片所示,下颌和左耳尖被错误地注释。第二行的第一张图像也是如此,其中左耳的尖端被错误标记。第二行的第四张图片中出现了另一个不正确的注释,其中两个耳塞都被贴错了标签。

如前所述,每个图像只有单个实例注释。观察第二行的第二张图片(从左到右),我们只有左边的狗的注释,而有三个狗的实例。

处理跨框和关键点的不匹配的地面实况注释,以进行动物姿态估计
处理不匹配的框和关键点注释的一种直观方法是根据给定的关键点估计矩形。这可以使用实用程序函数来近似给定一组坐标的矩形来完成。请稍等片刻,看看下面的示例。cv2.boundingRect

处理不匹配的注释以进行动物姿势估计
处理不匹配的边界框和关键点批注
尽管边界框并不完美,但使用上述方法处理不匹配的边界框和关键点注释可能成本低廉。我们可以运行一个检测模型,如 YOLOv8 来获得更准确的框注释,然后将关键点与最接近的边界框映射。

但是,我们将坚持使用原始 JSON 文件中提供的注释进行实验。

下载代码为了轻松完成本教程,请单击下面的按钮下载代码。注册完全免费!

下载代码

点击这里下载这篇文章的源代码
为训练和验证数据创建与 YOLOv8 一致的注解
在准备数据之前,我们需要精通 Ultralytics 的 YOLOv8 姿态模型所接受的关键点检测注释格式。以下几点突出显示了用于微调 Ultralytics 的 YOLOv8 Pose 模型的数据集格式:

用于训练YOLO姿态模型的数据集格式如下:

每张图片一个文本文件:数据集中的每张图片都有一个对应的文本文件,其名称和扩展名与图片相同。.txt
每个对象一行:文本文件中的每一行对应于图像中的一个对象实例。
每行对象信息:每行包含有关对象实例的以下信息:
对象类索引:表示对象类的整数(例如,人、汽车等)。01
对象中心坐标:对象中心的 x 和 y 坐标归一化为 和 。01
对象宽度和高度:对象的宽度和高度被规范化为介于 和 之间。01
对象宽度和高度:对象的宽度和高度被规范化为介于 和 之间。01
此外,可见性标志与关键点坐标相关联。它可以包含以下三个值之一:

0:未标记
1:已标记但不可见
2:已标记且可见。
JSON 注释包含一个额外的布尔可见性标志和前面讨论的关键点坐标。我们将所有可见关键点的标志设置为 。2

Ultralytics 中微调姿态模型的关键点注释对应于以下语法:

1
0 0.55991 0.503 0.76688 0.918 0.39143 0.91133 2.0 0.44227 0.72467 2.0
条目中的第一项是CLASS_ID,后跟边界框数据(规范化 x中心、y中心、宽度、高度),最后是归一化坐标以及可见性标志(即,对于两个关键点)。[x y]2

下载图像数据和关键点元数据
在开始数据准备之前,我们需要先下载图像数据。让我们定义一个实用程序函数,用于下载和提取包含图像的文件。此外,我们还将下载包含关键点元数据的元数据,例如动物姿势名称、每个关键点的颜色编码等,涵盖所有关键点。images.tarkeypoint_definitions.csv24
def download_and_unzip(url, save_path):

print("Downloading and extracting assets...", end="")
file = requests.get(url)
open(save_path, "wb").write(file.content)

try:
    # Extract tarfile.
    if save_path.endswith(".tar"):
        with tarfile.open(save_path, "r") as tar:
            tar.extractall(os.path.split(save_path)[0])
         
    print("Done")
except:
    print("Invalid file")

现在让我们指定图像和元数据 URL 并下载它们。

IMAGES_URL = r"http://vision.stanford.edu/aditya86/ImageNetDogs/images.tar"
IMAGES_DIR = "Images"
IMAGES_TAR_PATH = os.path.join(os.getcwd(), f"{IMAGES_DIR}.tar")
 
ANNS_METADATA_URL = r"https://github.com/benjiebob/StanfordExtra/raw/master/keypoint_definitions.csv"
ANNS_METADATA = "keypoint_definitions.csv"
 
if not os.path.exists(IMAGES_DIR):
    download_and_unzip(IMAGES_URL, IMAGES_TAR_PATH)
    os.remove(IMAGES_TAR_PATH)
 
if not os.path.isfile(ANNS_METADATA):
    download_and_unzip(ANNS_METADATA_URL, ANNS_METADATA)

所有下载的图像都将提取到目录中。它具有以下目录结构:Images

Images/
├── n02085620-Chihuahua
│   ├── n02085620_10074.jpg
│   ├── n02085620_10131.jpg
│   └── ...
├── n02085782-Japanese_spaniel
│   ├── n02085782_1039.jpg
│   ├── n02085782_1058.jpg
│   └── n02085782_962.jpg
└── ...

它指定了所有 120 个类别的狗的图像文件。

创建用于动物姿态估计的 YOLO 训练和验证目录
在为动物姿态估计创建训练和验证数据之前,我们需要有注释 JSON 文件。该目录包含文件以及训练、验证和测试拆分。

StanfordExtra_V12StanfordExtra_v12.json

StanfordExtra_V12
├── StanfordExtra_v12.json
├── test_stanford_StanfordExtra_v12.npy
├── train_stanford_StanfordExtra_v12.npy
└── val_stanford_StanfordExtra_v12.npy

现在让我们阅读注释文件。

ANN_PATH = "StanfordExtra_V12"
JSON_PATH = os.path.join(ANN_PATH, "StanfordExtra_v12.json")
 
with open(JSON_PATH) as file:
    json_data = json.load(file)

列表中的每个条目都是一个字典,其中包含图像和注释信息。示例实例可以是以下内容:json_data

{'img_path': 'n02091134-whippet/n02091134_3263.jpg',
 'img_width': 360,
 'img_height': 480,
 'img_bbox': [21, 55, 328, 422],
 'is_multiple_dogs': False,
 'joints': [[175.33333333333334, 453.3333333333333, 1],
  [260.0, 367.0, 1],
  [248.0, 296.6666666666667, 1],
  [337.6666666666667, 302.6666666666667, 1],
  [333.0, 265.0, 1],
  [329.3333333333333, 231.33333333333334, 1],
  [48.666666666666664, 415.0, 1],
  [167.0, 340.5, 1],
  [182.66666666666666, 280.3333333333333, 1],
  [0, 0, 0],
  [250.5, 253.0, 0],
  [277.0, 211.0, 0],
  [297.0, 200.5, 0],
  [0, 0, 0],
  [263.0, 117.0, 1],
  [193.66666666666666, 113.33333333333333, 1],
  [238.33333333333334, 182.0, 1],
  [231.66666666666666, 201.33333333333334, 1],
  [287.0, 69.61702127659575, 1],
  [187.36363636363637, 59.0, 1],
  [0, 0, 0],
  [0, 0, 0],
  [0, 0, 0],
  [0, 0, 0]],
 'seg': ...}

它具有以下密钥:

img_path:图像文件的路径。
img_width:图像宽度。
img_height:图像高度。
img_box:[x 中的边界框注释分钟、y分钟、宽度、高度] 格式。
is_multiple_dogs:一个布尔值,表示存在单个或多个狗实例。
joints:每个 24 个关键点像素坐标 (x, y) 的列表,每个坐标都与可见性标志 和 相关联。01
seg:运行长度编码 (RLE) 中的分段掩码。
文件:,并由与原始列表相关的训练和验证索引组成。
为简单起见,我们将使用测试数据进行验证。训练集和测试集分别包括 6773 个和 1703 个样本。

train_stanford_StanfordExtra_v12.npytest_stanford_StanfordExtra_v12.npyjson_data


train_ids = np.load(os.path.join(ANN_PATH, 
                                 "train_stanford_StanfordExtra_v12.npy"))
val_ids = np.load(os.path.join(ANN_PATH, 
                               "test_stanford_StanfordExtra_v12.npy"))

现在,我们将为每个 YOLO 创建训练和验证目录。具体来说,它将具有以下目录结构:

animal-pose-data
├── train
│   ├── images (6773 files)
│   └── labels (6773 files)
└── valid
    ├── images (1703 files)
    └── labels (1703 files)

现在,让我们初始化并创建训练和验证数据的目录路径。

DATA_DIR = "animal-pose-data"
 
TRAIN_DIR         = f"train"
TRAIN_FOLDER_IMG    = f"images"
TRAIN_FOLDER_LABELS = f"labels"
 
TRAIN_IMG_PATH   = os.path.join(DATA_DIR, TRAIN_DIR, TRAIN_FOLDER_IMG)
TRAIN_LABEL_PATH = os.path.join(DATA_DIR, TRAIN_DIR, TRAIN_FOLDER_LABELS)
 
VALID_DIR           = f"valid"
VALID_FOLDER_IMG    = f"images"
VALID_FOLDER_LABELS = f"labels"
 
VALID_IMG_PATH   = os.path.join(DATA_DIR, VALID_DIR, VALID_FOLDER_IMG)
VALID_LABEL_PATH = os.path.join(DATA_DIR, VALID_DIR, VALID_FOLDER_LABELS)
 
os.makedirs(TRAIN_IMG_PATH, exist_ok=True)
os.makedirs(TRAIN_LABEL_PATH, exist_ok=True)
os.makedirs(VALID_IMG_PATH, exist_ok=True)
os.makedirs(VALID_LABEL_PATH, exist_ok=True)

接下来,我们将使用和使用之前获得的图像和注释数据来收集图像和注释数据。

train_idsval_idsjson_data


train_json_data = []
for train_id in train_ids:
    train_json_data.append(json_data[train_id])
 
val_json_data = []
for val_id in val_ids:
    val_json_data.append(json_data[val_id])

现在,我们将使用图像路径将图像文件从之前创建的 和 数据复制到相应的文件夹。

train_json_dataval_json_dataimagestrainvalid

for data in train_json_data:
    img_file = data["img_path"]
    filename = img_file.split("/")[-1]
    copyfile(os.path.join(IMAGES_DIR, img_file),
             os.path.join(TRAIN_IMG_PATH, filename))
 
 
for data in val_json_data:
    img_file = data["img_path"]
    filename = img_file.split("/")[-1]
    copyfile(os.path.join(IMAGES_DIR, img_file),
             os.path.join(VALID_IMG_PATH, filename))

创建最终的 YOLO 注释文本文件

我们数据准备的最后一项任务是根据 Ultralytics 的 YOLO 创建框和关键点注释。由于我们将处理单个类(即狗),因此我们将类索引设置为 。0

1
CLASS_ID = 0
鉴于框和地标处于绝对坐标中,我们需要在相对于图像分辨率的范围内对它们进行归一化。[0, 1]

该函数执行以下任务:create_yolo_boxes_kpts

修改关键点的可见性指示器(将标记关键点的可见性设置为 )。2
规范化边界框和关键点相对于图像尺寸的坐标。
将边界框转换为规范化形式。
def create_yolo_boxes_kpts(img_size, boxes, lm_kpts):

IMG_W, IMG_H = img_size
# Modify kpts with visibilities as 1s to 2s.
vis_ones = np.where(lm_kpts[:, -1] == 1.)
lm_kpts[vis_ones, -1] = 2.

# Normalizing factor for bboxes and kpts.
res_box_array = np.array([IMG_W, IMG_H, IMG_W, IMG_H])
res_lm_array = np.array([IMG_W, IMG_H])

# Normalize landmarks in the range [0,1].
norm_kps_per_img = lm_kpts.copy()
norm_kps_per_img[:, :-1]  = norm_kps_per_img[:, :-1] / res_lm_array

# Normalize bboxes in the range [0,1].
norm_bbox_per_img = boxes / res_box_array 

# Create bboxes coordinates to YOLO.
# x_c, y_c = x_min + bbox_w/2. , y_min + bbox_h/2.
yolo_boxes = norm_bbox_per_img.copy()
yolo_boxes[:2] = norm_bbox_per_img[:2] + norm_bbox_per_img[2:]/2.

return yolo_boxes, norm_kps_per_img

以下是 的输入参数:create_yolo_boxes_kpts

img_size:指示图像尺寸(宽度、高度)的元组。
boxes:格式中的边界框。[xmin, ymin, width, height]
lm_kpts:具有形状 ( 的 ) 的地标关键点。[24, 3]3[x, y, visibility]
我们最终将根据之前获得的 和 为 YOLO 创建文件。该函数使用上述实用程序函数在 YOLO 中创建所需的注释。txttrain_json_dataval_json_datacreate_yolo_txt_files.txtcreate_yolo_boxes_kpts

def create_yolo_txt_files(json_data, LABEL_PATH):

for data in json_data:
 
    IMAGE_ID = data["img_path"].split("/")[-1].split(".")[0]
 
    IMG_WIDTH, IMG_HEIGHT = data["img_width"], data["img_height"]
     
    landmark_kpts  = np.nan_to_num(np.array(data["joints"], dtype=np.float32))
    landmarks_bboxes = np.array(data["img_bbox"], dtype=np.float32)
     
    bboxes_yolo, kpts_yolo = create_yolo_boxes_kpts(
                                        (IMG_WIDTH, IMG_HEIGHT),
                                        landmarks_bboxes,
                                        landmark_kpts)
     
    TXT_FILE = IMAGE_ID+".txt"
     
    with open(os.path.join(LABEL_PATH, TXT_FILE), "w") as f:
             
        x_c_norm, y_c_norm, box_width_norm, box_height_norm = round(bboxes_yolo[0],5),\
                                                              round(bboxes_yolo[1],5),\
                                                              round(bboxes_yolo[2],5),\
                                                              round(bboxes_yolo[3],5),\
         
        kps_flattend = [round(ele,5) for ele in kpts_yolo.flatten().tolist()]
        line = f"{CLASS_ID} {x_c_norm} {y_c_norm} {box_width_norm} {box_height_norm} "
        line+= " ".join(map(str, kps_flattend))            
        f.write(line)

它接受以下参数:

json_data:每个词典包含图像元数据的词典列表,包括图像尺寸、关键点(关节)和边界框 (img_bbox)。
LABEL_PATH:保存文本文件的路径。
注意:我们使用 NumPy 将带有 s 的关键点坐标转换为 0s。nan_to_numNaN

以下示例显示了一个这样的实例,其中关键点坐标为 NaNs。

'joints': [[423.5, 224.75, 1.0],
  [285.0, 284.0, 1.0],
  [265.0, 232.0, 0.0],
  [nan, nan, 0.0],
  [137.0, 238.0, 0.0],
  [153.0, 221.0, 0.0],
  [111.0, 212.6, 1.0],
  [75.0, 270.0, 0.0],
  [nan, nan, 0.0],
  [100.0, 234.0, 1.0],
  [nan, nan, 0.0],
  [nan, nan, 0.0],
  [87.0, 224.0, 0.0],
  [79.0, 218.0, 0.0],
  [312.6666666666667, 156.5, 1.0],
  [172.0, 133.83333333333334, 1.0],
  [223.5, 264.0, 1.0],
  [215.5, 304.8333333333333, 1.0],
  [nan, nan, 0.0],
  [nan, nan, 0.0],
  [nan, nan, 0.0],
  [nan, nan, 0.0],
  [nan, nan, 0.0],
  [nan, nan, 0.0]]

现在,我们将创建训练和验证注释。

create_yolo_txt_files(train_json_data, TRAIN_LABEL_PATH)
create_yolo_txt_files(val_json_data, VALID_LABEL_PATH)

可视化来自 YOLO 注释的数据

一旦我们创建了与YOLO兼容的数据,我们就可以可视化一些地面实况样本,以确保我们的转换是正确的。

在可视化样本之前,我们可以将可用的十六进制颜色编码映射到 RGB 值。keypoint_definitions.csv

ann_meta_data = pd.read_csv("keypoint_definitions.csv")
COLORS = ann_meta_data["Hex colour"].values.tolist()
 
COLORS_RGB_MAP = []
for color in COLORS:
    R, G, B = int(color[:2], 16), int(color[2:4], 16), int(color[4:], 16)
    COLORS_RGB_MAP.append({color: (R,G,B)})

该函数用于使用 对图像上相应的地标点进行注释。draw_landmarksCOLORS_RGB_MAP

def draw_landmarks(image, landmarks):
     
    radius = 5
    # Check if image width is greater than 1000 px.
    # To improve visualization.
    if (image.shape[1] > 1000):
        radius = 8
 
    for idx, kpt_data in enumerate(landmarks):
 
        loc_x, loc_y = kpt_data[:2].astype("int").tolist()
        color_id = list(COLORS_RGB_MAP[int(kpt_data[-1])].values())[0]
 
        cv2.circle(image,
                   (loc_x, loc_y),
                   radius,
                   color=color_id[::-1],
                   thickness=-1,
                   lineType=cv2.LINE_AA)
 
    return image

该函数用于注释边界框以及图像上的置信度分数(如果通过)。draw_boxes

def draw_boxes(image, detections, class_name = "dog", score=None, color=(0,255,0)):
 
    font_size = 0.25 + 0.07 * min(image.shape[:2]) / 100
    font_size = max(font_size, 0.5)
    font_size = min(font_size, 0.8)
    text_offset = 3
 
    thickness = 2
    # Check if image width is greater than 1000 px.
    # To improve visualization.
    if (image.shape[1] > 1000):
        thickness = 10
 
    xmin, ymin, xmax, ymax = detections[:4].astype("int").tolist()
    conf = round(float(detections[-1]),2)
    cv2.rectangle(image, 
                  (xmin, ymin),
                  (xmax, ymax),
                  color=(0,255,0),
                  thickness=thickness,
                  lineType=cv2.LINE_AA)
 
    display_text = f"{class_name}"
 
    if score is not None:
        display_text+=f": {score:.2f}"
 
    (text_width, text_height), _ = cv2.getTextSize(display_text, 
                                                   cv2.FONT_HERSHEY_SIMPLEX,
                                                   font_size, 2)
 
    cv2.rectangle(image,
                      (xmin, ymin),
                      (xmin + text_width + text_offset, ymin - text_height - int(15 * font_size)),
                      color=color, thickness=-1)
 
    image = cv2.putText(
                    image,
                    display_text,

现在,我们有了注释地标和边界框的实用程序。但是,我们需要绝对坐标(框和关键点)来在图像上注释它们 - 该实用程序在将注释转换为绝对坐标后绘制注释。visualize_annotations

回想一下,边界框坐标和关键点在 范围内被归一化。但是,要绘制它们,我们需要绝对坐标。[0, 1]

从 YOLO bboxes 到 的转换映射非常简单,可以使用以下公式集获得:[xmin, ymin, xmax, ymax]

x m i n = W 2 ( 2 x c e n t e r   −   w i d t h ) x_{min} = \frac{W}{2} (2x_{center} \ - \ width) xmin=2W2xcenter  width
y m i n = H 2 ( 2 y c e n t e r   −   h e i g h t ) y_{min} = \frac{H}{2} (2y_{center} \ - \ height) ymin=2H2ycenter  height
x m a x = x m i n + 宽度 ∗ W x_{max} = x_{min} + 宽度 * W xmax=xmin+宽度W
y m a x = y m i n + 高度 ∗ H y_{max} = y_{min} + 高度 * H ymax=ymin+高度H
同样,可以使用以下公式对关键点进行非规范化(到绝对坐标):

x a b s = x n o r m ∗ W x_{abs} = x_{norm}* W xabs=xnormW
y a b s = y n o r m ∗ H y_{abs} = y_{norm}* H yabs=ynormH
这里,and 分别是框的宽度和高度,而 and 分别是图像的宽度和高度。widthheightWH

def visualize_annotations(image, box_data, keypoints_data):
 
    image = image.copy()
 
    shape_multiplier = np.array(image.shape[:2][::-1]) # (W, H).
    # Final absolute coordinates (xmin, ymin, xmax, ymax).
    denorm_boxes = np.zeros_like(box_data)
 
    # De-normalize center coordinates from YOLO to (xmin, ymin).
    denorm_boxes[:, :2] = (shape_multiplier/2.) * (2*box_data[:,:2] - box_data[:,2:])
 
    # De-normalize width and height from YOLO to (xmax, ymax).
    denorm_boxes[:, 2:] = denorm_boxes[:,:2] + box_data[:,2:]*shape_multiplier
 
    for boxes, kpts in zip(denorm_boxes, keypoints_data):
        # De-normalize landmark coordinates.
        kpts[:, :2]*= shape_multiplier        
        image = draw_boxes(image, boxes)
        image = draw_landmarks(image, kpts)

下图显示了一些图像样本及其相应的地面实况注释。关键点批注根据其相应的可见性标志进行筛选。在这里插入图片描述
在这里插入图片描述
在我们的实验中,我们将使用 YOLOv8m-pose 和 YOLOv8l-pose 模型。

训练配置

我们将定义训练配置,以便在课堂上进行微调。

TrainingConfig
@dataclass(frozen=True)
class TrainingConfig:
    DATASET_YAML:   str = "animal-keypoints.yaml"
    MODEL:          str = "yolov8m-pose.pt"
    EPOCHS:         int = 100
    KPT_SHAPE:    tuple = (24,3)
    PROJECT:        str = "Animal_Keypoints"
    NAME:           str = f"{MODEL.split('.')[0]}_{EPOCHS}_epochs"
    CLASSES_DICT:  dict = field(default_factory = lambda:{0 : "dog"})

观察 (keypoint shape) 参数。 表示要训练的关键点数,同时指示坐标和“可见性”标志。KPT_SHAPE243x-y

数据配置

该类采用与数据相关的各种超参数,例如训练时要使用的图像大小和批大小,以及各种增强概率,例如马赛克、水平翻转等。DatasetConfig


@dataclass(frozen=True)
class DatasetConfig:
    IMAGE_SIZE:    int   = 640
    BATCH_SIZE:    int   = 16
    CLOSE_MOSAIC:  int   = 10
    MOSAIC:        float = 0.4
    FLIP_LR:       float = 0.0 # Turn off horizontal flip.

接下来,我们实例化 和 类。TrainingConfigDatasetConfig


2
train_config = TrainingConfig()
data_config = DatasetConfig()

在开始训练之前,我们需要创建一个包含图像和标签文件的路径。我们还需要指定类名、起始点和关键点形状。yamlindex=0

如果关键点沿参考点或一组参考点对称(例如,鼻子的一组关键点可以用作面部的参考点),我们也可以提供参数。flip_idx

例如,如果我们假设面部特征的五个关键点:[左眼、右眼、鼻子、左嘴、右嘴],并且原始索引是 ,那么flip_idx是 。当水平翻转用作数据增强时,这是必不可少的。[0, 1, 2, 3, 4][1, 0, 2, 4, 3]

注意:我们已经关闭了实验的水平(LR翻转)。

current_dir = os.getcwd()
 
data_dict = dict(
                path      = os.path.join(current_dir, DATA_DIR),
                train     = os.path.join(TRAIN_DIR, TRAIN_FOLDER_IMG),
                val       = os.path.join(VALID_DIR, VALID_FOLDER_IMG),
                names     = train_config.CLASSES_DICT,
                kpt_shape = list(train_config.KPT_SHAPE),
               )
 
with open(train_config.DATASET_YAML, "w") as config_file:
    yaml.dump(data_dict, config_file)

动物姿势估计的微调和训练

最后,我们将使用上面定义的配置进行训练。

pose_model = model = YOLO(train_config.MODEL)

pose_model.train(data = train_config.DATASET_YAML,
epochs = train_config.EPOCHS,
imgsz = data_config.IMAGE_SIZE,
batch = data_config.BATCH_SIZE,
project = train_config.PROJECT,
name = train_config.NAME,
close_mosaic = data_config.CLOSE_MOSAIC,
mosaic = data_config.MOSAIC,
fliplr = data_config.FLIP_LR
)

YOLOv8在动物姿态估计中的评价

回想一下,在目标检测中,交并集 (IoU) 对于查找两个框之间的相似性以及计算平均精度精度 (mAP) 至关重要。它与关键点估计类似,是对象关键点相似性 (OKS)。

OKS 的定义如下:在这里插入图片描述
d我是真值与预测关键点 i 之间的欧几里得距离
k 是关键点 i 的常数
s 是真值对象的比例尺;s2因此成为对象的分割区域。
v我是关键点的真值可见性标志i
δ(v我> 0)是狄拉克-德尔塔函数,其计算方式就好像关键点被标记一样,否则1i0
查看我们最近的文章,其中我们深入讨论了对象关键点相似性 (OKS)。

使用上面的配置,我们获得了 YOLOv8m 的以下指标:

Box 指标:
mAP@50: 0.991
map@50-95:0.922
姿势指标:
mAP@50: 0.937
map@50-95:0.497
下图显示了 YOLOv8m 的指标。在这里插入图片描述
以下是使用与训练 YOLOv8m 相同的超参数设置的 YOLOv8l 的指标:

Box 指标:
mAP@50: 0.992
map@50-95:0.932
姿势指标:
mAP@50: 0.941
map@50-95:0.509
下图显示了 YOLOv8l 的日志:在这里插入图片描述
观察 box、cls、dfl 的急剧下降,并在第 90 纪元后造成损失。这正是马赛克增强被关闭的时候!
您还可以查看 YOLOv8m 和 YOLOv8l 的 tensorboard 训练日志。

图像预测的可视化##

该函数获取相应图像的预测框、置信度分数和关键点。它接受以下阈值:prepare_predictions

BOX_IOU_THRESH:过滤掉大于此阈值的重叠边界框。
“BOX_CONF_THRESH”:筛选置信度分数低于此阈值的框。
KPT_CONF_THRESH:过滤置信度分数低于阈值的关键点坐标。



def prepare_predictions(
    image_dir_path,
    image_filename, 
    model,
    BOX_IOU_THRESH = 0.55,
    BOX_CONF_THRESH=0.30,
    KPT_CONF_THRESH=0.68):
 
    image_path = os.path.join(image_dir_path, image_filename)
    image = cv2.imread(image_path).copy()
 
    results = model.predict(image_path, conf=BOX_CONF_THRESH, iou=BOX_IOU_THRESH)[0].cpu()
 
    if not len(results.boxes.xyxy):
        return image
 
    # Get the predicted boxes, conf scores and keypoints.    
    pred_boxes = results.boxes.xyxy.numpy()
    pred_box_conf = results.boxes.conf.numpy()
    pred_kpts_xy = results.keypoints.xy.numpy()
    pred_kpts_conf = results.keypoints.conf.numpy()
 
    # Draw predicted bounding boxes, conf scores and keypoints on image.
    for boxes, score, kpts, confs in zip(pred_boxes, pred_box_conf, pred_kpts_xy, pred_kpts_conf):
        kpts_ids = np.where(confs > KPT_CONF_THRESH)[0]
        filter_kpts = kpts[kpts_ids]
        filter_kpts = np.concatenate([filter_kpts, np.expand_dims(kpts_ids, axis=-1)], axis=-1)
        image = draw_boxes(image, boxes, score=score)
        image = draw_landmarks(image, filter_kpts)
 

以下是 YOLOv8m 姿态模型的预测样本。在这里插入图片描述
下图表示 YOLOv8l 姿态模型的可视化效果。在这里插入图片描述
比较两个推理样本,即使 YOLOv8l 的指标略高,YOLOv8m 的性能似乎也略高于 YOLOv8l。

我们可以从下面的视频示例中确认这一点。

从样本图像和视频推断中,我们可以观察到模型仍有改进的空间,因为关键点预测,尤其是耳塞和尾部,不是最优的。通过解决我们之前讨论的数据集异常,可以显著改进预测。

结论

在本文中,我们了解了如何微调 YOLOv8 以进行动物姿态估计。我们还看到现有数据集中存在异常,这可能阻碍了模型学习,这从样本推断中可以明显看出。

可以通过正确标记注释来缓解异常,这可以改善现有模型的指标。
此外,我们还看到 YOLOv8 medium 在可视化方面的表现优于 YOLOv8 large,尽管指标略高于 YOLOv8m。

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

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

相关文章

一起学习生成式人工智能(四)|用低代码实现人工智能应用

点击蓝字 关注我们 编辑:Alan Wang 排版:Rani Sun 微软 Reactor 为帮助广开发者,技术爱好者,更好的学习 .NET Core, C#, Python,数据科学,机器学习,AI,区块链, IoT 等技术&#xff0…

EasyRecovery(数据恢复软件) 2024中文绿色无需激活版下载

EasyRecovery是一款功能强大且专业的数据恢复软件,软件能够对电脑误删的文件进行恢复,包括格式化硬盘是数据恢复、手机U盘数据恢复等,小编今天给大家带来的是根据官软件解压后直接使用。感兴趣的朋友快来下载使用吧。 EasyRecovery-2024mac最…

Java数据结构篇——实现顺序表的增删查改

文章目录 1.线性表2. 顺序表2.1 顺序表结构2.2 实现顺序表接口2.3 打印顺序表2.2 实现新增元素2.3 实现查找元素2.3 获取pos位置的值2.4 删除元素2.5 获取顺序表的长度2.6 清空顺序表 3.代码在这 1.线性表 定义:线性表是 n 个具有相同特性的数据元素的有序序列。线…

数据库性能优化八大方案

毫不夸张的说咱们后端工程师,无论在哪家公司,呆在哪个团队,做哪个系统,遇到的第一个让人头疼的问题绝对是数据库性能问题。如果我们有一套成熟的方法论,能让大家快速、准确的去选择出合适的优化方案,我相信…

Unity之OpenXR+XR Interaction Toolkit接入Meta Quest3

前言 随着备受期待的Meta Quest 3与今年10月10日发布,这款来自Meta的下一代VR游戏头戴设备承诺将彻底改变您的游戏方式。 Meta Quest 3,玩家只需轻松一触即可在虚拟现实和真实世界之间无缝切换,无需摘下头戴设备进行快速现实检查。 Meta Quest 3最引人注目的特点之一是其能…

【知识积累】深度度量学习综述

原文指路:https://hav4ik.github.io/articles/deep-metric-learning-survey Problem Setting of Supervised Metric Learning 深度度量学习是一组旨在衡量数据样本之间相似性的技术。 Contrastive Approaches 对比方法的主要思想是设计一个损失函数,直…

pytorch中的归一化:BatchNorm、LayerNorm 和 GroupNorm

1 归一化概述 训练深度神经网络是一项具有挑战性的任务。 多年来,研究人员提出了不同的方法来加速和稳定学习过程。 归一化是一种被证明在这方面非常有效的技术。 1.1 为什么要归一化 数据的归一化操作是数据处理的一项基础性工作,在一些实际问题中&am…

六.聚合函数

聚合函数 1.什么是聚合函数1.1AVG和SUM函数1.2MIN和MAX函数1.3COUNT函数 2.GROUP BY2.1基本使用2.2使用多个列分组2.3GROUP BY中使用WITH ROLLUP 3.HAVING3.1基本使用3.2WHERE和HAVING的区别 4.SELECT的执行过程4.1查询的结构4.2SELECT执行顺序4.3SQL执行原理 1.什么是聚合函数…

JOSEF约瑟快速跳闸继电器RXMS1RK216063 DC220V

系列型号 RXMS1 RK 216 437快速跳闸继电器;RXMS1 RK 216 237快速跳闸继电器; RXMS1 RK 216 449快速跳闸继电器;RXMS1 RK 216 249快速跳闸继电器; RXMS1 RK 216 450快速跳闸继电器;RXMS1 RK 216 250快速跳闸继电器&a…

HarmonyOS使用Web组件

Web组件的使用 1 概述 相信大家都遇到过这样的场景,有时候我们点击应用的页面,会跳转到一个类似浏览器加载的页面,加载完成后,才显示这个页面的具体内容,这个加载和显示网页的过程通常都是浏览器的任务。 ArkUI为我…

C语言实现贪吃蛇【完整版】

贪吃蛇 文章目录 贪吃蛇使用到的WIN32一些接口简单介绍控制台窗口大小隐藏光标控制光标的位置获取键盘的值的情况字符问题 游戏逻辑开始游戏打印地图初始化贪吃蛇创建食物 运行游戏控制蛇的移动 运行结束 贪吃蛇实现出来的效果如下: 贪吃蛇小游戏录屏 完整代码&…

【Spark精讲】Spark存储原理

目录 类比HDFS的存储架构 Spark的存储架构 存储级别 RDD的持久化机制 RDD缓存的过程 Block淘汰和落盘 类比HDFS的存储架构 HDFS集群有两类节点以管理节点-工作节点模式运行,即一个NameNode(管理节点)和多个DataNode(工作节点)。 Namenode管理文件系统的命名空…

销售技巧培训之如何提升金融销售技巧

销售技巧培训之如何提升金融销售技巧 在金融行业,销售技巧是决定业绩成败的关键因素之一。无论是销售保险、股票、债券,还是提供投资咨询服务,都需要掌握一定的销售技巧。本文将探讨如何提升金融销售技巧,通过案例分析&#xff0…

如何提升网络安全技术【蓝队】?在职学长告诉你

网络安全的防守技术是网络安全工程师必备技能,只有攻防兼备的白帽子,才算是真正的网安精英。 网络安全的攻击技术在前面我已经讲过了,感兴趣的可以去看看: 90%的人都不算会网络安全,这才是真正的白帽子技术【红队】 . …

GitHub帐户管理更改电子邮件

登录到您的 GitHub 帐户: 前往 GitHub 网站并使用您的凭据登录。 访问个人设置: 单击右上角的您的头像,然后选择“Settings”(设置)。 选择电子邮件选项卡: 在左侧边栏中选择“Emails”(电子邮…

单片稳压集成电路78LXX系列——固定的电压输出,适用于需100mA电源供给的应用场合(网络产品,声卡和电脑主板等产品)

78LXX系列是一款单片稳压集成电路,它们有一系列固定的电压输出,适用于需100mA电源供给的应用场合。78LXX系列采用T0-92和SOT-89-3L的封装形式。 主要特点: ● 最大输出电流为100mA ● 输出电压为3.3V. 5V. 6V. 8V、9V、10V、 12V和15V ● 热…

深入理解 Go Channel:解密并发编程中的通信机制

一、Channel管道 1、Channel说明 共享内存交互数据弊端 单纯地将函数并发执行是没有意义的。函数与函数间需要交互数据才能体现编发执行函数的意义虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发送静态问题为了保证数据交换的正确性&am…

HTTP、HTTPS、SSL协议以及相关报文讲解

目录 HTTP/HTTPS介绍 HTTP/HTTPS基本信息 HTTP如何实现有状态 HTTP请求与应答报文 HTTP请求报文 HTTP响应报文 SSL协议 SSL单向认证 SSL双向认证 HTTP连接建立与传输步骤 HTTP访问全过程相关报文(以访问www.download.cucdccom为例子) DNS报文…

什么是SEO优化

什么是SEO,百度其实就有答案,只是回答的很基础,说的都是基础概念,没有具体的体现在里面,SEO除了基础概念,还要有相应的构架,不然怎么弄都是一场空而已。 关于什么是SEO的文章导读? 1…

vite+vue3+electron搭建项目

编辑器使用vscode,打开一个空文件夹 第一步 初始化vite项目 初始化vite项目,命令 npm init vite 第二步 下载依赖 进入新建的项目,下载依赖,命令 cd vite-projec npm i第三步 使用cnpm下载 electron依赖 新建一个终端&#…