從下面github庫中拿代碼:
https://github.com/mikel-brostrom/Yolov5_DeepSort_Pytorchhttps://github.com/mikel-brostrom/Yolov5_DeepSort_PytorchGitHub - Sharpiless/Yolov5-Deepsort: 最新版本yolov5+deepsort目標(biāo)檢測(cè)和追蹤,能夠顯示目標(biāo)類別,支持5.0版本可訓(xùn)練自己數(shù)據(jù)集最新版本yolov5+deepsort目標(biāo)檢測(cè)和追蹤,能夠顯示目標(biāo)類別,支持5.0版本可訓(xùn)練自己數(shù)據(jù)集 - GitHub - Sharpiless/Yolov5-Deepsort: 最新版本yolov5+deepsort目標(biāo)檢測(cè)和追蹤,能夠顯示目標(biāo)類別,支持5.0版本可訓(xùn)練自己數(shù)據(jù)集https://github.com/Sharpiless/Yolov5-Deepsort
下載好匹配的deeosort和yolov5代碼很重要,題主折騰了一天,坑在版本上了??!
題主用的deeosort v3.0和yolov5 5.0版本,master似乎還不完善,沒跑通,要是跑通了的讀者希望可以交流一下。
直接進(jìn)入正題:
一.目標(biāo)追蹤整體代碼
?分別主體是yolov5和deep_sort。
二.訓(xùn)練自己的數(shù)據(jù)集
yolov5和deep_sort分開訓(xùn)練。首先訓(xùn)練yolov5,這個(gè)不難,超鏈接如下。
Yolov5 超詳細(xì)教程_武大人民泌外I科人工智能團(tuán)隊(duì)的博客-CSDN博客首先github拿代碼:GitHub - ultralytics/yolov5: YOLOv5 ?? in PyTorch > ONNX > CoreML > TFLiteYOLOv5 ?? in PyTorch > ONNX > CoreML > TFLite. Contribute to ultralytics/yolov5 development by creating an account on GitHub.https://github.com/ultralythttps://blog.csdn.net/weixin_53711236/article/details/123766920
三.訓(xùn)練deep_sort
準(zhǔn)備deep_sort的數(shù)據(jù)集,和yolov5不一樣,這是一個(gè)分類的數(shù)據(jù)集。
我們用代碼把圖像中的檢測(cè)目標(biāo)扣出來,作為我們的數(shù)據(jù)集。
代碼如下:
import cv2
import xml.etree.ElementTree as ET
import numpy as np
import xml.dom.minidom
import os
import argparse
def main():
# JPG文件的地址
img_path = '/home/zqy/Desktop/yolov5-master/nxm_data/images_all/'
# XML文件的地址
anno_path = '/home/zqy/Desktop/yolov5-master/nxm_data/labels_xml/'
# 存結(jié)果的文件夾
cut_path = '/home/zqy/Desktop/yolov5-master/nxm_data/crops/'
if not os.path.exists(cut_path):
os.makedirs(cut_path)
# 獲取文件夾中的文件
imagelist = os.listdir(img_path)
# print(imagelist
for image in imagelist:
image_pre, ext = os.path.splitext(image)
img_file = img_path + image
img = cv2.imread(img_file)
xml_file = anno_path + image_pre + '.xml'
# DOMTree = xml.dom.minidom.parse(xml_file)
# collection = DOMTree.documentElement
# objects = collection.getElementsByTagName("object")
tree = ET.parse(xml_file)
root = tree.getroot()
# if root.find('object') == None:
# return
obj_i = 0
for obj in root.iter('object'):
obj_i += 1
print(obj_i)
cls = obj.find('name').text
xmlbox = obj.find('bndbox')
b = [int(float(xmlbox.find('xmin').text)), int(float(xmlbox.find('ymin').text)),
int(float(xmlbox.find('xmax').text)),
int(float(xmlbox.find('ymax').text))]
img_cut = img[b[1]:b[3], b[0]:b[2], :]
path = os.path.join(cut_path, cls)
# 目錄是否存在,不存在則創(chuàng)建
mkdirlambda = lambda x: os.makedirs(x) if not os.path.exists(x) else True
mkdirlambda(path)
try:
cv2.imwrite(os.path.join(cut_path, cls, '{}_{:0>2d}.jpg'.format(image_pre, obj_i)), img_cut)
except:
continue
print("&&&&")
if __name__ == '__main__':
main()
注意:這里數(shù)據(jù)集可能會(huì)存在負(fù)樣本,導(dǎo)致img_cut為空,我在這里修改了代碼,加了try判斷,只算入了正樣本。
上述代碼在自己的數(shù)據(jù)集上生成了crops文件夾,目錄如下:
接著要把這些數(shù)據(jù)分為訓(xùn)練集和驗(yàn)證集,跟類別有關(guān)系,注意類別和目標(biāo)是兩個(gè)概念。
我在這檢測(cè)的目標(biāo)只有一個(gè),但是可以有不同的類別,在這里的類別有112個(gè),因此訓(xùn)練集和測(cè)試集下邊的類別就應(yīng)該有112個(gè)。可以自己整理,也可以用代碼分,代碼如下:
import os
from PIL import Image
from shutil import copyfile, copytree, rmtree, move
PATH_DATASET = '/home/zqy/Desktop/yolov5-master/nxm_data/crops' # 需要處理的文件夾
PATH_NEW_DATASET = '/home/zqy/Desktop/yolov5-master/nxm_data/stitches' # 處理后的文件夾
PATH_ALL_IMAGES = PATH_NEW_DATASET + '/all_images'
PATH_TRAIN = PATH_NEW_DATASET + '/train'
PATH_TEST = PATH_NEW_DATASET + '/test'
# 定義創(chuàng)建目錄函數(shù)
def mymkdir(path):
path = path.strip() # 去除首位空格
path = path.rstrip("\\") # 去除尾部 \ 符號(hào)
isExists = os.path.exists(path) # 判斷路徑是否存在
if not isExists:
os.makedirs(path) # 如果不存在則創(chuàng)建目錄
print(path + ' 創(chuàng)建成功')
return True
else:
# 如果目錄存在則不創(chuàng)建,并提示目錄已存在
print(path + ' 目錄已存在')
return False
class BatchRename():
'''
批量重命名文件夾中的圖片文件
'''
def __init__(self):
self.path = PATH_DATASET # 表示需要命名處理的文件夾
# 修改圖像尺寸
def resize(self):
for aroot, dirs, files in os.walk(self.path):
# aroot是self.path目錄下的所有子目錄(含self.path),dir是self.path下所有的文件夾的列表.
filelist = files # 注意此處僅是該路徑下的其中一個(gè)列表
# print('list', list)
# filelist = os.listdir(self.path) #獲取文件路徑
total_num = len(filelist) # 獲取文件長(zhǎng)度(個(gè)數(shù))
for item in filelist:
if item.endswith('.jpg'): # 初始的圖片的格式為jpg格式的(或者源文件是png格式及其他格式,后面的轉(zhuǎn)換格式就可以調(diào)整為自己需要的格式即可)
src = os.path.join(os.path.abspath(aroot), item)
# 修改圖片尺寸到128寬*256高
im = Image.open(src)
out = im.resize((128, 256), Image.ANTIALIAS) # resize image with high-quality
out.save(src) # 原路徑保存
def rename(self):
for aroot, dirs, files in os.walk(self.path):
# aroot是self.path目錄下的所有子目錄(含self.path),dir是self.path下所有的文件夾的列表.
filelist = files # 注意此處僅是該路徑下的其中一個(gè)列表
# print('list', list)
# filelist = os.listdir(self.path) #獲取文件路徑
total_num = len(filelist) # 獲取文件長(zhǎng)度(個(gè)數(shù))
i = 1 # 表示文件的命名是從1開始的
for item in filelist:
if item.endswith('.jpg'): # 初始的圖片的格式為jpg格式的(或者源文件是png格式及其他格式,后面的轉(zhuǎn)換格式就可以調(diào)整為自己需要的格式即可)
src = os.path.join(os.path.abspath(aroot), item)
# 根據(jù)圖片名創(chuàng)建圖片目錄
dirname = str(item.split('_')[0])
# 為相同車輛創(chuàng)建目錄
# new_dir = os.path.join(self.path, '..', 'bbox_all', dirname)
new_dir = os.path.join(PATH_ALL_IMAGES, dirname)
if not os.path.isdir(new_dir):
mymkdir(new_dir)
# 獲得new_dir中的圖片數(shù)
num_pic = len(os.listdir(new_dir))
dst = os.path.join(os.path.abspath(new_dir),
dirname + 'C1T0001F' + str(num_pic + 1) + '.jpg')
# 處理后的格式也為jpg格式的,當(dāng)然這里可以改成png格式 C1T0001F見mars.py filenames 相機(jī)ID,跟蹤指數(shù)
# dst = os.path.join(os.path.abspath(self.path), '0000' + format(str(i), '0>3s') + '.jpg') 這種情況下的命名格式為0000000.jpg形式,可以自主定義想要的格式
try:
copyfile(src, dst) # os.rename(src, dst)
print('converting %s to %s ...' % (src, dst))
i = i + 1
except:
continue
print('total %d to rename & converted %d jpgs' % (total_num, i))
def split(self):
# ---------------------------------------
# train_test
images_path = PATH_ALL_IMAGES
train_save_path = PATH_TRAIN
test_save_path = PATH_TEST
if not os.path.isdir(train_save_path):
os.mkdir(train_save_path)
os.mkdir(test_save_path)
for _, dirs, _ in os.walk(images_path, topdown=True):
for i, dir in enumerate(dirs):
for root, _, files in os.walk(images_path + '/' + dir, topdown=True):
for j, file in enumerate(files):
if (j == 0): # test dataset;每個(gè)車輛的第一幅圖片
print("序號(hào):%s 文件夾: %s 圖片:%s 歸為測(cè)試集" % (i + 1, root, file))
src_path = root + '/' + file
dst_dir = test_save_path + '/' + dir
if not os.path.isdir(dst_dir):
os.mkdir(dst_dir)
dst_path = dst_dir + '/' + file
move(src_path, dst_path)
else:
src_path = root + '/' + file
dst_dir = train_save_path + '/' + dir
if not os.path.isdir(dst_dir):
os.mkdir(dst_dir)
dst_path = dst_dir + '/' + file
move(src_path, dst_path)
rmtree(PATH_ALL_IMAGES)
if __name__ == '__main__':
demo = BatchRename()
demo.resize()
demo.rename()
demo.split()
分好后train和test下各有112個(gè)文件夾,代表著112個(gè)類別。
將train和test移動(dòng)到deep_sort/deep目錄下。
修改train.py中train dataset的預(yù)處理如下:
transform_train = torchvision.transforms.Compose([
torchvision.transforms.Resize((128, 64)),
torchvision.transforms.RandomCrop((128, 64), padding=4),
torchvision.transforms.RandomHorizontalFlip(),
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize(
[0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
?接著修改147行,以免權(quán)重保存覆蓋原始權(quán)重:
torch.save(checkpoint, './checkpoint/ckpt1.t7')
接著在model.py中修改類別,這類是112個(gè)類別:
class Net(nn.Module):
def __init__(self, num_classes= 112 ,reid=False):
super(Net,self).__init__()
# 3 128 64
self.conv = nn.Sequential(
nn.Conv2d(3,64,3,stride=1,padding=1),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
# nn.Conv2d(32,32,3,stride=1,padding=1),
# nn.BatchNorm2d(32),
# nn.ReLU(inplace=True),
nn.MaxPool2d(3,2,padding=1),
)
然后在deep_sort/deep目錄下打開終端,運(yùn)行:
python train.py --data-dir data/
得到結(jié)果如下:
?權(quán)重結(jié)果保存在deep/checkpoint中。
四.測(cè)試結(jié)果
python track.py --yolo_weights 你的權(quán)重 --source 你的視頻 --deep_sort_weights 你的權(quán)重 --device 0 --save-vid
?--save-vid要調(diào)用,否則不會(huì)保存結(jié)果。
結(jié)束!
ps:如果報(bào)錯(cuò)文章來源:http://www.zghlxwxcb.cn/news/detail-804034.html
File "/home/zqy/Desktop/Yolov5_DeepSort_Pytorch-3.0/deep_sort_pytorch/deep_sort/deep/feature_extractor.py", line 37, in _resize
return cv2.resize(im.astype(np.float32)/255., size)
cv2.error: OpenCV(4.5.5) /io/opencv/modules/imgproc/src/resize.cpp:4052: error: (-215:Assertion failed) !ssize.empty() in function 'resize'
原因,track.py里的iou和nms調(diào)太低了,如果仍然報(bào)錯(cuò),建議加個(gè)try跳過這些空的im。文章來源地址http://www.zghlxwxcb.cn/news/detail-804034.html
到了這里,關(guān)于Yolov5 + Deepsort 重新訓(xùn)練自己的數(shù)據(jù)(保姆級(jí)超詳細(xì))的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!