AI项目十八:YOLOV8自训练关键点检测一

news/2024/7/10 23:18:36 标签: YOLO

若该文为原创文章,转载请注明原文出处。

记录学习YOLOV8过程,自训练关键点检测模型。

清华源:-i https://mirror.baidu.com/pypi/simple

1、yolov8安装

git clone https://github.com/ultralytics/ultralytics
​
cd ultralytics
​
pip install -e .

安装成功后,使用命令 yolo 简单看下版本

(yolov8) llh@anhao:/$ yolo version
​
8.0.206

2、简单测试

下载权重文件

GitHub - ultralytics/ultralytics: NEW - YOLOv8 🚀 in PyTorch > ONNX > OpenVINO > CoreML > TFLite

直接点击下载。

获取测试图片的文件在ultralytics\assets目录有,使用的是的里面的bus.jpg测试。

使用 yolo 命令进行测试

yolo detect predict model=./yolov8n.pt source=./bus.jpg

输出在runs/detect/predict/目录下。

3、安装labelme

pip install labelme

直接在终端运行labelme打开软件

先取消“保存图片数据”(减少标注文件大小);在文件下

打开文件目录

接下来标注

  • 先标注检测框,检测框用Create Rectangle(Ctrl+N)

    • 填写类别名称

    • 填写group_id,用于匹配后续标注的关键点,以当前画面中出现的顺序标注即可。

  • 标注关键点,检测关键点用Create Point

    • 按关键点顺序标注,如我们的顺序是headtail,不可以错;

    • 填写关键点名称,如这里是head

    • 填写关键点所在物体的group_id,匹配检测框

注意,如果多个类型需要填写group_id,group_id要匹配检测框

4、把JSON转成TXT

使用labelme标注生成的JSON文件,不能直接训练,所以需要把JSON文件转成TXT文件。

打开一个标注json文件,内容大致如下:

version": "5.3.1",
  "flags": {},
  "shapes": [
    {
      "label": "smoke",
      "points": [
        [
          389.0,
          72.5
        ],
        [
          957.0,
          114.5
        ],
        [
          949.0,
          192.5
        ],
        [
          379.0,
          162.5
        ]
      ],
      "group_id": null,
      "description": "",
      "shape_type": "polygon",
      "flags": {}
    },

但是yolov8 要求的标注文件长这样

0 0.662641 0.494385 0.674719 0.988771 0.717187 0.189583 2.000000 0.798438 0.127083 2.000000 0.701562 0.091667 2.000000 0.921875 0.118750 2.000000 0.000000 0.000000 0.000000 0.971875 0.379167 2.000000 0.554688 0.262500 2.000000 0.000000 0.000000 0.000000 0.367188 0.427083 2.000000 0.767188 0.772917 2.000000 0.421875 0.500000 2.000000 0.829688 0.960417 1.000000 0.517188 0.881250 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000

根据这些规则,我们可以写一个转换脚本,将labelme标注的json格式转为yolo格式

labelme2yolo.py

# 将labelme标注的json文件转为yolo格式
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
import glob
import json
import tqdm
​
​
# 物体类别
class_list = ["smoke"]
# 关键点的顺序
keypoint_list = ["head", "tail"]
​
​
def json_to_yolo(img_data,json_data):
    h,w = img_data.shape[:2]
    # 步骤:
    # 1. 找出所有的矩形,记录下矩形的坐标,以及对应group_id
    # 2. 遍历所有的head和tail,记下点的坐标,以及对应group_id,加入到对应的矩形中
    # 3. 转为yolo格式
​
    rectangles = {}
    # 遍历初始化
    for shape in json_data["shapes"]:
        label = shape["label"] # pen, head, tail
        group_id = shape["group_id"] # 0, 1, 2, ...
        points = shape["points"] # x,y coordinates
        shape_type = shape["shape_type"]
​
        # 只处理矩形
        if shape_type == "rectangle":
            if group_id not in rectangles:
                rectangles[group_id] = {
                    "label": label,
                    "rect": points[0] + points[1],  # Rectangle [x1, y1, x2, y2]
                    "keypoints_list": []
                }
    # 遍历更新,将点加入对应group_id的矩形中
    for keypoint in keypoint_list:
        for shape in json_data["shapes"]:
            label = shape["label"]
            group_id = shape["group_id"]
            points = shape["points"]
            # 如果匹配到了对应的keypoint
            if label == keypoint:
                rectangles[group_id]["keypoints_list"].append(points[0])
    
    # 转为yolo格式
    yolo_list = []
    for id, rectangle in rectangles.items():
        result_list  = []
        label_id = class_list.index(rectangle["label"])
        # x1,y1,x2,y2
        x1,y1,x2,y2 = rectangle["rect"]
        # center_x, center_y, width, height
        center_x = (x1+x2)/2
        center_y = (y1+y2)/2
        width = abs(x1-x2)
        height = abs(y1-y2)
        # normalize
        center_x /= w
        center_y /= h
        width /= w
        height /= h
​
        # 保留6位小数
        center_x = round(center_x, 6)
        center_y = round(center_y, 6)
        width = round(width, 6)
        height = round(height, 6)
​
​
        # 添加 label_id, center_x, center_y, width, height
        result_list = [label_id, center_x, center_y, width, height]
​
        # 添加 p1_x, p1_y, p1_v, p2_x, p2_y, p2_v
        for point in rectangle["keypoints_list"]:
            x,y = point
            x,y = int(x), int(y)
            # normalize
            x /= w
            y /= h
            # 保留6位小数
            x = round(x, 6)
            y = round(y, 6)
            
            result_list.extend([x,y,2])
​
        yolo_list.append(result_list)
    
    return yolo_list
​
​
# 获取所有的图片
img_list = glob.glob("./*.jpg")
​
for img_path in tqdm.tqdm( img_list ):
        
    img = cv2.imread(img_path)
    print(img_path)
    json_file = img_path.replace('jpg', 'json')
    with open(json_file) as json_file:
        json_data = json.load(json_file)
​
    yolo_list = json_to_yolo(img, json_data)
    
    yolo_txt_path = img_path.replace('jpg', 'txt')
    with open(yolo_txt_path, "w") as f:
        for yolo in yolo_list:
            for i in range(len(yolo)):
                if i == 0:
                    f.write(str(yolo[i]))
                else:
                    f.write(" " + str(yolo[i]))
            f.write("\n")
​

运行后,把JSON生成TXT。

5、对yolo格式的标注进行可视化。检查标注是否正确。

先安装jupyter

pip install jupyter

然后在终端输入

jupyter-lab
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
import glob

img_path = './images/1.original_annotated/1 (20).jpg'

plt.figure(figsize=(15,10))
img = cv2.imread(img_path)
plt.imshow(img[:,:,::-1])
plt.axis('off')

yolo_txt_path = img_path.replace('jpg', 'txt')
print(yolo_txt_path)

with open(yolo_txt_path, 'r') as f:
    lines = f.readlines()

lines = [x.strip() for x in lines]

label = np.array([x.split() for x in lines], dtype=np.float32)

# 物体类别
class_list = ["smoke"]
# 类别的颜色
class_color = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255,255,0)]
# 关键点的顺序
keypoint_list = ["head", "tail"]
# 关键点的颜色
keypoint_color = [(255, 0, 0), (0, 255, 0)]

