44import argparse
55import shutil
66from pathlib import Path
7- from typing import Tuple , Union
7+ from typing import List , Tuple , Union
88
9+ import yaml
910from tqdm import tqdm
1011
1112ValueType = Union [str , Path , None ]
1213
1314
1415class YOLOV8ToYOLOV5 :
15- def __init__ (self , data_dir : ValueType = None , save_dir : ValueType = None ):
16+ def __init__ (
17+ self ,
18+ data_dir : ValueType = None ,
19+ save_dir : ValueType = None ,
20+ yaml_path : ValueType = None ,
21+ ):
1622 if data_dir is None :
1723 raise ValueError ("data_dir must not be None" )
1824 self .data_dir = Path (data_dir )
@@ -25,10 +31,12 @@ def __init__(self, data_dir: ValueType = None, save_dir: ValueType = None):
2531 self .verify_exists (self .label_dir )
2632
2733 if save_dir is None :
28- save_dir = self .data_dir .parent / f"{ Path (self .data_dir ).name } _yolov8 "
34+ save_dir = self .data_dir .parent / f"{ Path (self .data_dir ).name } _yolov5 "
2935 self .save_dir = save_dir
3036 self .mkdir (self .save_dir )
3137
38+ self .yaml_path = yaml_path
39+
3240 self .save_img_dir = save_dir / "images"
3341 self .mkdir (self .save_img_dir )
3442
@@ -40,24 +48,29 @@ def __call__(self, mode_list: Tuple[str] = ("train", "val")):
4048 raise ValueError ("mode_list is empty!!" )
4149
4250 for mode in tqdm (mode_list ):
43- txt_path = self .data_dir / f"{ mode } .txt"
44- self .verify_exists (txt_path )
45- img_list = self .read_txt (txt_path )
46-
47- save_mode_img_dir = self .save_img_dir / mode
48- self .mkdir (save_mode_img_dir )
49-
50- save_mode_label_dir = self .save_label_dir / mode
51- self .mkdir (save_mode_label_dir )
51+ img_dir = self .img_dir / mode
52+ img_list = list (img_dir .iterdir ())
5253
54+ img_relative_list = []
5355 # copy images to new img dir
5456 for img_path in img_list :
55- img_full_path = self .data_dir / img_path
56- shutil .copy (img_full_path , save_mode_img_dir )
57+ shutil .copy (img_path , self .save_img_dir )
5758
58- label_path = self .label_dir / Path ( img_path ) .with_suffix (".txt" ).name
59- shutil .copy (label_path , save_mode_label_dir )
59+ label_path = self .label_dir / mode / img_path .with_suffix (".txt" ).name
60+ shutil .copy (label_path , self . save_label_dir )
6061
62+ new_img_path = Path ("images" ) / img_path .name
63+ img_relative_list .append (new_img_path )
64+
65+ txt_path = self .save_dir / f"{ mode } .txt"
66+ self .write_txt (txt_path , img_relative_list )
67+
68+ class_txt_path = self .save_dir / "classes.txt"
69+ class_content = ""
70+ if self .yaml_path is not None :
71+ yaml_data = self .read_yaml (self .yaml_path )
72+ class_content = list (yaml_data ["names" ].values ())
73+ self .write_txt (class_txt_path , class_content )
6174 print (f"Successfully convert, detail in { self .save_dir } " )
6275
6376 @staticmethod
@@ -75,6 +88,24 @@ def verify_exists(file_path: Union[Path, str]):
7588 if not Path (file_path ).exists ():
7689 raise FileNotFoundError (f"The { file_path } is not exists!!!" )
7790
91+ @staticmethod
92+ def write_txt (save_path : str , content : List [str ], mode = "w" ) -> None :
93+ if not isinstance (save_path , str ):
94+ save_path = str (save_path )
95+
96+ if isinstance (content , str ):
97+ content = [content ]
98+
99+ with open (save_path , mode , encoding = "utf-8" ) as f :
100+ for value in content :
101+ f .write (f"{ value } \n " )
102+
103+ @staticmethod
104+ def read_yaml (yaml_path ):
105+ with open (yaml_path , "rb" ) as f :
106+ data = yaml .load (f , Loader = yaml .Loader )
107+ return data
108+
78109
79110def main ():
80111 parser = argparse .ArgumentParser ("Datasets converter from YOLOV5 to COCO" )
@@ -91,7 +122,7 @@ def main():
91122 parser .add_argument ("--yaml_path" , type = str , default = None )
92123 args = parser .parse_args ()
93124
94- converter = YOLOV8ToYOLOV5 (args .data_dir , args .save_dir )
125+ converter = YOLOV8ToYOLOV5 (args .data_dir , args .save_dir , args . yaml_path )
95126 converter (mode_list = args .mode_list .split ("," ))
96127
97128
0 commit comments