、一 数据标注与处理
(一)数据标注
使用labelme标注数据
标注完后在图片文件夹李会有对应的json文件(如图)
使用此代码可视化检查数据
# 导入工具包
import os
import cv2
import numpy as np
import json
import matplotlib.pyplot as plt
num = 0
# 图片与标签json的文件夹路径
files_path = r"D:\Myself_project\YOLOV8pose\data_me\Goal_Detect_data\xxxxx\images"
for file in os.listdir(files_path):
if file.endswith(".jpg"):
img_path = os.path.join(files_path, file)
img_bgr = cv2.imread(img_path)
file_profix = os.path.splitext(file)[0]
labelme_name = file_profix + '.json' # DSC_0219.json
labelme_path = os.path.join(files_path, labelme_name)
# 载入labelme格式的json标注文件
with open(labelme_path, 'r', encoding='utf-8') as f:
labelme = json.load(f)
# <<<<<<<<<<<<<<<<<<可视化框(rectangle)标注>>>>>>>>>>>>>>>>>>>>>
# 框可视化配置
bbox_color = (255, 129, 0) # 框的颜色
bbox_thickness = 5 # 框的线宽
# 框类别文字
bbox_labelstr = {
'font_size': 6, # 字体大小
'font_thickness': 14, # 字体粗细
'offset_x': 0, # X 方向,文字偏移距离,向右为正
'offset_y': -80, # Y 方向,文字偏移距离,向下为正
}
# 画框
for each_ann in labelme['shapes']: # 遍历每一个标注
if each_ann['shape_type'] == 'rectangle': # 筛选出框标注
# 框的类别
bbox_label = each_ann['label']
# 框的两点坐标
bbox_keypoints = each_ann['points']
bbox_keypoint_A_xy = bbox_keypoints[0]
bbox_keypoint_B_xy = bbox_keypoints[1]
# 左上角坐标
bbox_top_left_x = int(min(bbox_keypoint_A_xy[0], bbox_keypoint_B_xy[0]))
bbox_top_left_y = int(min(bbox_keypoint_A_xy[1], bbox_keypoint_B_xy[1]))
# 右下角坐标
bbox_bottom_right_x = int(max(bbox_keypoint_A_xy[0], bbox_keypoint_B_xy[0]))
bbox_bottom_right_y = int(max(bbox_keypoint_A_xy[1], bbox_keypoint_B_xy[1]))
# 画矩形:画框
img_bgr = cv2.rectangle(img_bgr, (bbox_top_left_x, bbox_top_left_y), (bbox_bottom_right_x, bbox_bottom_right_y),
bbox_color, bbox_thickness)
# 写框类别文字:图片,文字字符串,文字左上角坐标,字体,字体大小,颜色,字体粗细
img_bgr = cv2.putText(img_bgr, bbox_label, (
bbox_top_left_x + bbox_labelstr['offset_x'],
bbox_top_left_y + bbox_labelstr['offset_y']),
cv2.FONT_HERSHEY_SIMPLEX, bbox_labelstr['font_size'], bbox_color,
bbox_labelstr['font_thickness'])
# 可视化
plt.imshow(img_bgr[:, :, ::-1]) # 将bgr通道转换成rgb通道 (为防止图片过大 cv2不好展示所有用pil)
plt.show()
运行结果:
(二)数据处理
用下面代码把上面文件夹下的图片与json标签分开
import os
import shutil
# 图片与json标签的同一文件夹路径
source_folder = 'images'
# 分出后用来只存放图片的路径
out_img_folder = 'data_me/images'
# 分出后用来只存放json标签的路径
out_json_folder = "data_me/label_json"
# 确保目标文件夹存在,如果不存在则创建
os.makedirs(out_img_folder, exist_ok=True)
os.makedirs(out_json_folder, exist_ok=True)
for file_name in os.listdir(source_folder):
source_file_path = os.path.join(source_folder, file_name)
if file_name.endswith('.jpg'):
source_img_file_path = os.path.join(source_folder, file_name)
destination_img_file_path = os.path.join(out_img_folder, file_name)
shutil.move(source_img_file_path, destination_img_file_path)
elif file_name.endswith('.json'):
source_json_file_path = os.path.join(source_folder, file_name)
destination_json_file_path = os.path.join(out_json_folder, file_name)
shutil.move(source_json_file_path, destination_json_file_path)
print("=======ok")
运行完成后得到如下:
使用以下代码划分数据集
import os
import shutil
from tqdm import tqdm
import random
""" 使用:只需要修改 1. Dataset_folde,
2. os.chdir(os.path.join(Dataset_folder, 'images'))里的 images,
3. val_scal = 0.2
4. os.chdir('../label_json') label_json换成自己json标签文件夹名称 """
# 图片文件夹与json标签文件夹的根目录
Dataset_folder = r'D:\Myself_project\YOLOV8pose\data_me\Goal_Detect_data\xxxxx'
# 把当前工作目录改为指定路径
os.chdir(os.path.join(Dataset_folder, 'images')) # images : 图片文件夹的名称
folder = '.' # 代表os.chdir(os.path.join(Dataset_folder, 'images'))这个路径
imgs_list = os.listdir(folder)
random.seed(123) # 固定随机种子,防止运行时出现bug后再次运行导致imgs_list 里面的图片名称顺序不一致
random.shuffle(imgs_list) # 打乱
val_scal = 0.2 # 验证集比列
val_number = int(len(imgs_list) * val_scal)
val_files = imgs_list[:val_number]
train_files = imgs_list[val_number:]
print('all_files:', len(imgs_list))
print('train_files:', len(train_files))
print('val_files:', len(val_files))
os.mkdir('train')
for each in tqdm(train_files):
shutil.move(each, 'train')
os.mkdir('val')
for each in tqdm(val_files):
shutil.move(each, 'val')
os.chdir('../label_json')
os.mkdir('train')
for each in tqdm(train_files):
json_file = os.path.splitext(each)[0] + '.json'
shutil.move(json_file, 'train')
os.mkdir('val')
for each in tqdm(val_files):
json_file = os.path.splitext(each)[0] + '.json'
shutil.move(json_file, 'val')
print('划分完成')
结果:
适应代码把json标签转yolo的txt格式
import os
import json
import numpy as np
import shutil
"""使用: 1.修改类别 classes 你是几个类别就添加,比如你是类别cat,dog 则修改成classes = {'cat':0, 'dog':1}
2.修改 Dataset_root 成自己路径
3.修改os.chdir('json_label/train') 与 os.chdir('json_label/val ') ---> 标签文件夹下的train与val文件夹路径 """
# 图片与标签json文件的路径(Dataset_root下是图片文件夹与json标签文件夹)
Dataset_root = 'D:\Myself_project\YOLOV8pose\data_me\Goal_Detect_data\Set_Square'
classes = {
'sjb_rect':0,
}
os.chdir(Dataset_root)
os.mkdir('labels')
os.mkdir('labels/train')
os.mkdir('labels/val')
def process_single_json(labelme_path, save_folder='../../labels/train'):
# 载入 labelme格式的 json 标注文件
with open(labelme_path, 'r', encoding='utf-8') as f:
labelme = json.load(f)
img_width = labelme['imageWidth'] # 图像宽度
img_height = labelme['imageHeight'] # 图像高度
# 生成 YOLO 格式的 txt 文件
suffix = labelme_path.split('.')[-2]
yolo_txt_path = suffix + '.txt'
with open(yolo_txt_path, 'w', encoding='utf-8') as f:
for each_ann in labelme['shapes']: # 遍历每个框
if each_ann['shape_type'] == 'rectangle': # 筛选出框
# 获取类别 ID
bbox_class_id = classes[each_ann['label']]
# 左上角和右下角的 XY 像素坐标
bbox_top_left_x = int(min(each_ann['points'][0][0], each_ann['points'][1][0]))
bbox_bottom_right_x = int(max(each_ann['points'][0][0], each_ann['points'][1][0]))
bbox_top_left_y = int(min(each_ann['points'][0][1], each_ann['points'][1][1]))
bbox_bottom_right_y = int(max(each_ann['points'][0][1], each_ann['points'][1][1]))
# 框中心点的 XY 像素坐标
bbox_center_x = int((bbox_top_left_x + bbox_bottom_right_x) / 2)
bbox_center_y = int((bbox_top_left_y + bbox_bottom_right_y) / 2)
# 框宽度
bbox_width = bbox_bottom_right_x - bbox_top_left_x
# 框高度
bbox_height = bbox_bottom_right_y - bbox_top_left_y
# 框中心点归一化坐标
bbox_center_x_norm = bbox_center_x / img_width
bbox_center_y_norm = bbox_center_y / img_height
# 框归一化宽度
bbox_width_norm = bbox_width / img_width
# 框归一化高度
bbox_height_norm = bbox_height / img_height
# 生成 YOLO 格式的一行标注,指定保留小数点后几位
bbox_yolo_str = '{} {:.4f} {:.4f} {:.4f} {:.4f}'.format(bbox_class_id, bbox_center_x_norm,
bbox_center_y_norm, bbox_width_norm,
bbox_height_norm)
# 写入 txt 文件中
f.write(bbox_yolo_str + '\n')
shutil.move(yolo_txt_path, save_folder)
print('{} --> {} 转换完成'.format(labelme_path, yolo_txt_path))
os.chdir('json_label/train') # 标签文件夹下的train文件夹路径
save_folder = '../../labels/train'
for labelme_path in os.listdir():
process_single_json(labelme_path, save_folder=save_folder)
print('YOLO格式的txt标注文件已保存至 ', save_folder)
os.chdir(Dataset_root)
os.chdir('json_label/val') # 标签文件夹下的val文件夹路径
save_folder = '../../labels/val'
for labelme_path in os.listdir():
process_single_json(labelme_path, save_folder=save_folder)
print('YOLO格式的txt标注文件已保存至 ', save_folder)
结果:
此时数据已经全部处理好
二、环境配置与训练
假设conda已经安装,环境配置已完成
(一)、环境配置
cmd打开终端创建虚拟环境:
conda create -n yolo8 python==3.8
激活虚拟环境:
conda activate yolo8
安装匹配cuda的torch(我这里是cuda11.6)
安装pytorch
pip install torch==1.12.1+cu116 torchvision==0.13.1+cu116 torchaudio==0.12.1 --extra-index-url https://download.pytorch.org/whl/cu116
进入github仓库
使用命令克隆项目 或者直接 DownloadZip
git clone https://github.com/ultralytics/ultralytics.git
在项目文件夹下创建一个yaml配置文件,内容如下
在终端安装 各种包:
pip install numpy opencv-python pillow pandas matplotlib seaborn tqdm wandb seedir emoji -i https://pypi.tuna.tsinghua.edu.cn/simple
训练:命令或者python
命令训练:
yolo detect train data=yolov8n.yaml model=yolov8n.pt epochs=8 imgsz=640 batch=8 workers=2 device=0
python训练:
from ultralytics import YOLO
# 加载模型
model = YOLO('yolov8n.pt') # 加载预训练权重开始训练
# model = YOLO('yolov8n.yaml') # 从 YAML 构建一个新模型开始训练
# model = YOLO('yolov8n.yaml').load('yolov8n.pt') # 从YAML构建新模型并转移权重开始训练
if __name__ == '__main__':
# 训练模型 batch默认16 workers默认最大一般是8 pretrained默认True(如果不想加载预训练权重就设置False)
# (如果出现:OSError: [WinError 1455] 页面文件太小,无法完成操作)降低workers的值
results = model.train(data='triangle_goal_detect.yaml', epochs=10, imgsz=640, batch=8, device=0, workers=0)
# metrics = model.val()
训练完成后用python 接口侦测或者命令侦测;
命令侦测:
yolo task=detect mode=predict model=runs\detect\train11\weights\last.pt source=3.jpg device=0 save=True
python侦测:
from IPython import display
import ultralytics
from ultralytics import YOLO, settings
from os import path
def predict():
model = YOLO(r"D:\Myself_project\yolov8_pose_pre_whight\ultralytics\runs\detect\train\weights\last.pt")
image_file1 = r"bus.jpg"
image_file2 = r"2.jpg"
image_file3 = r"3.jpg"
# 预测一张图片:source=[image_file1] 预测多张图片:source=[image_file1, image_file2]
results_list = model.predict(source=[image_file3], show=False, save=True, save_conf=True, conf=0.5,
save_txt=False)
for results in results_list:
boxes = results.boxes
print(boxes.xyxy) # 所有框在原图上的左上角与右下角坐标
print()
for box in boxes.xyxy:
print(box) # 每个框在原图上的左上角与右下角坐标
if __name__ == '__main__':
predict()
欧克 全部完成