# 绘制检测框
img_copy = img.copy()
h,w = img_copy.shape[:2]
for id,l in enumerate( label ):
    # label_id ,center x,y and width, height
    label_id, cx, cy, bw, bh = l[0:5]
    label_text = class_list[int(label_id)]
    # rescale to image size
    cx *= w
    cy *= h
    bw *= w
    bh *= h
    
    # draw the bounding box
    xmin = int(cx - bw/2)
    ymin = int(cy - bh/2)
    xmax = int(cx + bw/2)
    ymax = int(cy + bh/2)
    cv2.rectangle(img_copy, (xmin, ymin), (xmax, ymax), class_color[int(label_id)], 2)
    cv2.putText(img_copy, label_text, (xmin, ymin-10), cv2.FONT_HERSHEY_SIMPLEX, 1, class_color[int(label_id)], 2)


# display the image
plt.figure(figsize=(15,10))
plt.imshow(img_copy[:,:,::-1])
plt.axis('off')
# save the image
cv2.imwrite("./tmp.jpg", img_copy)

img_copy = img.copy()
h,w = img_copy.shape[:2]
for id,l in enumerate( label ):
    # label_id ,center x,y and width, height
    label_id, cx, cy, bw, bh = l[0:5]
    label_text = class_list[int(label_id)]
    # rescale to image size
    cx *= w
    cy *= h
    bw *= w
    bh *= h
    
    # draw the bounding box
    xmin = int(cx - bw/2)
    ymin = int(cy - bh/2)
    xmax = int(cx + bw/2)
    ymax = int(cy + bh/2)
    cv2.rectangle(img_copy, (xmin, ymin), (xmax, ymax), class_color[int(label_id)], 2)
    cv2.putText(img_copy, label_text, (xmin, ymin-10), cv2.FONT_HERSHEY_SIMPLEX, 2, class_color[int(label_id)], 2)
    
    # draw 17 keypoints, px,py,pv,px,py,pv...
    for i in range(5, len(l), 3):
        px, py, pv = l[i:i+3]
        # rescale to image size
        px *= w
        py *= h
        # puttext the index 
        index = int((i-5)/3)
        # draw the keypoints
        cv2.circle(img_copy, (int(px), int(py)), 10, keypoint_color[int(index)], -1)
        keypoint_text = "{}_{}".format(index, keypoint_list[index])
        cv2.putText(img_copy, keypoint_text, (int(px), int(py)-10), cv2.FONT_HERSHEY_SIMPLEX, 1, keypoint_color[int(index)], 2)

