当前位置:   article > 正文

YOLOv8 segment介绍_yolov8分割数据集格式

yolov8分割数据集格式

      1.YOLOv8图像分割支持的数据格式:

      (1).用于训练YOLOv8分割模型的数据集标签格式如下:

      1).每幅图像对应一个文本文件:数据集中的每幅图像都有一个与图像文件同名的对应文本文件,扩展名为".txt";

      2).文本文件中每个目标(object)占一行:文本文件中的每一行对应图像中的一个目标实例;

      3).每行目标信息:如下所示:之间用空格分隔

      A.目标类别索引:整数,例如:0代表person,1代表car,等等;

      B.目标边界坐标:mask区域周围的边界坐标,归一化为[0, 1];

<class-index> <x1> <y1> <x2> <y2> ... <xn> <yn>

      :每行的长度不必相等;每个分隔label必须至少有3对xy点

      (2).数据集YAML格式:Ultralytics框架使用YAML文件格式来定义用于训练分隔模型的数据集和模型配置,如下面测试数据集melon中melon_seg.yaml内容如下: 在网上下载了60多幅包含西瓜和冬瓜的图像组成melon数据集

  1. path: ../datasets/melon_seg # dataset root dir
  2. train: images/train # train images (relative to 'path')
  3. val: images/val # val images (relative to 'path')
  4. test: # test images (optional)
  5. # Classes
  6. names:
  7. 0: watermelon
  8. 1: wintermelon

      2.使用半自动标注工具 EISeg 对数据集melon进行标注:

      (1).从 PaddleSeg 中下载"通用场景的图像标注"高精度模型static_hrnet18_ocr64_cocolvis.zip;

      (2).标注前先按照下面操作设置好:

      1).选中JSON保存,取消COCO保存;

      2).选中自动保存;

      3).取消灰度保存.

      3.编写Python脚本将EISeg生成的json文件转换成YOLOv8 segment支持的txt文件:

  1. import os
  2. import json
  3. import argparse
  4. import colorama
  5. import random
  6. import shutil
  7. import cv2
  8. # supported image formats
  9. img_formats = (".bmp", ".jpeg", ".jpg", ".png", ".webp")
  10. def parse_args():
  11. parser = argparse.ArgumentParser(description="json(EISeg) to txt(YOLOv8)")
  12. parser.add_argument("--dir", required=True, type=str, help="images directory, all json files are in the label directory, and generated txt files are also in the label directory")
  13. parser.add_argument("--labels", required=True, type=str, help="txt file that hold indexes and labels, one label per line, for example: face 0")
  14. parser.add_argument("--val_size", default=0.2, type=float, help="the proportion of the validation set to the overall dataset:[0., 0.5]")
  15. parser.add_argument("--name", required=True, type=str, help="the name of the dataset")
  16. args = parser.parse_args()
  17. return args
  18. def get_labels_index(name):
  19. labels = {} # key,value
  20. with open(name, "r") as file:
  21. for line in file:
  22. # print("line:", line)
  23. key_value = []
  24. for v in line.split(" "):
  25. # print("v:", v)
  26. key_value.append(v.replace("\n", "")) # remove line breaks(\n) at the end of the line
  27. if len(key_value) != 2:
  28. print(colorama.Fore.RED + "Error: each line should have only two values(key value):", len(key_value))
  29. continue
  30. labels[key_value[0]] = key_value[1]
  31. with open(name, "r") as file:
  32. line_num = len(file.readlines())
  33. if line_num != len(labels):
  34. print(colorama.Fore.RED + "Error: there may be duplicate lables:", line_num, len(labels))
  35. return labels
  36. def get_json_files(dir):
  37. jsons = []
  38. for x in os.listdir(dir+"/label"):
  39. if x.endswith(".json"):
  40. jsons.append(x)
  41. return jsons
  42. def parse_json(name_json, name_image):
  43. img = cv2.imread(name_image)
  44. if img is None:
  45. print(colorama.Fore.RED + "Error: unable to load image:", name_image)
  46. raise
  47. height, width = img.shape[:2]
  48. with open(name_json, "r") as file:
  49. data = json.load(file)
  50. objects=[]
  51. for i in range(0, len(data)):
  52. object = []
  53. object.append(data[i]["name"])
  54. object.append(data[i]["points"])
  55. objects.append(object)
  56. return width, height, objects
  57. def write_to_txt(name_json, width, height, objects, labels):
  58. name_txt = name_json[:-len(".json")] + ".txt"
  59. # print("name txt:", name_txt)
  60. with open(name_txt, "w") as file:
  61. for obj in objects: # 0: name; 1: points
  62. if len(obj[1]) < 3:
  63. print(colorama.Fore.RED + "Error: must be at least 3 pairs:", len(obj[1]), name_json)
  64. raise
  65. if obj[0] not in labels:
  66. print(colorama.Fore.RED + "Error: unsupported label:", obj[0], labels)
  67. raise
  68. string = ""
  69. for pt in obj[1]:
  70. string = string + " " + str(round(pt[0] / width, 6)) + " " + str(round(pt[1] / height, 6))
  71. string = labels[obj[0]] + string + "\r"
  72. file.write(string)
  73. def json_to_txt(dir, jsons, labels):
  74. for json in jsons:
  75. name_json = dir + "/label/" + json
  76. name_image = ""
  77. for format in img_formats:
  78. file = dir + "/" + json[:-len(".json")] + format
  79. if os.path.isfile(file):
  80. name_image = file
  81. break
  82. if not name_image:
  83. print(colorama.Fore.RED + "Error: required image does not exist:", json[:-len(".json")])
  84. raise
  85. # print("name image:", name_image)
  86. width, height, objects = parse_json(name_json, name_image)
  87. # print(f"width: {width}; height: {height}; objects: {objects}")
  88. write_to_txt(name_json, width, height, objects, labels)
  89. def get_random_sequence(length, val_size):
  90. numbers = list(range(0, length))
  91. val_sequence = random.sample(numbers, int(length*val_size))
  92. # print("val_sequence:", val_sequence)
  93. train_sequence = [x for x in numbers if x not in val_sequence]
  94. # print("train_sequence:", train_sequence)
  95. return train_sequence, val_sequence
  96. def get_files_number(dir):
  97. count = 0
  98. for file in os.listdir(dir):
  99. if os.path.isfile(os.path.join(dir, file)):
  100. count += 1
  101. return count
  102. def split_train_val(dir, jsons, name, val_size):
  103. if val_size > 0.5 or val_size < 0.01:
  104. print(colorama.Fore.RED + "Error: the interval for val_size should be:[0.01, 0.5]:", val_size)
  105. raise
  106. dst_dir_images_train = "datasets/" + name + "/images/train"
  107. dst_dir_images_val = "datasets/" + name + "/images/val"
  108. dst_dir_labels_train = "datasets/" + name + "/labels/train"
  109. dst_dir_labels_val = "datasets/" + name + "/labels/val"
  110. try:
  111. os.makedirs(dst_dir_images_train) #, exist_ok=True
  112. os.makedirs(dst_dir_images_val)
  113. os.makedirs(dst_dir_labels_train)
  114. os.makedirs(dst_dir_labels_val)
  115. except OSError as e:
  116. print(colorama.Fore.RED + "Error: cannot create directory:", e.strerror)
  117. raise
  118. # print("jsons:", jsons)
  119. train_sequence, val_sequence = get_random_sequence(len(jsons), val_size)
  120. for index in train_sequence:
  121. for format in img_formats:
  122. file = dir + "/" + jsons[index][:-len(".json")] + format
  123. # print("file:", file)
  124. if os.path.isfile(file):
  125. shutil.copy(file, dst_dir_images_train)
  126. break
  127. file = dir + "/label/" + jsons[index][:-len(".json")] + ".txt"
  128. if os.path.isfile(file):
  129. shutil.copy(file, dst_dir_labels_train)
  130. for index in val_sequence:
  131. for format in img_formats:
  132. file = dir + "/" + jsons[index][:-len(".json")] + format
  133. if os.path.isfile(file):
  134. shutil.copy(file, dst_dir_images_val)
  135. break
  136. file = dir + "/label/" + jsons[index][:-len(".json")] + ".txt"
  137. if os.path.isfile(file):
  138. shutil.copy(file, dst_dir_labels_val)
  139. num_images_train = get_files_number(dst_dir_images_train)
  140. num_images_val = get_files_number(dst_dir_images_val)
  141. num_labels_train = get_files_number(dst_dir_labels_train)
  142. num_labels_val = get_files_number(dst_dir_labels_val)
  143. if num_images_train + num_images_val != len(jsons) or num_labels_train + num_labels_val != len(jsons):
  144. print(colorama.Fore.RED + "Error: the number of files is inconsistent:", num_images_train, num_images_val, num_labels_train, num_labels_val, len(jsons))
  145. raise
  146. def generate_yaml_file(labels, name):
  147. path = os.path.join("datasets", name, name+".yaml")
  148. # print("path:", path)
  149. with open(path, "w") as file:
  150. file.write("path: ../datasets/%s # dataset root dir\n" % name)
  151. file.write("train: images/train # train images (relative to 'path')\n")
  152. file.write("val: images/val # val images (relative to 'path')\n")
  153. file.write("test: # test images (optional)\n\n")
  154. file.write("# Classes\n")
  155. file.write("names:\n")
  156. for key, value in labels.items():
  157. # print(f"key: {key}; value: {value}")
  158. file.write(" %d: %s\n" % (int(value), key))
  159. if __name__ == "__main__":
  160. colorama.init()
  161. args = parse_args()
  162. # 1. parse JSON file and write it to a TXT file
  163. labels = get_labels_index(args.labels)
  164. # print("labels:", labels)
  165. jsons = get_json_files(args.dir)
  166. # print(f"jsons: {jsons}; number: {len(jsons)}")
  167. json_to_txt(args.dir, jsons, labels)
  168. # 2. split the dataset
  169. split_train_val(args.dir, jsons, args.name, args.val_size)
  170. # 3. generate a YAML file
  171. generate_yaml_file(labels, args.name)
  172. print(colorama.Fore.GREEN + "====== execution completed ======")

      以上脚本包含3个功能:

      1).将json文件转换成txt文件;

      2).将数据集随机拆分成训练集和测试集;

      3).产生需要的yaml文件

      4.编写Python脚本进行train:

  1. import argparse
  2. import colorama
  3. from ultralytics import YOLO
  4. def parse_args():
  5. parser = argparse.ArgumentParser(description="YOLOv8 train")
  6. parser.add_argument("--yaml", required=True, type=str, help="yaml file")
  7. parser.add_argument("--epochs", required=True, type=int, help="number of training")
  8. parser.add_argument("--task", required=True, type=str, choices=["detect", "segment"], help="specify what kind of task")
  9. args = parser.parse_args()
  10. return args
  11. def train(task, yaml, epochs):
  12. if task == "detect":
  13. model = YOLO("yolov8n.pt") # load a pretrained model
  14. elif task == "segment":
  15. model = YOLO("yolov8n-seg.pt") # load a pretrained model
  16. else:
  17. print(colorama.Fore.RED + "Error: unsupported task:", task)
  18. raise
  19. results = model.train(data=yaml, epochs=epochs, imgsz=640) # train the model
  20. metrics = model.val() # It'll automatically evaluate the data you trained, no arguments needed, dataset and settings remembered
  21. model.export(format="onnx") #, dynamic=True) # export the model, cannot specify dynamic=True, opencv does not support
  22. # model.export(format="onnx", opset=12, simplify=True, dynamic=False, imgsz=640)
  23. model.export(format="torchscript") # libtorch
  24. if __name__ == "__main__":
  25. colorama.init()
  26. args = parse_args()
  27. train(args.task, args.yaml, args.epochs)
  28. print(colorama.Fore.GREEN + "====== execution completed ======")

      执行结果如下图所示:会生成best.pt、best.onnx、best.torchscript

      5.生成的best.onnx使用Netron进行可视化,结果如下图所示:

      说明

      1).输入:images: float32[1,3,640,640] :与YOLOv8 detect一致,大小为3通道640*640

      2).输出:包括2层,output0和output1

      A.output0: float32[1,38,8400] :

      a.8400:模型预测的所有box的数量,与YOLOv8 detect一致;

      b.38: 每个框给出38个值:4:xc, yc, width, height;2:class, confidences;32:mask weights

      B.output1: float32[1,32,160,160] :最终mask大小是160*160;output1中的masks实际上只是原型masks,并不代表最终masks。为了得到某个box的最终mask,你可以将每个mask与其对应的mask weight相乘,然后将所有这些乘积相加。此外,你可以在box上应用NMS,以获得具有特定置信度阈值的box子集

      6.编写Python脚本实现predict:

  1. import colorama
  2. import argparse
  3. from ultralytics import YOLO
  4. import os
  5. def parse_args():
  6. parser = argparse.ArgumentParser(description="YOLOv8 predict")
  7. parser.add_argument("--model", required=True, type=str, help="model file")
  8. parser.add_argument("--dir_images", required=True, type=str, help="directory of test images")
  9. parser.add_argument("--dir_result", required=True, type=str, help="directory where the image results are saved")
  10. args = parser.parse_args()
  11. return args
  12. def get_images(dir):
  13. # supported image formats
  14. img_formats = (".bmp", ".jpeg", ".jpg", ".png", ".webp")
  15. images = []
  16. for file in os.listdir(dir):
  17. if os.path.isfile(os.path.join(dir, file)):
  18. # print(file)
  19. _, extension = os.path.splitext(file)
  20. for format in img_formats:
  21. if format == extension.lower():
  22. images.append(file)
  23. break
  24. return images
  25. def predict(model, dir_images, dir_result):
  26. model = YOLO(model) # load an model
  27. model.info() # display model information
  28. images = get_images(dir_images)
  29. # print("images:", images)
  30. os.makedirs(dir_result) #, exist_ok=True)
  31. for image in images:
  32. results = model.predict(dir_images+"/"+image)
  33. for result in results:
  34. # print(result)
  35. result.save(dir_result+"/"+image)
  36. if __name__ == "__main__":
  37. colorama.init()
  38. args = parse_args()
  39. predict(args.model, args.dir_images, args.dir_result)
  40. print(colorama.Fore.GREEN + "====== execution completed ======")

      执行结果如下图所示:

      其中一幅图像的分割结果如下图所示:以下是epochs设置为100时生成的best.pt的结果

      GitHubhttps://github.com/fengbingchun/NN_Test

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/979859
推荐阅读
相关标签
  

闽ICP备14008679号