引言
最近的項目涉及到對無人機航拍圖像的目標檢測,檢測的目標包含車輛、人、無人機、船舶,比較熱門的航拍數(shù)據(jù)集大多是遙感圖像的數(shù)據(jù)集,與本項目相關的數(shù)據(jù)集查找不易,本文分享一下相關的航拍數(shù)據(jù)數(shù)據(jù)集,以及數(shù)據(jù)集的處理方法。
文中部分數(shù)據(jù)集已經(jīng)下載,需要獲取文中涉及到的數(shù)據(jù)集請私信(目錄中的文件名是本人為了方便自己定義的)
數(shù)據(jù)集處理
1、獲取感興趣的類別
在訓練過程中,數(shù)據(jù)集中的部分類別使用不到,需要提取中感興趣的類別,如果以圖像中沒有感興趣的類別,將圖像舍棄,如果圖像中既有感興趣的類別也有不感興趣的類別,則將不感興趣的類別從標簽文件中刪除,只保存感興趣的類別信息
import os
import shutil
#voc格式標簽的地址
ann_filepath='VOCdevkit/VOC2012/Annotations/'
#原圖像的地址
img_filepath='VOCdevkit/VOC2012/JPEGImages/'
#轉(zhuǎn)換后圖像的存放地址
img_savepath='VOCdevkit/VOC2012/JPEGImages_ssd/'
#轉(zhuǎn)換后標簽的存放地址
ann_savepath='VOCdevkit/VOC2007/Annotations_ssd/'
if not os.path.exists(img_savepath):
os.mkdir(img_savepath)
if not os.path.exists(ann_savepath):
os.mkdir(ann_savepath)
names = locals()
#數(shù)據(jù)集中所有的類別,類別名稱要與標簽號對應,如aeroplane對應name_id為0,將其放在第一個位置
#以voc數(shù)據(jù)集為例如下24~27
classes = ['aeroplane','bicycle','bird', 'boat', 'bottle',
'bus', 'car', 'cat', 'chair', 'cow','diningtable',
'dog', 'horse', 'motorbike', 'pottedplant',
'sheep', 'sofa', 'train', 'tvmonitor', 'person']
for file in os.listdir(ann_filepath):
print(file)
fp = open(ann_filepath + file)
ann_savefile=ann_savepath+file
fp_w = open(ann_savefile, 'w')
lines = fp.readlines()
ind_start = []
ind_end = []
lines_id_start = lines[:]
lines_id_end = lines[:]
#設置感興趣的類別:classesn = '\t\t<name>RoiClassName</name>\n'
#RoiClassName為具體的類別名稱
classes1 = '\t\t<name>aeroplane</name>\n'
classes2 = '\t\t<name>boat</name>\n'
classes3 = '\t\t<name>bus</name>\n'
classes4 = '\t\t<name>car</name>\n'
classes5 = '\t\t<name>person</name>\n'
#在xml中找到object塊,并將其記錄下來
while "\t<object>\n" in lines_id_start:
a = lines_id_start.index("\t<object>\n")
ind_start.append(a)
lines_id_start[a] = "delete"
while "\t</object>\n" in lines_id_end:
b = lines_id_end.index("\t</object>\n")
ind_end.append(b)
lines_id_end[b] = "delete"
#names中存放所有的object塊
i = 0
for k in range(0, len(ind_start)):
names['block%d' % k] = []
for j in range(0, len(classes)):
if classes[j] in lines[ind_start[i] + 1]:
a = ind_start[i]
for o in range(ind_end[i] - ind_start[i] + 1):
names['block%d' % k].append(lines[a + o])
break
i += 1
#print(names['block%d' % k])
#xml頭
string_start = lines[0:ind_start[0]]
#xml尾
string_end = [lines[len(lines) - 1]]
#在給定的類中搜索,若存在則,寫入object塊信息
a = 0
for k in range(0, len(ind_start)):
if classes1 in names['block%d' % k]:
a += 1
string_start += names['block%d' % k]
if classes2 in names['block%d' % k]:
a += 1
string_start += names['block%d' % k]
if classes3 in names['block%d' % k]:
a += 1
string_start += names['block%d' % k]
if classes4 in names['block%d' % k]:
a += 1
string_start += names['block%d' % k]
if classes5 in names['block%d' % k]:
a += 1
string_start += names['block%d' % k]
string_start += string_end
for c in range(0, len(string_start)):
fp_w.write(string_start[c])
fp_w.close()
#如果沒有我們尋找的模塊,則刪除此xml,有的話拷貝圖片
if a == 0:
os.remove(ann_savepath+file)
else:
name_img = img_filepath + os.path.splitext(file)[0] + ".jpg"
shutil.copy(name_img, img_savepath)
fp.close()
2、修改和刪除相應類別ID以及標注信息
-
在實際應用中,數(shù)據(jù)集無需劃分子類,如原數(shù)據(jù)集中含有貨船、郵輪、客船等船的子類;但是項目中只需要檢測到船,并不需要劃分子類,這就需要我們對將數(shù)據(jù)集中的類別進行和并重構(gòu)
-
數(shù)據(jù)集中含有的與項目無關的類別也可以刪除
import os
import random
import numpy as np
from numpy import *
txt_file_path = '/mnt/dir1/database/VisDrone2019/VisDrone2019-DET-val/labels' # 原始的標簽路徑
save_file_path = '/mnt/dir1/database/VisDrone2019/VisDrone2019-DET-val/labels1' # 修改后的標簽路徑
labels_name = os.listdir(txt_file_path) # 獲得每一個標簽名字的列表 / os.listdir() 方法用于返回指定的文件夾包含的文件或文件夾的名字的列表
num = len(labels_name) # 獲取列表長度
list = range(num) # 創(chuàng)建從0到num的整數(shù)列表 list = range(0, num)
files = os.listdir(save_file_path)
for i in list: # 遍歷每一個文件
name = labels_name[i] # 獲取每一個文件的文件名
read_file = open(txt_file_path + "/" + name, 'r') # 讀取txt_file_path/labels路徑中的文件,r表示以只讀方式打開文件
fline = read_file.readlines() # 讀取txt文件中每一行 / readlines()表示讀取整行 / fline是列表類型,fline列表里的元素是str類型
save_txt = open(save_file_path + "/" + name, 'w+') # 讀取save_file_path/labels路徑中的文件. w+表示打開一個文件用于讀寫。如果該文件已存在則打開文件,并從開頭開始編輯,即原有內(nèi)容會被刪除。如果該文件不存在,創(chuàng)建新文件。
for j in fline: # 遍歷txt文件中每一行
list1 = j.split()
# print(list1)
# 刪除類別
if list1[0] != '2': # 刪除類別2
if list1[0] != '6': # 刪除類別6
if list1[0] != '7': # 刪除類別7
if list1[0] != '9': # 刪除類別9
list2 = list1
#print(list2)
# 修改類別
if list2[0] == '1':
list2[0] = '0' # 將類別1改成類別0
elif list2[0] == '3':
list2[0] = '1' # 將類別3改成類別1
elif list2[0] == '4':
list2[0] = '1' # 將類別4改成類別1
elif list2[0] == '5':
list2[0] = '1' # 將類別5改成類別1
elif list2[0] == '8':
list2[0] = '1' # 將類別8改成類別1
b = " ".join(list2) # 將列表轉(zhuǎn)換成字符串類型,且用空格分割
save_txt.write(b) # 寫入新的文件中
save_txt.write('\n') # 換行
3、VOC數(shù)據(jù)集轉(zhuǎn)YOLO
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
def convert(size, box):
x_center = (box[0] + box[1]) / 2.0
y_center = (box[2] + box[3]) / 2.0
x = x_center / size[0]
y = y_center / size[1]
w = (box[1] - box[0]) / size[0]
h = (box[3] - box[2]) / size[1]
return (x, y, w, h)
def convert_annotation(xml_files_path, save_txt_files_path, classes):
xml_files = os.listdir(xml_files_path)
#print(xml_files)
for xml_name in xml_files:
print(xml_name)
xml_file = os.path.join(xml_files_path, xml_name)
out_txt_path = os.path.join(save_txt_files_path, xml_name.split('.')[0] + '.txt')
#
folder = os.path.exists(save_txt_files_path)
if not folder: #判斷是否存在文件夾如果不存在則創(chuàng)建為文件夾
os.makedirs(save_txt_files_path) #makedirs 創(chuàng)建文件時如果路徑不存在會創(chuàng)建這個路徑#
#
out_txt_f = open(out_txt_path, 'w', encoding="utf-8")
tree = ET.parse(xml_file)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.iter('object'):
difficult = obj.find('difficult').text
cls = obj.find('name').text
if cls not in classes or int(difficult) == 1:
continue
cls_id = classes.index(cls)
xmlbox = obj.find('bndbox')
b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
float(xmlbox.find('ymax').text))
# b=(xmin, xmax, ymin, ymax)
print(w, h, b)
bb = convert((w, h), b)
out_txt_f.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
if __name__ == "__main__":
# 需要轉(zhuǎn)換的類別,需要一一對應
classes1 = ['aeroplane', 'boat', 'bus', 'car', 'person']
# 2、voc格式的xml標簽文件路徑
xml_files1 = r'VOCdevkit/VOC2012/Annotations_ssd/'
# 3、轉(zhuǎn)化為yolo格式的txt標簽文件存儲路徑
save_txt_files1 = r'VOCdevkit/VOC2012/labels_ssd/'
convert_annotation(xml_files1, save_txt_files1, classes1)
無人機數(shù)據(jù)集介紹
?FW-UAV1
固定翼無人機數(shù)據(jù)集,其中包含1817幅圖像,圖像格式為.png,已經(jīng)轉(zhuǎn)換為yolo格式,但是還未劃分數(shù)據(jù)集、標簽和圖像在一個文件夾中。
下載地址:Fixed Wing UAV Dataset (kaggle.com)
?圖像實例:
FW-UAV2
固定翼無人機,554幅圖像,yolo格式,標簽和圖像在一個文件夾中
?下載地址:Fixed Wing UAV Dataset (kaggle.com)
圖像實例:文章來源:http://www.zghlxwxcb.cn/news/detail-774416.html
FW-UAV3
固定翼無人機數(shù)據(jù)集,包含1790幅圖像,包含yolo標簽格式
下載地址:Fixed Wing UAV - Plane (kaggle.com)
?
?圖片實例:
?
UAV1
旋翼式無人機數(shù)據(jù)集,其中包含4010幅圖像,已經(jīng)標注好了yolo格式,標簽和圖片在一個文件夾中,數(shù)據(jù)集未劃分
下載地址:Drone Object Detection (kaggle.com)
圖像實例:
UAV2
旋翼式無人機數(shù)據(jù)集,其中包含4014幅圖像,已經(jīng)標注好了yolo格式,標簽和圖片在一個文件夾中,數(shù)據(jù)集未劃分
下載地址:Amateur Unmanned Air Vehicle Detection (kaggle.com)
?圖像實例:
?
車輛和行人數(shù)據(jù)集
VisDrone
VisDrone數(shù)據(jù)集中的一部分,一共有5138幅圖像,已經(jīng)轉(zhuǎn)換為yolo格式,劃分好了訓練集、驗證集、測試集
下載地址:visdrone (kaggle.com)
?圖像實例:
HIT-UAV
車輛和行人數(shù)據(jù)集,共有2866幅圖像,Person8000個,Car5000個,可以直接使用
數(shù)據(jù)集地址:HIT-UAV: A High-altitude Infrared Thermal Dataset (kaggle.com)
?圖像實例:
?
船舶數(shù)據(jù)集
SHIP1
航拍船只數(shù)據(jù)集(衛(wèi)星),一共有621幅圖像,標注格式為voc ,archive2
下載地址:Ship Detection from Aerial Images (kaggle.com)
?圖像實例:
?
SHIP2
共有134000幅航拍船只圖像(遙感),標簽格式為yolo archive3
下載地址:Ships/Vessels in Aerial Images (kaggle.com)
?圖像實例:
SHIP3
航拍鳥瞰圖,沒有標簽,8932幅圖像
下載地址:ship-imageclassify (kaggle.com)
圖像實例:
文章來源地址http://www.zghlxwxcb.cn/news/detail-774416.html
到了這里,關于無人機航拍圖像數(shù)據(jù)集匯總的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!