YOLO数据集制作

1、视频提取图片

#! /usr/bin/python
# -*- coding:utf-8 -*-
import cv2
import os
import numpy as np
import random 
import shutil


def video_2_images(video_path, save_iamge_path):
    count = 0
    for v_path in video_path:
        print('is dealing {}'.format(v_path))
        video = cv2.VideoCapture(v_path)
        while video.isOpened():
            ret, frame = video.read()
            if not ret:
                break
            cv2.imwrite(os.path.join(save_iamge_path, str(count)+'.jpg'), frame)
            count += 1
        video.release()

def write_2_txt(txt_path, label_data_list):
    '''
    label_data_list : 列表, 元素是 str, 每个str是“cls x y w h” xywh是除以图像宽高之后的数值
    '''
    with open(txt_path, 'a') as f:
        f.writelines(label_data_list)
 
           
def use_cv2_label_image(images_path, save_label_path):
    all_images_name = os.listdir(images_path)
    for image_name in all_images_name:
        print('doing {}'.format(image_name))
        img_path = os.path.join(images_path, image_name)
        save_txt_path = os.path.join(save_label_path, image_name.split('.')[0] + '.txt')

        img = cv2.imread(img_path, 0)
        _, img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)  
        kernel = np.ones((5,5), np.uint8)
        img = cv2.dilate(img, kernel, iterations = 1)
        # img = cv2.erode(img, kernel, iterations = 1)
        
        
        contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        areas = []
        select_contours = []
        for c in contours:
            area = cv2.contourArea(c)
            if area > 3000 and area < 4500:
                areas.append(area)
                select_contours.append(c)
        if select_contours == []:
            continue
        else:
            left_up_x, left_up_y = 0., 0.
            right_down_x, right_down_y = 0., 0.
            w, h = 0., 0.
            img_w = img.shape[1]
            img_h = img.shape[0]
            label_rect = []
            
            # draw_img = np.zeros(img.shape, np.uint8)
            for c in select_contours:
                c = np.squeeze(c)
                left_up_x = np.min(c, axis=0)[0]
                left_up_y = np.min(c, axis=0)[1]
                right_down_x = np.max(c, axis=0)[0]
                right_down_y = np.max(c, axis=0)[1]
                w = right_down_x - left_up_x
                h = right_down_y - left_up_y
                label_rect.append('0 '+ str(round((left_up_x + right_down_x)/(2*img_w), 6)) + ' '+ \
                    str(round((left_up_y + right_down_y)/(2 * img_h), 6)) + ' '+ \
                        str(round(w/img_w, 6)) + ' ' + str(round(h/img_h, 6)) )
                
                # cv2.rectangle(draw_img, (left_up_x, left_up_y), (right_down_x, right_down_y), (255,255,255), -1)
            write_2_txt(save_txt_path, label_rect)
        # print("img {}, area = {}".format(image_name, areas))
        # draw_img = np.zeros(img.shape, np.uint8)
        # cv2.drawContours(draw_img, select_contours, -1, (255,255,255), thickness = -1)
        # cv2.imwrite(os.path.join("/home/nvidia/rk3588/dataset/label_images", image_name), draw_img)

def allocate_dataset(source_label_path, source_image_path, target_label_path, target_image_path, train_rate=0.6):
    all_label_names = os.listdir(source_label_path)
    all_labeled_iamges_path = [os.path.join(source_image_path, label_name.split('.')[0] + '.jpg') for label_name in all_label_names]
    all_labels_path = [os.path.join(source_label_path, label_name) for label_name in all_label_names]
    
    # 按照比例随即分配数量给train val
    all_labels_num = len(all_label_names)
    train_num = int(all_labels_num * train_rate)
    train_sample_index = random.sample(range(all_labels_num), train_num)
    
    for i in range(all_labels_num):
        if i  in train_sample_index:
            shutil.move(all_labeled_iamges_path[i], os.path.join(target_image_path, 'train'))
            shutil.move(all_labels_path[i], os.path.join(target_label_path, 'train'))
        else:
            shutil.move(all_labeled_iamges_path[i], os.path.join(target_image_path, 'val'))
            shutil.move(all_labels_path[i], os.path.join(target_label_path, 'val'))
         

if __name__ == '__main__':
    # video_2_images(video_path=["/home/nvidia/l/30.mp4", "/home/nvidia/l/20.mp4"], save_iamge_path="/home/nvidia/rk3588/dataset/original_images")
    # use_cv2_label_image(images_path="/home/nvidia/rk3588/dataset/original_images", save_label_path="/home/nvidia/rk3588/dataset/original_labels")
    allocate_dataset(source_label_path="/home/nvidia/rk3588/dataset/original_labels", source_image_path="/home/nvidia/rk3588/dataset/original_images", target_label_path="/home/nvidia/rk3588/dataset/tank/labels", target_image_path="/home/nvidia/rk3588/dataset/tank/images")

