import os
import shutil
from tqdm import tqdm
import argparse
import json
import pycocotools.mask as mask_util
import cv2
import numpy as np
from imantics import Mask
import json
import random
from PIL import Image, ImageDraw, ImagePath
'''
easydata_data标注数据平台默认格式导出下载数据
功能:
1.转成labelme格式json储存在当前目录下labelme文件夹
2.图像处理转成output文件夹;目前是绿草地不变,other,weed和hay完全涂黑,green,ignore标签进行颜色变换(rgb>-r0b)
3.转成yolo训练txt格式,存在txt文件夹;目前只写入了一个grass标签,对应标签0,多标签需要修改代码
4.转成png掩码图,存在txt文件,默认未开启
5.将数据集切分,分别将对应jpg、txt放入test文件夹和train文件夹
'''
def Separate_files_JPG_JSON(data_folder):
datas_folder = data_folder.rsplit('/', 1)[0]
jsons_floder = os.path.join(datas_folder, 'json')
jpgs_floder = os.path.join(datas_folder, 'jpg')
os.makedirs(jsons_floder, exist_ok=True)
os.makedirs(jpgs_floder, exist_ok=True)
files = os.listdir(data_folder)
for file in tqdm(files):
file_path = os.path.join(data_folder, file)
if file.endswith('.json'):
shutil.move(file_path, jsons_floder)
elif file.endswith('.jpg'):
shutil.move(file_path, jpgs_floder)
return jsons_floder, jpgs_floder
# json文件和jpg文件能全部一一对应
def delete_images_with_json(jpg_folder, json_folder):
json_files = os.listdir(json_folder)
jpg_files = os.listdir(jpg_folder)
json_file_names = set(os.path.splitext(file)[0] for file in json_files if file.endswith(".json"))
jpg_file_names = set(os.path.splitext(file)[0] for file in jpg_files if file.endswith(".jpg"))
for jpg_file in tqdm(jpg_files):
if jpg_file.endswith(".jpg"):
json_file_name = os.path.splitext(jpg_file)[0] + ".json"
# 如果不存在对应的 JSON 文件,则删除对应的图片文件
if os.path.splitext(json_file_name)[0] not in json_file_names:
jpg_file_path = os.path.join(jpg_folder, jpg_file)
os.remove(jpg_file_path)
for json_file in tqdm(json_files):
json_path = os.path.join(json_folder, json_file)
if json_file.endswith(".json"):
jpg_file_name = os.path.splitext(json_file)[0] + ".jpg"
# 如果不存在对应的 JPG 文件,则删除对应的图片文件
if os.path.splitext(jpg_file_name)[0] not in jpg_file_names:
json_file_path = os.path.join(json_folder, json_file)
os.remove(json_file_path)
# 如果txt为空文件,删除空文件和对应jpg文件
if os.path.exists(json_path) and os.stat(json_path).st_size == 0:
os.remove(json_path) # 删除空的TXT文件
os.remove(os.path.join(jpg_folder, jpg_file_name)) # 删除对应的JPG文件
def delete_images_with_txt(jpg_folder, txt_folder):
txt_files = os.listdir(txt_folder)
jpg_files = os.listdir(jpg_folder)
txt_file_names = set(os.path.splitext(file)[0] for file in txt_files if file.endswith(".txt"))
jpg_file_names = set(os.path.splitext(file)[0] for file in jpg_files if file.endswith(".jpg"))
for jpg_file in tqdm(jpg_files):
if jpg_file.endswith(".jpg"):
txt_file_name = os.path.splitext(jpg_file)[0] + ".txt"
# 如果不存在对应的 TXT 文件,则删除对应的图片文件
if os.path.splitext(txt_file_name)[0] not in txt_file_names:
jpg_file_path = os.path.join(jpg_folder, jpg_file)
os.remove(jpg_file_path)
for txt_file in tqdm(txt_files):
txt_path = os.path.join(txt_folder, txt_file)
if txt_file.endswith(".txt"):
jpg_file_name = os.path.splitext(txt_file)[0] + ".jpg"
if os.path.splitext(jpg_file_name)[0] not in jpg_file_names:
txt_file_path = os.path.join(txt_folder, txt_file)
os.remove(txt_file_path)
# 如果txt为空文件,删除空文件和对应jpg文件
if os.path.exists(txt_path) and os.stat(txt_path).st_size == 0:
os.remove(txt_path) # 删除空的TXT文件
os.remove(os.path.join(jpg_folder, jpg_file_name)) # 删除对应的JPG文件
def mask2polygons(mask):
output = []
# 得到掩码对应的全部像素点
polygons_list = (Mask(mask).polygons()).points
# 对像素点进行均匀采样生成多边形边界框
for polygons in polygons_list:
saved_length = 15 if len(polygons) > 300 else 10 if len(polygons) > 200 else 5 \
if len(polygons) > 100 else 2 if len(polygons) > 50 else 1
polygons = np.concatenate((polygons[::saved_length], polygons[-1:]))
output.append(polygons.tolist())
return output[0]
def easydata2labelme(img_path, json_path, out_dir, label_name):
"""
:param img_path: 待转换的图片路径
:param json_path: Easydata导出的json文件路径
:param out_dir: 转换后的json文件路径
:return:
"""
if not os.path.exists(img_path):
print(img_path + " is not exists!")
return
if not os.path.exists(json_path):
print(json_path + " is not exists!")
return
if not os.path.exists(out_dir):
os.makedirs(out_dir)
with open(json_path, 'r', encoding='utf8') as fp:
results = json.load(fp)
ori_img = cv2.imread(img_path).astype(np.float32)
height, width = ori_img.shape[:2]
data = {}
# 版本号对应的是环境中安装的labelme的版本
data["version"] = "5.0.1"
data["flags"] = {}
data["shapes"] = []
for item in results['labels']:
if item['name'] == 'weed':
print("this picture {} has weed".format(img_path))
os.remove(img_path)
break
# Draw bbox
if item['name'] == 'grass_normal' or item['name'] == 'grass_shadow' or item['name'] == 'grass' or item['name'] == 'hay' or item['name'] == '0':
# if item['name'] == 'grass_normal' or item['name'] == 'grass_shadow' or item['name'] == 'grass':
label = '0'
elif item['name'] not in label_name:
label = label_name['ignore'] if 'ignore' in label_name else label_name['green']
else:
label = label_name[item['name']] # 所属类别
points = []
shape_type = item['shape']
if shape_type == "brush":
# Draw mask
rle_obj = {"counts": item['mask'],
"size": [height, width]}
# # 多区域边界坐标点转换
mask = mask_util.decode(rle_obj)
mask_np = np.zeros_like(ori_img, dtype=np.uint8)
# if item['name'] == 'grass' or item['name'] == 'grass_normal' or item['name'] == 'grass_shadow':
mask_np[mask > 0] = 255
# 转换为灰度图像
gray_mask = cv2.cvtColor(mask_np, cv2.COLOR_BGR2GRAY)
# cv2.imshow("gray_mask",gray_mask)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# 对掩码应用阈值,获取二值化图像
_, thresh = cv2.threshold(gray_mask, 127, 255, cv2.THRESH_BINARY)
# 连通组件分析
_, labels, stats, _ = cv2.connectedComponentsWithStats(thresh)
# 获取区域数量
num_regions = len(stats) - 1
# 提取每个区域的像素
regions = []
for i in range(1, num_regions + 1):
region = np.zeros_like(mask)
region[labels == i] = 255
regions.append(region)
# 显示每个区域
# for i, region in enumerate(regions):
# cv2.imshow(f"Region {i + 1}", region)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# 对每个区域进行轮廓识别
for region in regions:
# 创建一个空列表来存储多个轮廓列表
contours_list = []
# 找到轮廓
contours, hierarchy = cv2.findContours(region, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 绘制多边形轮廓
# 对每个轮廓进行判断,并存储到轮廓列表中
for contour in contours:
# 计算轮廓的面积
area = cv2.contourArea(contour)
# 判断不是噪点
if area > 100:
# contours_list = np.concatenate(contours_list,contour)
# contour_list = np.squeeze(contour).tolist()
contours_list.extend(contour)
if len(contours_list) != 0:
# res = cv2.drawContours(ori_img_copy, contours_list, -1, (255, 0, 255),10) # 图像,轮廓,轮廓索引(-1,0,),颜色,线条厚度
# cv2.imshow("res", res)
# cv2.waitKey(0)
contour_list = np.squeeze(contours_list).tolist()
points.extend(contours_list)
shapes = {}
shapes["label"] = label
shapes["points"] = contour_list # 使用extend()拼接轮廓的点坐标
shapes["group_id"] = None
shapes["shape_type"] = "polygon"
shapes["flags"] = {}
# 将shape字典添加到data["shapes"]中
data["shapes"].append(shapes)
# # 直接对单区域转换
# points = mask2polygons(mask)
# points = np.array(points, dtype=np.int32)
# # 绘制边界线
# cv2.polylines(ori_img_copy, [points], isClosed=True, color=(255, 0, 0), thickness=2)
# # 显示结果
# cv2.imshow("ori_img_copy", ori_img_copy)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
else:
if shape_type == "polygon":
ori_points = item["meta"]["points"] # 列表嵌套字典
points = []
for idx in ori_points:
ls = []
x = idx["x"] if 0 <= idx["x"] <= width else (0 if idx["x"] < 0 else width)
y = idx["y"] if 0 <= idx["y"] <= height else (0 if idx["y"] < 0 else height)
ls.append(x)
ls.append(y)
points.append(ls)
elif shape_type == "circle":
ori_points = item["meta"]
points = []
radius = ori_points["radius"]
center_x = ori_points["center"]["x"]
center_y = ori_points["center"]["y"]
points.append([center_x, center_y])
points.append([center_x + radius, center_y])
shapes = {}
shapes["label"] = label
shapes["points"] = points
shapes["group_id"] = None
shapes["shape_type"] = shape_type
shapes["flags"] = {}
data["shapes"].append(shapes)
data["imagePath"] = '.' + img_path
data["imageData"] = None
data["imageHeight"] = height
data["imageWidth"] = width
json_name = json_path.split('/')[-1]
out_path = os.path.join(out_dir, json_name)
with open(out_path, 'w') as f:
json.dump(data, f)
def gray2bgr(mask):
return cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
def run(jsons, jpg, png):
# labels 用于生成mask掩码图,所以需要错位去0
labels = {"0": 1,
"1": 2,
"2": 3,
"3": 4,
"4": 5,
"5": 6
}
# read json file
for file in tqdm(os.listdir(jsons)):
with open(os.path.join(jsons, file), 'r') as f:
data = f.read()
# convert str to json objs
data = json.loads(data)
# read image to get shape
image_file = os.path.join(jpg, file.replace(".json", ".jpg"))
image = cv2.imread(image_file)
# create a blank image
blank_image = np.zeros_like(image, dtype=np.uint8)
mask = np.zeros(blank_image.shape[:2], dtype=np.uint8)
for d in data['shapes']:
label = d['label']
if label == '0' :
points = d['points']
# get the points
# points = data["shapes"][0]["points"]
points = np.array(points, dtype=np.int32) # tips: points location must be int32
# color = (labels[label], labels[label], labels[label])
color = (labels[label])
# fill the contour with 255
cv2.fillPoly(mask, [points], color)
# mask+=1
# save the mask
# cv2.imwrite("mask.png", mask)
# cv2.imshow("mask", mask * 80)
# cv2.waitKey(1)
# cv2.imwrite(os.path.join(png, file.replace(".json", ".png")), np.array(mask, dtype=np.uint8) * 80)
cv2.imwrite(os.path.join(png, file.replace(".json", ".png")), np.array(mask*80, dtype=np.uint8))
def json_to_txt(jsons, txt, label_name):
# 定义输入和输出文件路径
input_json_dir = jsons
output_dir = txt
# 遍历输入目录中的所有 JSON 文件
for json_file in tqdm(f for f in os.listdir(input_json_dir) if f.endswith('json')):
# 读取 JSON 文件
with open(os.path.join(input_json_dir, json_file), 'r') as f:
data = json.load(f)
width = data['imageWidth']
height = data['imageHeight']
# 生成输出文件路径
output_file = os.path.join(output_dir, json_file.replace(".json", ".txt"))
# 读取图像尺寸
# image = cv2.imread(os.path.join(input_image_dir, image_file))
# height, width = image.shape[:2]
# 设定一个标识符
grass_label = True
# 根据 YOLO 格式计算标注框坐标并写入输出文件txt,用于训练
with open(output_file, "w") as f:
# 针对测试集,不需要没有grass的数据,需要加入下列代码
# labels_list = [d['label'] for d in data['shapes']]
# if str(label_name.get('grass_normal')) not in labels_list and label == str(label_name.get('grass_shadow')) not in labels_list:
# grass_label = False
for d in data['shapes']:
label = d['label']
points = d['points']
# 根据标签名称获取类别 ID
# label_id = labels.get(label)
# 自己设置标签id,目前训练只训练grass,对应标签0
if label == '0':
label_id = "0"
# else:
# label_id = "1"
if grass_label:
# 将多边形的坐标转换为相对于图像尺寸的比例
coordinates = []
for point in points:
x = point[0] / width
x = 1.0 if x > 0.98 else x
x = 0 if x < 0.02 else x
# if (point[1] < 80):
# point[1] = 0
# else :
# point[1] = point[1] - 80
y = point[1] / height
# y = point[1] / 400
y = 1.0 if y > 0.98 else y
y = 0 if y < 0.02 else y
x = max(0, min(x, 1))
y = max(0, min(y, 1))
coordinates.append((x, y))
# 将标注框的坐标写入输出文件
f.write(f"{label_id} ")
for coord in coordinates:
f.write(f"{coord[0]} {coord[1]} ")
f.write("\n")
# print(f"Processed {json_file}")
# 修改标签区域所有像素的RGB
def polygon_to_pixels(image, points):
result_image = image.copy()
# 使用 ImageDraw 创建可绘制对象
draw = ImageDraw.Draw(result_image)
# 转换多边形边界点的坐标为整数
integer_points = [(int(x), int(y)) for x, y in points]
# 绘制多边形区域并填充颜色
draw.polygon(integer_points, outline=(255, 255, 255), fill=(255, 255, 255))
# 获取图像的像素访问对象
result_pixels = result_image.load()
original_pixels = image.load()
# 对多边形区域内的每个像素点执行 RGB -> BGR 变换
for x in range(image.width):
for y in range(image.height):
# 如果像素点在多边形区域内
if result_pixels[x, y] == (255, 255, 255):
# 获取像素点的 RGB 值
r, g, b = original_pixels[x, y]
# 更新像素点的颜色
original_pixels[x, y] = (b, 0, r)
# 返回图像对象
return image
# 覆盖标签区域所有像素的RGB
def polygon_to_cover(image, image_copy, points):
result_image = image.copy()
# 使用 ImageDraw 创建可绘制对象
draw = ImageDraw.Draw(result_image)
# 转换多边形边界点的坐标为整数
integer_points = [(int(x), int(y)) for x, y in points]
# 绘制多边形区域并填充颜色
draw.polygon(integer_points, outline=(255, 255, 255), fill=(255, 255, 255))
# 获取图像的像素访问对象
result_pixels = result_image.load()
original_pixels = image_copy.load()
real_original_pixels = image.load()
# 对多边形区域内的每个像素点执行 RGB -> BGR 变换
for x in range(image.width):
for y in range(image.height):
# 如果像素点在多边形区域内
if result_pixels[x, y] == (255, 255, 255):
# 获取像素点的 RGB 值
r, g, b = original_pixels[x, y]
# 更新像素点的颜色
# real_original_pixels[x, y] = (r, g, b)
real_original_pixels[x, y] = (0, g, b)
return image
def change_image(jsons, jpg, jpg_output, label_name):
# read json file
for file in tqdm(os.listdir(jsons)):
if not file.endswith(".json"):
continue
# read image to get shape
image_name = file.replace(".json", ".jpg")
image_file = os.path.join(jpg, image_name)
if not os.path.exists(image_file):
continue
# image = cv2.imread(image_file)
try:
# image = Image.open(image_file)
# draw = ImageDraw.Draw(image)
image = cv2.imread(image_file)
mask = np.zeros_like(image)
with open(os.path.join(jsons, file), 'r') as f:
data = f.read()
data = json.loads(data)
for d in data['shapes']:
label = d['label']
points = d['points']
# points = np.array(points, dtype=np.int32) # tips: points location must be int32
# 对不同的标签进行不同的颜色变换
# 检查grass标注
if label == '0':
points = np.array(points, dtype=np.int32)
cv2.fillPoly(mask,[points],color=(255,255,255))
# cv2.drawContours(mask, [points], -1, (255, 255, 255), thickness=cv2.FILLED)
# 将标注信息绘制在结果图像上
result = cv2.addWeighted(image, 0.5, mask, 0.5, 0)
cv2.putText(result, label, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.imwrite(os.path.join(jpg_output, image_name), result)
# if label == str(label_name.get('hay_normal')) or label == str(
# label_name.get('hay_shadow')) or label == str(label_name.get('hay')):
# # 创建填充颜色
# path = tuple(map(tuple, points))
# fill_color = (117, 117, 117)
# # fill_color = (0, 0, 255) # 在这里设置你想要填充的颜色
# # 绘制多边形区域并填充颜色
# draw.polygon(path, fill=fill_color)
# elif label == str(label_name.get('other')) or label == str(label_name.get('weed')):
# # 创建填充颜色
# path = tuple(map(tuple, points))
# fill_color = (117, 117, 117) # 在这里设置你想要填充的颜色
# # 绘制多边形区域并填充颜色
# draw.polygon(path, fill=fill_color)
# elif label == str(label_name.get('green')) or label == str(
# label_name.get('shrubs')) or label == str(label_name.get('ignore')):
# # 对多边形区域内的所有像素点进行 RGB 变换
# # polygon_to_pixels(image, points)
# # pass
# # 创建填充颜色
# path = tuple(map(tuple, points))
# fill_color = (0, 0, 0) # 在这里设置你想要填充的颜色
# # 绘制多边形区域并填充颜色
# draw.polygon(path, fill=fill_color)
# 保存处理后的图片
# 覆盖草地区域
# for d in data['shapes']:
# label = d['label']
# points = d['points']
# # points_np = np.array([points], dtype=np.int32)
# if label == '0':
# polygon_to_cover(image, image_copy, points)
# image.save(os.path.join(jpg_output, image_name), quality=100)
except:
print("{} has error".format(image_file))
else:
continue
def split_jpg(source_folder, train_jpg, test_jpg, split_ratio=0.9):
# 创建目标文件夹
os.makedirs(train_jpg, exist_ok=True)
os.makedirs(test_jpg, exist_ok=True)
# 获取源文件夹中所有文件名
file_list = [f for f in os.listdir(source_folder) if f.endswith('jpg')]
# 打乱文件列表的顺序
random.shuffle(file_list)
# 计算切分索引
split_index = int(len(file_list) * split_ratio)
# 将文件切分为训练集和测试集
train_files = file_list[:split_index]
test_files = file_list[split_index:]
# 将文件复制到对应的目标文件夹
for file in tqdm(train_files):
source_path = os.path.join(source_folder, file)
train_path = os.path.join(train_jpg, file)
shutil.copyfile(source_path, train_path)
for file in tqdm(test_files):
source_path = os.path.join(source_folder, file)
test_path = os.path.join(test_jpg, file)
shutil.copyfile(source_path, test_path)
# 返回分割后的训练集和测试集文件列表
train_list = os.listdir(train_jpg)
test_list = os.listdir(test_jpg)
return train_list, test_list
def copy_txt(train_txt, test_txt, train_jpg, test_jpg, txt_folder):
os.makedirs(train_txt, exist_ok=True)
os.makedirs(test_txt, exist_ok=True)
train_list = os.listdir(train_jpg)
test_list = os.listdir(test_jpg)
train_names = [os.path.splitext(f)[0] for f in train_list]
test_names = [os.path.splitext(f)[0] for f in test_list]
for train_name in tqdm(train_names):
txt_train_name = train_name + ".txt"
shutil.copy(os.path.join(txt_folder, txt_train_name), train_txt)
for test_name in tqdm(test_names):
txt_test_name = test_name + ".txt"
shutil.copy(os.path.join(txt_folder, txt_test_name), test_txt)
def main():
# 参数设置
# 设置标签
# z数据标签
label_name = {
'grass': '0',
'ignore': '1',
'shrubs': '2',
'weed': '3',
'hay': '4'
}
# c和e数据集标签
# label_name = {
# 'grass_normal': '0',
# 'grass_shadow': '1',
# 'hay_normal': '2',
# 'hay_shadow': '3',
# 'green': '4',
# 'other': '5'
# }
# # json和jpg文件在同一个目录下
# data_folder = '/mnt/Data1/xiebohua/xbh_picture/yolov8-seg_clean/cleanned/newc_data/data2/2023256_1708228146'
# # 将json和jpg文件分开
# if os.path.exists(data_folder):
# files = os.listdir(data_folder)
# if any(file.endswith('.json') for file in files) and any(file.endswith('.jpg') for file in files):
# json_folder, jpg_folder = Separate_files_JPG_JSON(data_folder)
# else:
# print('data_folder error')
# json和jpg文件在不同目录下
jpg_folder = '/home/lxy/Desktop/test/2024.3.15/easydata_jpg'
json_folder = '/home/lxy/Desktop/test/2024.3.15/easydata_json'
# 数据切分比例
split_ratio = 0.8
# 执行数据处理脚本
# 使JPG文件和JSON文件一一对应,删除没有对应JPG或JSON数据,方便后续处理
# delete_images_with_json(jpg_folder, json_folder)
# # easydata数据json文件转labelmejson格式文件,for循环拼接路径
# labelme_json_folder = jpg_folder.rsplit('/', 1)[0] + '/labelme_json'
labelme_json_folder = '/home/lxy/Desktop/test/2024.3.15/labelme/labelme_json'
os.makedirs(labelme_json_folder, exist_ok=True)
for path in tqdm(os.listdir(jpg_folder)):
if path.split('.')[-1] == 'json':
continue
# img_path = os.path.join(easydata_dir, path)
img_path = os.path.join(jpg_folder, path)
# json_path = easydata_dir + '/' + path.split('.')[0] + '.json'
json_path = json_folder + '/' + path.split('.')[0] + '.json'
try:
easydata2labelme(img_path, json_path, labelme_json_folder, label_name)
except ValueError as e:
# 处理解码错误
print("{}解码错误{}:".format(img_path, e))
else:
# 继续执行其他操作
continue
# labelmejson文件转mask,txt,对图像做变化处理
# png_dir = json_folder.rsplit('/',1)[0] + '/png'
png_dir = '/home/lxy/Desktop/test/2024.3.15/labelme/labelme_png'
os.makedirs(png_dir,exist_ok=True)
run(labelme_json_folder,jpg_folder,png_dir)
print('make png finish')
# txt_dir = json_folder.rsplit('/', 1)[0] + '/txt'
# txt_dir = '/home/lxy/Desktop/test/2024.3.15/labelme/labelme_txt'
# os.makedirs(txt_dir, exist_ok=True)
# json_to_txt(labelme_json_folder, txt_dir, label_name)
# print('make txt finish')
# output_dir = json_folder.rsplit('/', 1)[0] + '/output'
output_dir = '/home/lxy/Desktop/test/2024.3.15/labelme/labelme_data'
os.makedirs(output_dir, exist_ok=True)
change_image(labelme_json_folder, jpg_folder, output_dir, label_name)
print('change_jpg finish')
# 由于json可能出现解码错误,所以txt文件和jpg文件需要重新对一次
# delete_images_with_txt(jpg_folder, txt_dir)
# # 将数据分成训练集和数据集
# # train_jpg_dir = jpg_folder.rsplit('/', 1)[0] + '/images' + '/train'
# # test_jpg_dir = jpg_folder.rsplit('/', 1)[0] + '/images' + '/val'
# train_jpg_dir = jpg_folder.rsplit('/', 1)[0] + '/images' + '/train'
# test_jpg_dir = jpg_folder.rsplit('/', 1)[0] + '/images' + '/val'
# os.makedirs(train_jpg_dir, exist_ok=True)
# os.makedirs(test_jpg_dir, exist_ok=True)
# split_jpg(jpg_folder, train_jpg_dir, test_jpg_dir, split_ratio)
# # 将对应txt复制到labels文件夹
# # train_txt_dir = jpg_folder.rsplit('/', 1)[0] + '/labels' + '/train'
# # test_txt_dir = jpg_folder.rsplit('/', 1)[0] + '/labels' + '/val'
# train_txt_dir = jpg_folder.rsplit('/', 1)[0] + '/labels' + '/train'
# test_txt_dir = jpg_folder.rsplit('/', 1)[0] + '/labels' + '/val'
# os.makedirs(train_txt_dir, exist_ok=True)
# os.makedirs(test_txt_dir, exist_ok=True)
# copy_txt(train_txt_dir, test_txt_dir, train_jpg_dir, test_jpg_dir, txt_dir)
if __name__ == "__main__":
main()