提出问题
最近做目标检测/跟踪研究中,需要自己标注研究领域数据集。网上的标注软件很多,但因为目前不同输入格式的算法也很多,所以想着能不能找一种包含多种数据集格式的软件,方便不同输入格式的转换。最后,在网上找到了DarkLabel这个软件,这个软件封装了不少的输入格式,而且还能自己自定义保存格式,整体来说还算不错的。以下附上下载链接:DarkLabel,这个软件最新版是2.4版,估计也是好久没更新了,本人下载的也是DarkLabel2.4。
解决方案
-
标注步骤
- 我下载的是DarkLabel2.4的二进制软件,因此可以直接打开。软件内容和界面如下:
直接点击DarkLabel.exe即可,出现右侧的界面。其中,darklabel.yml文件可以看到各种标注方式的定义,并且可以自定义数据集标注格式。
- 如何标注?
如图中左侧所示的数字步骤:
- (1)点击“Open Video”加载需要标注的视频;
- (2)选择需要标注的格式,这里我们选择VOC的标注格式,为后续的YOLO系列算法输入做准备。其他算法按照算法的输入格式选择即可;
- (3)选择保存的格式,这里我们选择了xml的保存格式,并且是分离开来的保存,也是为了后续算法的输入做准备;
- (4)这里在标注的时候选择类别,比如我们在图中标注的是船只,就可以选择“ship”这一类,标注其他类别时就切换其他类别;
- (5)这里是选择xml中记录的内容,我们这里选择Box+Label格式,即xml文件存储时,记录的内容如下图所示,即左上角和右下角坐标,以及类别。
(6)其他:界面中有个“Save Settings”选项,当以上步骤都选择好之后,可以点此选项,下次再打开界面就是当前设置,不用再次设置。
(7)标注:标注其实和大多数软件一样,鼠标点击标注即可,标注完之后,左上角的椭圆形有个r=1这种记录表示当前帧有几个目标。其次,*“Shfit”+鼠标左键即可对目标位置进行调整;“Shfit”+鼠标左键两次,显示如下图所示的内容,可以对目标属性进行编辑,可以设置类别和id等。鼠标右键点选表示删除当前绘制的目标。***
-
数据处理 (以YOLO系列输入为准)
以上第一步骤标注完之后,会生成多文件夹保存的xml文件,里面包含冗余帧(空帧),以及后续怎么将整个数据集合在一起输入YOLO算法,需要进一步处理。这里提供三个算法,分别用于视频转影像、删除空帧以及重命名。
代码1(视频转影像)
# coding=utf-8
import cv2
import os
import threading
from threading import Lock, Thread
video_path = "./video_detection/videodata/"
pic_path = "./xml_process/video2data/"
filelist = os.listdir(video_path)
print (filelist)
def video2pic(filename):
# print(filename)
cnt = 0
dnt = 0
if os.path.exists(pic_path + str(filename[:-4])):
pass
else:
os.mkdir(pic_path + str(filename[:-4]))
cap = cv2.VideoCapture(video_path + str(filename)) # 读入视频
#print(cap)
while True:
# get a frame
ret, image = cap.read()
if image is None:
break
# show a frame
w = image.shape[1]
h = image.shape[0]
if (cnt % 1) == 0:
cv2.imencode('.jpg', image)[1].tofile(pic_path + str(filename[:-4]) + '/' + str(dnt).zfill(8) + '.jpg')
print(pic_path + str(filename[:-4]) + '/' + str(dnt) + '.jpg')
dnt = dnt + 1
cnt = cnt + 1
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
if __name__ == '__main__':
for filename in filelist:
threading.Thread(target=video2pic, args=(filename, )).start()
代码2(删除空帧)
###author:Wang Xiaofan
import os
def delete_null(filePath1, filePath2):
list1 = os.listdir(filePath1)
file_list1 = [] #annotations中的文件名列表 不带后缀
for i in list1:
#print (os.path.splitext(i)[0][-6:])
file_list1.append(os.path.splitext(i)[0][-8:])
#print(file_list1)
list2 = os.listdir(filePath2)
file_list2 = [] #image中的文件名列表 不带后缀
for i in list2:
#print (os.path.splitext(i)[0][-6:])
file_list2.append(os.path.splitext(i)[0])
#print(file_list2)
#找出没有标注的图片名称列表
b = [y for y in file_list2 if y not in file_list1]
#把这些列表加上扩展名 然后将其删除
for i in b:
os.remove(os.path.join(filePath2, i+'.jpg'))
img_path = './xml_process/video2data/'
xml_path = './xml_process/darklabel_xml/'
for item in os.listdir(img_path):
file1 = os.path.join(xml_path, item)
file2 = os.path.join(img_path, item)
delete_null(file1, file2)
代码3(重命名影像名和xml文件名)
import glob
import os
img_path = './xml_process/video2data/'
txt_path = './xml_process/darklabel_xml'
for item in os.listdir(img_path):
file1 = os.path.join(txt_path, item)
file2 = os.path.join(img_path, item)
#print (file1)
for i in glob.glob(file1 + "/*.xml"):
#print (item + '_' + os.path.split(i)[1][:-4][2:] + '.txt')
os.rename(i, './xml_process/labels/' + item + '_' + os.path.split(i)[1])
for i in glob.glob(file2 + "/*.jpg"):
#print (item + '_' + os.path.split(i)[1][:-4] + '.jpg')
os.rename(i, './xml_process/images/' + item + '_' + os.path.split(i)[1])
文章评论