Video-based pedestrian re-identification-01
1. Know the mars data set
Research on video pedestrian re-recognition basically cannot bypass the mars data set. As a more recognized data set for video pedestrian re-recognition, the excellent papers of each top issue are improving the rank of the mars data set.
So first, let us get to know this data set:
data set address
info file
We download the content in the above link, and then unzip it and save it in the following way:
Then, explain the content in these folders:
1.1 bbox_train
In the bbox_train folder, there are 625 subfolders (representing 625 pedestrian ids), which contain a total of 8,298 tracklets, and a total of 509,914 pictures.
Note: The names of the folders here are not consecutive!
Open any folder to see these contents: (explained after the file name)
1.2 bbox_test
There are a total of 636 subfolders in the bbox_test folder (representing 636 pedestrian ids), a total of 12,180 tracklets (tracklets), a total of 681,089 pictures. In the experiment, this folder was divided into gallery + query set. This will be explained in the info folder.
Note that they are not continuous! ! ! !
The subfolder named 00-1 represents useless picture collections, and their corresponding pedestrian id is set to **-1**, and pictures with pid = -1 are generally ignored in the algorithm.
In the name 0000 subfolder, their corresponding pedestrian id is set to 0, which indicates interference factors and negatively affects the accuracy of retrieval.
1.3 info
The info folder contains 5 sub-files, which contain the information of the entire data set, in order to facilitate the use of the data set.
1.3.1 train_name.txt
In this txt file, the names of all pictures in the bbox_train folder are stored in order, with a total of 509,914 lines (corresponding to 509914 pictures).
Picture name explanation:
0001 C1 T0001 F0001.jpg as an example.
0001 represents the id of the pedestrian, which is the corresponding 0001 subfolder name in the bbox_train folder;
C1 represents the id of the camera, indicating that this picture was taken under the first camera (a total of 6 cameras);
T0001 said Regarding the first
short video (tracklet) in this pedestrian video segment; F0001 indicates that this picture is the first frame in this short video (tracklet). In each short video (tracklet), the number of frames starts from F0001.
1.3.2 test_name.txt
Similarly, in this txt file, the names of all pictures in the bbox_test folder are stored in order, with a total of 681,089 lines.
1.3.3 tracks_train_info.mat
The file in the .mat format is a file saved by matlab. After opening it with matlab, you can see that it is an 8298*4 matrix.
Each row of the matrix represents a tracklet; the
first and second columns represent the sequence number (start, end) of the picture, which corresponds to the row number in the train_name.txt file; the
third column is for pedestrians id, which is the name of the corresponding subfolder in the bbox_train folder;
the fourth column is the corresponding camera id (a total of 6 cameras).
Pay attention to comparing the two pictures~
1.3.4 tracks_train_info.mat
After opening this file with matlab, you can see that it is a 12180 * 4 matrix.
Each row of the matrix represents a tracklet; the
first and second columns represent the serial number of the picture, which corresponds to the row number in the test_name.txt file; the
third column is the id of the pedestrian, which is in the bbox_test folder The name of the corresponding subfolder;
the fourth column is the corresponding camera id (a total of 6 cameras).
Similar to the above~
1.3.5 query_IDX.mat
After opening this file with matlab, you can see that it is a 1 * 1980 matrix (choose 1980 query ids), and you can see that each column corresponds to the first few rows in the tracks_test_info.mat file above .
For example, the value in the 1978 column is 12177, which corresponds to line 12177 in the tracks_test_info.mat file (one line corresponds to one tracks).
In line 12177, you can see its id=1496 (pedestrian id). It is not difficult to find that the lines with the same id=1496 also have 12166, 12167, etc. (a pedestrian corresponds to multiple trajectories).
In fact, this means that in the subfolder named 1496 (the pedestrian id is 1496), there are multiple short videos (tracklets).
It is worth noting that not all query sets id, the gallery has a row corresponding to the pedestrian with the same id. Among the 1980 query ids, the number of valid ids (there are rows with the same id in the gallery) = 1840.
In other words, there is only 1 tracklet in some folders.
1.4 Summary
In general:
- One training set corresponds to multiple pedestrian ids, one id corresponds to multiple tracks, and one track corresponds to multiple pictures.
- There is no duplicate pedestrian id in training set and test level
- The selected part of the test set is used as query
2.mars data set management data_manager
When introducing pedestrian re-recognition earlier, this part is also included. The purpose is to encapsulate the mars data set in the hard disk into the dataset.
Most of the methods are the same, just paste the code directly:
# 导入相关包
from __future__ import print_function, absolute_import
import os
import glob
import re
import sys
import urllib
import tarfile
import zipfile
import os.path as osp
from scipy.io import loadmat
import numpy as np
import random
from utils.util import mkdir_if_missing, write_json, read_json
"""Dataset classes"""
# 定义类方法
class Mars(object):
"""
MARS
Reference:
Zheng et al. MARS: A Video Benchmark for Large-Scale Person Re-identification. ECCV 2016.
Dataset statistics:
# identities: 1261
# tracklets: 8298 (train) + 1980 (query) + 9330 (gallery)
# cameras: 6
Args:
min_seq_len (int): tracklet with length shorter than this value will be discarded (default: 0).
"""
# 设置mars路径 这个要根据自己文件夹中存放数据集的位置
root = '/home/user/桌面/code/data/mars'
# 读取对应文件夹路径
train_name_path = osp.join(root, 'info/train_name.txt')
test_name_path = osp.join(root, 'info/test_name.txt')
track_train_info_path = osp.join(root, 'info/tracks_train_info.mat')
track_test_info_path = osp.join(root, 'info/tracks_test_info.mat')
query_IDX_path = osp.join(root, 'info/query_IDX.mat')
# 初始化类方法
def __init__(self, min_seq_len=0):
# 1 提高工程性 确保文件都存在
self._check_before_run()
# 2 prepare meta data
# 获得所有的训练集图片名字,放在train_names列表中;
# 获取所有测试集图片名字,放在test_names 列表中。
train_names = self._get_names(self.train_name_path)
test_names = self._get_names(self.test_name_path)
# 使用loadmat()函数读取.mat文件,它读取出来的data是字典格式的,通过['track_train_info']这个key,找到对应的value。获得的是一个数组格式数据。
track_train = loadmat(self.track_train_info_path)['track_train_info'] # numpy.ndarray (8298, 4) 8298tracks 4:start、end、id、cid
track_test = loadmat(self.track_test_info_path)['track_test_info'] # numpy.ndarray (12180, 4) 12180tracks 4:start、end、id、cid
query_IDX = loadmat(self.query_IDX_path)['query_IDX'].squeeze() # numpy.ndarray (1980,)
# 查询集的行号减一,跟track_test中的行号索引保持一致。
query_IDX -= 1 # index from 0
# 根据 query_IDX行号索引,找到track_test中对应行的数据 numpy.ndarray (1980, 4)
track_query = track_test[query_IDX,:]
# 图库集的行号 = 原始的track_test行号 - query_IDX中包含的行号
gallery_IDX = [i for i in range(track_test.shape[0]) if i not in query_IDX]
# 根据图库集行号,在track_test中找到对应行的数据,numpy.ndarray (1980, 4)
track_gallery = track_test[gallery_IDX,:]
# 3 数据处理
train, num_train_tracklets, num_train_pids, num_train_imgs = \
self._process_data(train_names, track_train, home_dir='bbox_train', relabel=True, min_seq_len=min_seq_len)
query, num_query_tracklets, num_query_pids, num_query_imgs = \
self._process_data(test_names, track_query, home_dir='bbox_test', relabel=False, min_seq_len=min_seq_len)
gallery, num_gallery_tracklets, num_gallery_pids, num_gallery_imgs = \
self._process_data(test_names, track_gallery, home_dir='bbox_test', relabel=False, min_seq_len=min_seq_len)
num_imgs_per_tracklet = num_train_imgs + num_query_imgs + num_gallery_imgs
min_num = np.min(num_imgs_per_tracklet)
max_num = np.max(num_imgs_per_tracklet)
avg_num = np.mean(num_imgs_per_tracklet)
num_total_pids = num_train_pids + num_query_pids
num_total_tracklets = num_train_tracklets + num_query_tracklets + num_gallery_tracklets
print("=> MARS loaded")
print("Dataset statistics:")
print(" ------------------------------")
print(" subset | # ids | # tracklets")
print(" ------------------------------")
print(" train | {:5d} | {:8d}".format(num_train_pids, num_train_tracklets))
print(" query | {:5d} | {:8d}".format(num_query_pids, num_query_tracklets))
print(" gallery | {:5d} | {:8d}".format(num_gallery_pids, num_gallery_tracklets))
print(" ------------------------------")
print(" total | {:5d} | {:8d}".format(num_total_pids, num_total_tracklets))
print(" number of images per tracklet: {} ~ {}, average {:.1f}".format(min_num, max_num, avg_num))
print(" ------------------------------")
self.train = train
self.query = query
self.gallery = gallery
self.num_train_pids = num_train_pids
self.num_query_pids = num_query_pids
self.num_gallery_pids = num_gallery_pids
# 检验文件是否存在
def _check_before_run(self):
"""Check if all files are available before going deeper"""
if not osp.exists(self.root):
raise RuntimeError("'{}' is not available".format(self.root))
if not osp.exists(self.train_name_path):
raise RuntimeError("'{}' is not available".format(self.train_name_path))
if not osp.exists(self.test_name_path):
raise RuntimeError("'{}' is not available".format(self.test_name_path))
if not osp.exists(self.track_train_info_path):
raise RuntimeError("'{}' is not available".format(self.track_train_info_path))
if not osp.exists(self.track_test_info_path):
raise RuntimeError("'{}' is not available".format(self.track_test_info_path))
if not osp.exists(self.query_IDX_path):
raise RuntimeError("'{}' is not available".format(self.query_IDX_path))
# 获取txt文件中的字符串(图片名字),放在names列表中。
def _get_names(self, fpath):
names = []
with open(fpath, 'r') as f:
for line in f:
new_line = line.rstrip()
names.append(new_line)
return names
# 对获得的数据按照规则进行截断 获得tracklets, num_tracklets, num_pids, num_imgs_per_tracklet
def _process_data(self, names, meta_data, home_dir=None, relabel=False, min_seq_len=0):
assert home_dir in ['bbox_train', 'bbox_test']
num_tracklets = meta_data.shape[0]
pid_list = list(set(meta_data[:,2].tolist()))
num_pids = len(pid_list)
if relabel: pid2label = {
pid:label for label, pid in enumerate(pid_list)}
tracklets = []
num_imgs_per_tracklet = []
#txt_name = self.root + home_dir + str(len(meta_data)) + '.txt'
#fid = open(txt_name, "w")
for tracklet_idx in range(num_tracklets):
data = meta_data[tracklet_idx,...]
start_index, end_index, pid, camid = data
if pid == -1: continue # junk images are just ignored
assert 1 <= camid <= 6
if relabel: pid = pid2label[pid]
camid -= 1 # index starts from 0
img_names = names[start_index-1:end_index]
# make sure image names correspond to the same person
pnames = [img_name[:4] for img_name in img_names]
assert len(set(pnames)) == 1, "Error: a single tracklet contains different person images"
# make sure all images are captured under the same camera
camnames = [img_name[5] for img_name in img_names]
assert len(set(camnames)) == 1, "Error: images are captured under different cameras!"
# append image names with directory information
img_paths = [osp.join(self.root, home_dir, img_name[:4], img_name) for img_name in img_names]
if len(img_paths) >= min_seq_len:
img_paths = tuple(img_paths)
tracklets.append((img_paths, pid, camid))
num_imgs_per_tracklet.append(len(img_paths))
#fid.write(img_names[0] + '\n')
#fid.close()
num_tracklets = len(tracklets)
return tracklets, num_tracklets, num_pids, num_imgs_per_tracklet
"""Create dataset"""
__factory = {
'mars': Mars,
'ilidsvid': iLIDSVID,
'prid': PRID,
}
def get_names():
return __factory.keys()
def init_dataset(name, *args, **kwargs):
if name not in __factory.keys():
raise KeyError("Unknown dataset: {}".format(name))
return __factory[name](*args, **kwargs)
# test
if __name__ == '__main__':
init_dataset(name="mars")
#dataset = Market1501()
#dataset = Mars()
Result:
Explanation:
- Training set:
- 625 ids, 8298 trajectories in total
- Test set:
- Query 626 id selected 1980 tracks (not all valid, a pedestrian may only have one track)
- gallery 622 id, the remaining 9330 trajectories
A total of 1251 pedestrian ids, train+query, 8298+1980+9330=19608 trajectories