YOLOv8实例分割并训练自己的数据篇(小白版)
数据标注及处理
- 标注工具:labelme
- 标注文件:json格式(标注完后的格式)
- 训练数据要求:坐标归一化的txt文件
1.利用labelme进行数据标注
1.1Labelme 安装方法
首先你得先安装 有Anaconda,然后在你的虚拟环境下运行下列命令:
(前提你是已经配置好了自己的虚拟环境和相关的库,没有的同学请看我另一篇博文)
(下面安装图像标注工具labelme)
pip install labelme
安装好后,输入打开图像标注工具labelme的指令:
labelme
1.2Labelme 使用教程
使用 labelme 进行场景分割标注的教程详见:labelme(官方教程,打开需要T子)
2.新建训练目录
找个空目录(可以去E盘里),新建文件夹,名称叫做 mydataset,也可以是其他名称,这里的例子是在E盘的mydataset文件夹
在 mydataset新建roadscene_train和roadscene_val文件夹。
标注数据
将准备好的数据集图片文件放置在mydataset目录下的 roadscene_train文件夹。
打开 labelme软件点OpenDir进入选择roadscene_train文件夹。
(Open只能打开一副图片,所以选择OpenDir打开目录所有图片)
中文界面解释
下面选择(创建多边形)开始标注图形轮廓
标注完后输入标签
标注完成后,点下一张,它会叫保存,我们直接选Save保存.
标注完后,再复制一份json文件到roadscene_val文件夹里
图像标注格式转换
把labelme标注的json数据格式转换成COCO数据格式的。依次输入以下指令:
(我这里是虚拟环境下切换到E盘,如图)
cd mydataset
python labelme2cocoAll.py roadscene_train --output roadscene_train.json
python labelme2cocoAll.py roadscene_val --output roadscene_val.json
转换后的两个COCO格式文件如图:
如果输入指令提示找不到labelme2cocoAll.py文件,那么我们就在mydataset目录下新建一个labelme2cocoAll.py文件,再输入以下代码:
import os
import argparse
import json
from labelme import utils
import numpy as np
import glob
import PIL.Image
class labelme2coco(object):
def __init__(self, labelme_json=[], save_json_path="./coco.json"):
"""
:param labelme_json: the list of all labelme json file paths
:param save_json_path: the path to save new json
"""
self.labelme_json = labelme_json
self.save_json_path = save_json_path
self.images = []
self.categories = []
self.annotations = []
self.label = []
self.annID = 1
self.height = 0
self.width = 0
self.save_json()
def data_transfer(self):
for num, json_file in enumerate(self.labelme_json):
with open(json_file, "r") as fp:
data = json.load(fp)
self.images.append(self.image(data, num))
for shapes in data["shapes"]:
label = shapes["label"].split("_")
if label not in self.label:
self.label.append(label)
points = shapes["points"]
self.annotations.append(self.annotation(points, label, num))
self.annID += 1
# Sort all text labels so they are in the same order across data splits.
self.label.sort()
for label in self.label:
self.categories.append(self.category(label))
for annotation in self.annotations:
annotation["category_id"] = self.getcatid(annotation["category_id"])
def image(self, data, num):
image = {}
img = utils.img_b64_to_arr(data["imageData"])
height, width = img.shape[:2]
img = None
image["height"] = height
image["width"] = width
image["id"] = num
image["file_name"] = data["imagePath"].split("/")[-1]
self.height = height
self.width = width
return image
def category(self, label):
category = {}
category["supercategory"] = label[0]
category["id"] = len(self.categories)
category["name"] = label[0]
return category
def annotation(self, points, label, num):
annotation = {}
contour = np.array(points)
x = contour[:, 0]
y = contour[:, 1]
area = 0.5 * np.abs(np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1)))
annotation["segmentation"] = [list(np.asarray(points).flatten())]
annotation["iscrowd"] = 0
annotation["area"] = area
annotation["image_id"] = num
annotation["bbox"] = list(map(float, self.getbbox(points)))
annotation["category_id"] = label[0] # self.getcatid(label)
annotation["id"] = self.annID
return annotation
def getcatid(self, label):
for category in self.categories:
if label == category["name"]:
return category["id"]
print("label: {} not in categories: {}.".format(label, self.categories))
exit()
return -1
def getbbox(self, points):
polygons = points
mask = self.polygons_to_mask([self.height, self.width], polygons)
return self.mask2box(mask)
def mask2box(self, mask):
index = np.argwhere(mask == 1)
rows = index[:, 0]
clos = index[:, 1]
left_top_r = np.min(rows) # y
left_top_c = np.min(clos) # x
right_bottom_r = np.max(rows)
right_bottom_c = np.max(clos)
return [
left_top_c,
left_top_r,
right_bottom_c - left_top_c,
right_bottom_r - left_top_r,
]
def polygons_to_mask(self, img_shape, polygons):
mask = np.zeros(img_shape, dtype=np.uint8)
mask = PIL.Image.fromarray(mask)
xy = list(map(tuple, polygons))
PIL.ImageDraw.Draw(mask).polygon(xy=xy, outline=1, fill=1)
mask = np.array(mask, dtype=bool)
return mask
def data2coco(self):
data_coco = {}
data_coco["images"] = self.images
data_coco["categories"] = self.categories
data_coco["annotations"] = self.annotations
return data_coco
def save_json(self):
print("save coco json")
self.data_transfer()
self.data_coco = self.data2coco()
print(self.save_json_path)
os.makedirs(
os.path.dirname(os.path.abspath(self.save_json_path)), exist_ok=True
)
json.dump(self.data_coco, open(self.save_json_path, "w"), indent=4)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(
description="labelme annotation to coco data json file."
)
parser.add_argument(
"labelme_images",
help="Directory to labelme images and annotation json files.",
type=str,
)
parser.add_argument(
"--output", help="Output json file path.", default="trainval.json"
)
args = parser.parse_args()
labelme_json = glob.glob(os.path.join(args.labelme_images, "*.json"))
labelme2coco(labelme_json, args.output)
保存好后退出,再继续运行上面的代码试试看。
COCO格式标注数据转换成YOLO格式
YOLO segmentation dataset label format extends detection format with segment points.
YOLO 分割数据集标签格式扩展了检测格式使其增加带有分割点。(翻译)
cls x1 y1 x2 y2 p1 p2 ... pn
To convert your existing dataset from other formats( like COCO, VOC etc.) to YOLO format, please use json2yolo tool by Ultralytics. The https://github.com/ultralytics/COCO2YOLO repo contains code to convert JSON datasets into YOLO (darknet) format. The code works on Linux, MacOS and Windows.
(看不懂不用理,照着下面做就行)
克隆repo到本地
git clone https://github.com/ultralytics/JSON2YOLO
我这里是克隆下载到E盘,就可以在E盘上找到
再依次执行以下指令:
cd JSON2YOLO
pip install -r requirements.txt
这样子转换工具就安装好了
然后去E盘找到刚刚克隆下载的json2yolo文件打开,复制文件general_json2yolo.py,再新建文件my_json2yolo.py,其中修改代码:
然后用VsCode打开my_json2yolo.py文件,修改一下里面指定的标注路径(往下滑到底)
if source == 'COCO':
convert_coco_json('../mydataset', # directory with *.json
use_segments=True,
cls91to80=False)
再修改第二个地方,
函数
def convert_coco_json(json_dir='../coco/annotations/', use_segments=False, cls91to80=False):
中修改一句(把后面的-1删了)
#cls = coco80[ann['category_id'] - 1] if cls91to80 else ann['category_id'] - 1
# class
cls = coco80[ann['category_id'] - 1] if cls91to80 else ann['category_id'] #
class
大概在第293行代码处可以找到修改并保存。
紧接着打开命令行,指定E:\JSON2YOLO>文件夹下执行以下命令:
python my_json2yolo.py
执行完后的结果
在E:\JSON2YOLO文件夹下就会看到新生成的new_dir文件,里面就是转换好的文件。
注:里面的images文件夹是空的,labels文件夹里面的两个文件夹都是存有数据的。
准备自己的数据集
在D:\ultralytics\ultralytics文件夹下找到mydataset-seg文件夹,把转成的YOLO数据格式的数据复制到以下对应的文件夹。 目录结构如下:
(找到自己的ultralytics文件,没有的自己看我另一个博客有下载教程)博客
D:\ultralytics
└── ultralytics
├── mydataset-seg
├── images ├── train └── val
├── labels |── train └── val
其中:
images/train放所有的训练集图片;images/val放所有的验证集图片;
lables/train放所有的训练集标签;labels/val放所有的验证集标签。标签格式为YOLO格式。
鸟瞰图
修改配置文件
考虑到有人会用到旧版本的ultralytics,这里我给出的是新版本的路径,自己研究一下自己的路径在哪,下面的修改是用新版本的路径教程。
修改文件D:\ultralytics\ultralytics\cfg\datasets\coco8-seg.ymal为myyolo-seg.yaml并打开修改位置和标签。修改内容如下:
修改文件D:/ultralytics/ultralytics/cfg/models/v8/yolov8-seg.yaml
打开文件,原来文件是
nc: 80 # number of classes
改为
nc: 1 # number of classes
开始训练自己的数据集
开始训练的指令:
yolo detect train data=D:\ultralytics\ultralytics\cfg\datasets\myyolo-seg.yaml model=D:\ultralytics\ultralytics\weights\yolov8s-seg.pt epochs=100 imgsz=640 batch=16 workers=4
注意:如果出现显存溢出,可减小batch size
默认训练的次数epoches为100
命令参数说明:https://docs.ultralytics.com/modes/train/#arguments
官方训练指令参考:(不建议小白用下面的指令,还需要自己配路径)
yolo detect train data=coco8.yaml model=yolo11n.pt epochs=100 imgsz=640
训练结果的查看
模型位置查看D:\ultralytics\runs\segment\train\weights目录下的文件
测试训练出的网络模型
测试一张图片:
yolo segment predict model=D:\ultralytics\runs\segment\train2\weights\best.pt data=D:\ultralytics\ultralytics\cfg\datasets\myyolo-seg.yaml source=D:\ultralytics\ultralytics\mydataset-seg\images\val\1.jpg
测试结果:
批量测试图片:
yolo segment predict model=D:\ultralytics\runs\segment\train2\weights\best.pt data=D:\ultralytics\ultralytics\cfg\datasets\myyolo-seg.yaml source=D:\ultralytics\ultralytics\mydataset-seg\images\val
运行结果:
测试视频指令:
yolo segment predict model=D:\ultralytics\runs\segment\train2\weights\best.pt data=D:\ultralytics\ultralytics\cfg\datasets\myyolo-seg.yaml source=视频文件路径
命令参数说明:https://docs.ultralytics.com/modes/predict/
在指令后加上save_txt 可保存分割结果到文本文件
性能统计:
yolo segment val model=D:\ultralytics\runs\segment\train2\weights\best.pt data=D:\ultralytics\ultralytics\cfg\datasets\myyolo-seg.yaml
运行结果:
到此,恭喜你学会了实例分割。
作者:小胡学长