plt.figure(figsize=(15,10))
plt.imshow(img_copy[:,:,::-1])
plt.axis('off')
# save 
cv2.imwrite('./tmp.jpg', img_copy)

6、训练

组织目录结构,我是直接把datasets目录放到yolov8的根目录下:

  • 图片 datasets/custom_dataset/images/train/{文件名}.jpg对应的标注文件在 datasets/custom_dataset/labels/train/{文件名}.txtYOLO会根据这个映射关系自动寻找(images换成labels);
  • 训练集和验证集
    • images文件夹下有trainval文件夹,分别放置训练集和验证集图片;
    • labels文件夹有trainval文件夹,分别放置训练集和验证集标签(yolo格式)。

配置文件smoke.yaml

# Ultralytics YOLO 🚀, AGPL-3.0 license
# COCO8-pose dataset (first 8 images from COCO train2017) by Ultralytics
# Example usage: yolo train data=coco8-pose.yaml
# parent
# ├── ultralytics
# └── datasets
#     └── coco8-pose  ← downloads here (1 MB)


# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: ../datasets/custom_dataset  # dataset root dir
train: images/train  # train images (relative to 'path') 4 images
val: images/val  # val images (relative to 'path') 4 images
test:  # test images (optional)

# Keypoints
kpt_shape: [2, 3]  # number of keypoints, number of dims (2 for x,y or 3 for x,y,visible)
#flip_idx: [0, 2, 1, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 16, 15]

# Classes
names:
  0: smoke

# Download script/URL (optional)
#download: https://ultralytics.com/assets/coco8-pose.zip

編寫訓練train.py,訓練自己的模型

from ultralytics import YOLO

# 加载模型
# model = YOLO('yolov8s-pose.yaml')  # 从头训练
model = YOLO('./yolov8s-pose.pt')  # 使用预训练模型 (recommended for training)
# model = YOLO('yolov8s-pose.yaml').load('yolov8s-pose.pt')  # 从yaml构建网络并从预训练模型中迁移权重

# 训练
results = model.train(data='./smoke_pose.yaml', epochs=300, imgsz=640, workers=0, batch=20, project="pen_bolt", name="s120")

执行python train.py

会看到开始训练,并在pen_bolt\s1202下看到训练的结果。

如有侵权,或需要完整代码,请及时联系博主。


http://www.niftyadmin.cn/n/5269275.html

相关文章

.NET基础面试题一

1.C#中堆和栈的区别? 堆(Heap)和栈(Stack)是C#中两种分配内存的不同方式 栈(Stack):是一种先进后出的内存分配方式。它用于存储基本数据类型和对象引用,它是一种连续的内存空间,存储在cpu的寄存器上,它的大小在编译的时就是已知的…

【C语言】——认识指针变量和地址,以及指针变量类型的意义

🎥 岁月失语唯石能言的个人主页 🔥个人栏专:秒懂C语言 ⭐若在许我少年时,一两黄金一两风 目录 前言 一、指针变量和地址 1.1 取地址操作符(&) 1.2 指针变量和解引用操作符&#xff…

Golang. channel的关闭

使用内置函数close可以关闭channel,当channel关闭后,就不能再向channel写数据了,但是仍然可以从channel中读取数据。 一旦将channel关闭了,只能读不能写。相当于关闭管道就数据不能进入到队列里面了,只能进行读操作&a…

UE5Console 控制台命令

启动模块,注册 void FAdvModModule::StartupModule() {RegisterConsole(); }void FAdvModModule::RegisterConsole() {IConsoleManager::Get().RegisterConsoleVariable(TEXT("adv.bLocked"), true, TEXT("Lock selected actor!"), ECVF_Scala…

Android Studio Gradle构建很慢,下载依赖缓慢问题

在项目的 build.gradle或setting.gradle(Android Studio新老版本配置不同)中配置镜像源 阿里云: maven { url https://maven.aliyun.com/repository/gradle-plugin } maven { url https://maven.aliyun.com/repository/spring-plugin } mav…

每日一题:LeetCode-611. 有效三角形的个数

每日一题系列(day 14) 前言: 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 &#x1f50e…

docker compose部署wordpress

准备机器: 192.168.58.151 (关闭防火墙和selinux) 安装好docker服务 (详细参照:http://t.csdnimg.cn/usG0s 中的国内源安装docker) 部署wordpress: 创建目录: [rootdocker ~]# mkdi…

基于高通MSM8953平台的android系统CW2015电量计驱动开发

3.1、修改aboot.c文件: 修改/bootable/bootloader/lk/app/aboot/aboot.c,增加: +#include <i2c_qup.h> +#include <blsp_qup.h> #include <app.h> extern int get_target_boot_params(const char *cmdline, const char *part, char **buf); +static s…