1.下載crowdhuman數(shù)據(jù)集,下載鏈接如下:CrowdHuman Dataset
2.labels文件odgt格式j(luò)son文件轉(zhuǎn)換成coco數(shù)據(jù)格式,代碼如下:
# corwdhuman->coco
import os
import json
from PIL import Image
def load_file(fpath):#fpath是具體的文件 ,作用:#str to list
assert os.path.exists(fpath) #assert() raise-if-not
with open(fpath,'r') as fid:
lines = fid.readlines()
records = [json.loads(line.strip('\n')) for line in lines] #str to list
return records
def crowdhuman2coco(odgt_path,json_path):#一個輸入文件路徑,一個輸出文件路徑
records = load_file(odgt_path) #提取odgt文件數(shù)據(jù)
#預(yù)處理
json_dict = {"images":[], "annotations": [], "categories": []}#定義一個字典,coco數(shù)據(jù)集標(biāo)注格式
START_B_BOX_ID = 1 #設(shè)定框的起始ID
image_id = 1 #每個image的ID唯一,自己設(shè)定start,每次++
bbox_id = START_B_BOX_ID
image = {} #定義一個字典,記錄image
annotation = {} #記錄annotation
categories = {} #進(jìn)行類別記錄
record_list = len(records) #獲得record的長度,循環(huán)遍歷所有數(shù)據(jù)。
print(record_list)
#一行一行的處理。
for i in range(record_list):
file_name = records[i]['ID']+'.jpg' #這里是字符串格式 eg.273278,600e5000db6370fb
#image_id = int(records[i]['ID'].split(",")[0]) 這樣會導(dǎo)致id唯一,要自己設(shè)定
im = Image.open("/media/ubuntu/work_space/data-human/crowdhuman/Images/"+file_name)
#根據(jù)文件名,獲取圖片,這樣可以獲取到圖片的寬高等信息。因為再odgt數(shù)據(jù)集里,沒有寬高的字段信息。
image = {'file_name': file_name, 'height': im.size[1], 'width': im.size[0],'id':image_id} #im.size[0],im.size[1]分別是寬高
json_dict['images'].append(image) #這一步完成一行數(shù)據(jù)到字典images的轉(zhuǎn)換。
gt_box = records[i]['gtboxes']
gt_box_len = len(gt_box) #每一個字典gtboxes里,也有好幾個記錄,分別提取記錄。
for j in range(gt_box_len):
category = gt_box[j]['tag']
if category not in categories: #該類型不在categories,就添加上去
new_id = len(categories) + 1 #ID遞增
categories[category] = new_id
category_id = categories[category] #重新獲取它的類別ID
fbox = gt_box[j]['fbox'] #獲得全身框
#對ignore進(jìn)行處理,ignore有時在key:extra里,有時在key:head_attr里。屬于互斥的。
ignore = 0 #下面key中都沒有ignore時,就設(shè)為0,據(jù)觀察,都存在,只是存在哪個字典里,需要判斷一下
if "ignore" in gt_box[j]['head_attr']:
ignore = gt_box[j]['head_attr']['ignore']
if "ignore" in gt_box[j]['extra']:
ignore = gt_box[j]['extra']['ignore']
#對字典annotation進(jìn)行設(shè)值。
annotation = {'area': fbox[2]*fbox[3], 'iscrowd': ignore, 'image_id': #添加hbox、vbox字段。
image_id, 'bbox':fbox, 'hbox':gt_box[j]['hbox'],'vbox':gt_box[j]['vbox'],
'category_id': category_id,'id': bbox_id,'ignore': ignore,'segmentation': []}
#area的值,暫且就是fbox的寬高相乘了,觀察里面的數(shù)據(jù),發(fā)現(xiàn)fbox[2]小、fbox[3]很大,剛好一個全身框的寬很小,高就很大。(猜測),不是的話,再自行修改
#segmentation怎么處理?博主自己也不知道,找不到對應(yīng)的數(shù)據(jù),這里就暫且不處理。
#hbox、vbox、ignore是添加上去的,以防有需要。
json_dict['annotations'].append(annotation)
bbox_id += 1 #框ID ++
image_id += 1 #這個image_id的遞增操作,注意位置,博主一開始,放上面執(zhí)行了,后面出了bug,自己可以理一下。
#annotations的轉(zhuǎn)化結(jié)束。
#下面這一步,對所有數(shù)據(jù),只需執(zhí)行一次,也就是對categories里的類別進(jìn)行統(tǒng)計。
for cate, cid in categories.items():
#dict.items()返回列表list的所有列表項,形如這樣的二元組list:[(key,value),(key,value),...]
cat = {'supercategory': 'none', 'id': cid, 'name': cate}
json_dict['categories'].append(cat)
#到此,json_dict的轉(zhuǎn)化全部完成,對于其他的key,
#因為沒有用到(不訪問),就不需要給他們空間,也不需要去處理,字典是按key訪問的,如果自己需要就自己添加上去就行
json_fp = open(json_path, 'w')
json_str = json.dumps(json_dict) #寫json文件。
json_fp.write(json_str)
json_fp.close()
if __name__ == '__main__':
json_dict = '/media/ubuntu/work_space/data-human/crowdhuman/train.json'
odge_path = '/media/ubuntu/work_space/data-human/crowdhuman/annotation_train.odgt'
crowdhuman2coco(odge_path,json_dict)
3.coco數(shù)據(jù)格式轉(zhuǎn)換yolo數(shù)據(jù)
"""
COCO 格式的數(shù)據(jù)集轉(zhuǎn)化為 YOLO 格式的數(shù)據(jù)集
--json_path 輸入的json文件路徑
--save_path 保存的文件夾名字,默認(rèn)為當(dāng)前目錄下的labels。
"""
import os
import json
from tqdm import tqdm
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--json_path', default='/media/ubuntu/work_space/data-human/crowdhuman/val.json',type=str, help="input: coco format(json)")
parser.add_argument('--save_path', default='/media/ubuntu/work_space/data-human/crowdhuman/labels/', type=str, help="specify where to save the output dir of labels")
arg = parser.parse_args()
#中心點坐標(biāo),長和寬(小數(shù)點形式)
def convert(size, box):
dw = 1. / (size[0])
dh = 1. / (size[1])
x = box[0] + box[2] / 2.0
y = box[1] + box[3] / 2.0
w = box[2]
h = box[3]
x = x * dw
w = w * dw
y = y * dh
h = h * dh
return (x, y, w, h)
if __name__ == '__main__':
json_file = arg.json_path # COCO Object Instance 類型的標(biāo)注
ana_txt_save_path = arg.save_path # 保存的路徑
data = json.load(open(json_file, 'r'))
if not os.path.exists(ana_txt_save_path):
os.makedirs(ana_txt_save_path)
id_map = {} # coco數(shù)據(jù)集的id不連續(xù)!根據(jù)自己需求順序自定義輸出每個類別的id
with open(os.path.join(ana_txt_save_path, 'classes.txt'), 'w') as f:
# 寫入classes.txt
for i, category in enumerate(data['categories']):
f.write(f"{category['name']}\n")
id_map[category['id']] = category['id']-1
print("name={}, id={}".format(category['name'], category['id']))
print("id_map={}".format(id_map))
i = 0
for img in tqdm(data['images']):
filename = img["file_name"]
img_width = img["width"]
img_height = img["height"]
img_id = img["id"]
head, tail = os.path.splitext(filename)
ana_txt_name = head + ".txt" # 對應(yīng)的txt名字,與jpg一致
f_txt = open(os.path.join(ana_txt_save_path, ana_txt_name), 'w')
for ann in data['annotations']:
# print("ann_type={}".format(type(ann)))
if ann == None:
# print("filename={}".format(filename))
continue
else:
if ann['image_id'] == img_id:
# print("i={}".format(i))
print("img_id is:",img_id)
box = convert((img_width, img_height), ann["bbox"])
print('****',id_map[ann["category_id"]])
f_txt.write("%s %s %s %s %s\n" % (id_map[ann["category_id"]], box[0], box[1], box[2], box[3]))
f_txt.close()
i = i + 1
4.通過步驟3,crowdhuman標(biāo)簽轉(zhuǎn)換成了coco數(shù)據(jù)集,但是在標(biāo)簽文檔中有個classes的txt文檔,內(nèi)容有兩個標(biāo)簽:person和mask? ?(person:0,mask:1)
For example txt?containing:
0 ?0.4609375 ?0.2791666666 ??0.028125 ???0.0638888
0 ?0.5910156 ?0.6375000000 ??0.04140625 ?0.0916666
0 ?0.9058593 ?0.4722222222 ??0.04765625 ?0.0916666
5.清理yolo的txt標(biāo)簽文件,去掉mask,類別為1的標(biāo)簽去掉,代碼如下:
import os
import shutil
import json
from tqdm import tqdm
txt_path = '/media/ubuntu/work_space/data-human/crowdhuman/train_labels/'
txt_list = os.listdir(txt_path)
for i in tqdm(txt_list):
txt_name = txt_path + i
lines = [l for l in open(txt_name,"r") if l.find("1",0,1) !=0]
fd = open(txt_name,"a")
fd.truncate(0)
j = 0
while True:
if j < len(lines):
fd.write(lines[j])
j += 1
else:
break
fd.close()
6.darknet environment preparation
(1) Install darknet environment
git clone GitHub - AlexeyAB/darknet: YOLOv4 / Scaled-YOLOv4 / YOLO - Neural Networks for Object Detection (Windows and Linux version of Darknet )
(2) modify Makefile
GPU=1
CUDNN=1
OPENCV=1
(3) compile darknet
cd darknet
Make
7.data preparation
? ?(1)generate train.txt file and test.txt
Run the following command in the terminal to generate train.txt
find /media/deepnorth/14b6945d-9936/head-doc/JPEGImages/ ?-name "*.jpg" ?> train.txt
train.txt contains the path of each images in the JPEGImages file
text.txt is the same method ,contains the path of each images in the JPEGImages file, as shown below:
?
? ??
8.train file preparation
Create a new folder named yolov7?under the darknet folder, including the following files
?
?
(1) Create file obj.data containing (where classes = number of objects), backup is the path where the model is saved :
classes= 1
train ?= yolov7/train.list
valid ?= yolov7/test.list
names =? yolov7/obj.names
backup = backup/
(2)Create file obj.names with objects names - each in new line
here is:person
(3)Calculating the anchors of a dataset
execute the following command in the darknet directory
./darknet detector calc_anchors yolov7/yolov7.data -num_of_clusters 9?-width 640?-height 640
:可以省略
(4)modify yolov7.cfg
[yolo]
mask = 3,4,5
anchors = 12,16, 19,36, 40,28, 36,75, 76,55, 72,146, 142,110, 192,243, 459,401
classes=1
num=9
change line classes=1 to your number of objects in each of 3?[yolo]-layers
change [filters=255] to filters=(classes + 5)x3?in the 3?[convolutional] before each [yolo] layer
anchors are calculated from step (3)
9.Start training
./darknet detector train yolov7/obj.data yolov7/yolov7.cfg -dont_show -gpus 0,1,2,3
(Optional) Resume training after interruption
./darknet detector train yolov7/obj.data yolov7/yolov7.cfg /backup/yolov3-tiny_1000.weights -gpus 0,1,2,3
(Optional)?drawing of chart of average-Loss and accuracy-mAP (-map flag) during training
./darknet detector train yolov7/obj.data yolov7/yolov7.cfg?-dont_show -mjpeg_port 8090 -map
When the training is completed, we will see that many models are saved under the path corresponding to backup, as shown in the following figure.
?10.Test
(1)Test image
./darknet detector test yolov7/obj.data yolov7/yolov7.cfg ?yolov7.weight imgtest.jpg
(2) Test video
./darknet detector demo yolov7/obj.data yolov7/yolov7.cfg ?yolov7.weight <video file>
(3) Check accuracy mAP@IoU=0.5:
./darknet detector map yolov7/obj.data yolov7/yolov7.cfg ?yolov7.weight -iou_thresh 0.5
11.Model selection
Method 1: When -map?flag is added to the training command line, you will get the following chart. Select the model with the highest map value as the final model.
文章來源:http://www.zghlxwxcb.cn/news/detail-451647.html
Method 2: Calculate the map through step5, and then select the model with the highest map as the final model.文章來源地址http://www.zghlxwxcb.cn/news/detail-451647.html
到了這里,關(guān)于crowdhuman 數(shù)據(jù)集 darknet yolov7訓(xùn)練的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!