说明:工作中,有时需要处理一批已经标注好的yolo格式的数据集,例如图片裁剪了,相应的标签应该得与裁剪后的图片呼应上,就是框的坐标应同裁剪图像一样作出相应的处理,使得处理后的标签文件里的框坐标能对应上裁剪后的图。
代码如下:
import os #导入os模块,用于操作文件和文件夹
import cv2 #导入OpenCV库,用于图像处理。
def convert_coordinates(x, y, w, h, img_width, img_height): #定义一个函数,用于将相对坐标转换为绝对坐标。
# 将yolo格式的坐标转换为像素坐标
left = int((x - w / 2) * img_width)
top = int((y - h / 2) * img_height)
right = int((x + w / 2) * img_width)
bottom = int((y + h / 2) * img_height)
print("left,top,right,bottom:", left,top,right,bottom)
return left, top, right, bottom
def crop_image(image_path, label_path, output_folder): #定义一个函数,用于裁剪图像并调整标签坐标。
# 读取图片
image = cv2.imread(image_path) #读取图像文件。
img_height, img_width, _ = image.shape # 获取图像的高度和宽度。
print("yuantu:",image.shape)
#裁剪图像,将图像高度从y1到y2,宽度从x1到x2的区域提取出来。根据你要裁的坐标改x1,y1,x2,y2的值
x1 = 300 #左上角坐标(x1,y1)
y1 = 0
x2 = 1600 #右下角坐标(x2,y2)
y2 = 1080
cropped_image = image[y1:y2, x1:x2] # 对读取的原始图片裁剪
print("caihou:",cropped_image.shape)
# 保存裁剪后的图片
image_name = os.path.basename(image_path) #获取图像文件名。
output_path = os.path.join(output_folder, image_name) #构建输出图像路径。
cv2.imwrite(output_path, cropped_image) #将裁剪后的图像保存到输出路径。
# 读取对应的标签文件
label_name = os.path.splitext(image_name)[0] + ".txt" #构建标签文件名。
label_file = open(os.path.join(label_path, label_name), "r") #打开标签文件。
# 转换标签坐标并保存到新的标签文件中
new_label_path = os.path.join(output_folder, "new_labels_txt") #构建新标签文件夹路径。
os.makedirs(new_label_path, exist_ok=True) #创建新标签文件夹。
new_label_file = open(os.path.join(new_label_path, label_name), "w") #创建新标签文件。
for line in label_file: #遍历标签文件中的每一行。
class_id, x, y, w, h = map(float, line.strip().split()) #解析每一行的标签信息。
left, top, right, bottom = convert_coordinates(x, y, w, h, img_width, img_height) #将相对坐标转换为绝对坐标。
if left >= x1 and right <= x2: #判断目标框是否在裁剪区域内。
# 转换裁剪后的坐标
left -= x1 #调整目标框的左坐标。
right -= x1 #调整目标框的右坐标。
new_x = format((left + (right - left) / 2) / (x2 - x1), '6f') #计算调整后的目标框中心点的x坐标。
new_y = format((top + (bottom - top) / 2) / (y2 - y1), '6f') #计算调整后的目标框中心点的y坐标。
new_w = format((right - left) / (x2 - x1), '6f') #计算调整后的目标框的宽度。
new_h = format((bottom - top) / (y2 - y1), '6f') #计算调整后的目标框的高度。
# 保存新的标签坐标
new_label_file.write(f"{int(class_id)} {new_x} {new_y} {new_w} {new_h}\n") #写入调整后的标签信息到新标签文件。
print("new_x,new_y,new_w,new_h:",new_x,new_y,new_w,new_h)
label_file.close() #关闭标签文件。
new_label_file.close() #关闭新标签文件。
if __name__ == "__main__":
image_folder = "E:/images" #图像文件夹路径。
label_folder = "E:/labels" #标签文件夹路径。
output_folder = "E:/caihou" #输出文件夹路径。
# 获取所有图片文件路径
image_files = [f for f in os.listdir(image_folder) if f.endswith(".jpg")] #获取图像文件夹中所有以".jpg"结尾的文件。
# 对每张图片进行裁剪和标签转换
for image_file in image_files: #遍历图像文件列表。
image_path = os.path.join(image_folder, image_file) #构建图像文件路径。
crop_image(image_path, label_folder, output_folder) #调用裁剪图像函数,对图像进行裁剪和标签调整。
最后用labelimg检查裁后的图和对应的标签框。