2、LabelImg制作标签

1、平台/环境

jetson xavier , aarch64 , conda(pyhton=3.6环境)

2、安装 PyQt5 (pyhton=3.6环境)

(1)使用 pip3 install PyQt5 在 aarch平台上装不上,一直卡住;
(2) 正确方法,参考这里
主要步骤:

sudo apt install pyqt5*
sudo apt-get install python3-pyqt5

建立软链接,不可直接复制,根据自己环境修改
ln -s /usr/lib/python3/dist-packages/PyQt5/  ~/miniforge3/envs/mytest/lib/python3.6/site-packages
ln -s /usr/lib/python3/dist-packages/sip*  ~/miniforge3/envs/mytest/lib/python3.6/site-packages

3、下载LabelImg源码

链接
使用:

python3 labelImg.py

LabelImg 使用方法在此

4、XML文件转成 txt 文件

由于LabelImg 标注完之后生成的是 xml 格式的文件, yolo 训练需要的是txt 格式的文件,所以需要一个脚本转换,下面代码转载自他人,出处一时半会找不到了,见谅。

# -×- coding:utf-8 -*-
import os
from os import listdir,getcwd
import re

classes=[]					#列表,储存标签类别
classes_dict={}				#字典,储存标签类别及对应的序号,yolo标签文件中用序号表示各个类别

def convert(Imgsize,box):
    width,height=Imgsize
    xmin,ymin,xmax,ymax=box
    dw=max(xmin,xmax)-min(xmin,xmax)#框的宽
    dh=max(ymin,ymax)-min(ymin,ymax)#框的高
    x_=(xmin+xmax)/2.0#框的中心点x坐标
    y_=(ymin+ymax)/2.0#框的中心点y坐标

    #归一化
    cx=round(x_/width,6)
    cy=round(y_/height,6)
    w=round(dw/width,6)
    h=round(dh/height,6)

    return [cx,cy,w,h]


def save_txt(namepath,text):			#将内容保存至文本文件中,即成功转化为yolo的标签文件
    with open(namepath,'w')as f:
        f.write(text)

def convert_annotation(xml_path,name):
    xml_name=xml_path+"/"+name
    with open(xml_name,"r",encoding="utf-8")as f1:
        text=f1.read().replace("\n","")
        text=text.replace(" ","")
    # print(text)
    img_size=re.findall("<width>([0-9]+)</width>.*?<height>([0-9]+)</height>",text)[0]
    print(img_size)
    find_datas=re.findall("<object>.*?<name>([a-z|A-Z]*?)</name>.*?<xmin>([0-9]+?)</xmin>.*?<ymin>([0-9]+?)</ymin>.*?<xmax>([0-9]+?)</xmax>.*?<ymax>([0-9]+?)</ymax>",text)
    # print(find_datas)
    savetext=""
    for item in find_datas:			#由于每张图片中可能存在多个类别或标签,将同张图片中所有标签内容保存在一个txt文件中
        class_=item[0]				#类别名
        if class_ not in classes:	#判断此类别是否已存在于classes列表中
            classes.append(class_)	#如果不存在,则添加至列表中
            classes_dict[class_]=len(classes)-1		#同时,为此类别标记序号,即第几个类别,从0开始标号

        print(item)
        imgsize=[int(img_size[0]),int(img_size[1])]			#正则获取的内容为文本格式,需要转化为数字
        box=[int(item[1]),int(item[2]),int(item[3]),int(item[4])]
        site=convert(imgsize,box)							#整理内容,归一化数值
        # print(class_,site)
        savetext+="{0} {1} {2} {3} {4}".format(classes_dict[class_],site[0],site[1],site[2],site[3])		#按格式拼接内容
        savetext+="\n"			#文本换行
    # print(savetext)
    name=name.split(".")[0]		#获取文件名,不包含文件后缀
    save_txt(labels_p+"/"+name+".txt",savetext.strip())			#保存标签文件
    

if __name__=="__main__":
    root_path=os.getcwd()			#获取当前目录绝对路径
    print(root_path)
    labels_p= '/home/nvidia/Dataset/txt_label'	#定义标签储存的文件夹路径
    
    xml_path= '/home/nvidia/Dataset/xml_label'		#.xml文件的父级文件夹路径
    xml_list=sorted(listdir(xml_path))			#获取所有.xml文件名,并保存至列表中,同时排序
    print(xml_list)
    
    for name in xml_list:						#历遍列表
        print(name)
        convert_annotation(xml_path,name)		#开始转化
    
    print(classes,classes_dict)
    with open(labels_p+"/classes.txt","w")as f2:	#保存类别标签文件
        text=""
        for t in classes:
            text+=t
            text+="\n"
        print(text)
        f2.write(text)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里飞刀客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值