2 from __future__
import division, print_function, absolute_import
10 from application_util
import preprocessing
11 from application_util
import visualization
12 from deep_sort
import nn_matching
18 """Gather sequence information, such as image filenames, detections, 19 groundtruth (if available). 24 Path to the MOTChallenge sequence directory. 26 Path to the detection file. 31 A dictionary of the following sequence information: 33 * sequence_name: Name of the sequence 34 * image_filenames: A dictionary that maps frame indices to image 36 * detections: A numpy array of detections in MOTChallenge format. 37 * groundtruth: A numpy array of ground truth in MOTChallenge format. 38 * image_size: Image size (height, width). 39 * min_frame_idx: Index of the first frame. 40 * max_frame_idx: Index of the last frame. 43 image_dir = os.path.join(sequence_dir,
"img1")
45 int(os.path.splitext(f)[0]): os.path.join(image_dir, f)
46 for f
in os.listdir(image_dir)}
47 groundtruth_file = os.path.join(sequence_dir,
"gt/gt.txt")
50 if detection_file
is not None:
51 detections = np.load(detection_file)
53 if os.path.exists(groundtruth_file):
54 groundtruth = np.loadtxt(groundtruth_file, delimiter=
',')
56 if len(image_filenames) > 0:
57 image = cv2.imread(next(iter(image_filenames.values())),
59 image_size = image.shape
63 if len(image_filenames) > 0:
64 min_frame_idx = min(image_filenames.keys())
65 max_frame_idx = max(image_filenames.keys())
67 min_frame_idx =
int(detections[:, 0].min())
68 max_frame_idx =
int(detections[:, 0].max())
70 info_filename = os.path.join(sequence_dir,
"seqinfo.ini")
71 if os.path.exists(info_filename):
72 with open(info_filename,
"r") as f: 73 line_splits = [l.split('=')
for l
in f.read().splitlines()[1:]]
75 s
for s
in line_splits
if isinstance(s, list)
and len(s) == 2)
77 update_ms = 1000 /
int(info_dict[
"frameRate"])
81 feature_dim = detections.shape[1] - 10
if detections
is not None else 0
83 "sequence_name": os.path.basename(sequence_dir),
84 "image_filenames": image_filenames,
85 "detections": detections,
86 "groundtruth": groundtruth,
87 "image_size": image_size,
88 "min_frame_idx": min_frame_idx,
89 "max_frame_idx": max_frame_idx,
90 "feature_dim": feature_dim,
91 "update_ms": update_ms
97 """Create detections for given frame index from the raw detection matrix. 101 detection_mat : ndarray 102 Matrix of detections. The first 10 columns of the detection matrix are 103 in the standard MOTChallenge detection format. In the remaining columns 104 store the feature vector associated with each detection. 107 min_height : Optional[int] 108 A minimum detection bounding box height. Detections that are smaller 109 than this value are disregarded. 113 List[tracker.Detection] 114 Returns detection responses at given frame index. 117 frame_indices = detection_mat[:, 0].astype(np.int)
118 mask = frame_indices == frame_idx
121 for row
in detection_mat[mask]:
122 bbox, confidence, feature = row[2:6], row[6], row[10:]
123 if bbox[3] < min_height:
125 detection_list.append(
Detection(bbox, confidence, feature))
126 return detection_list
129 def run(sequence_dir, detection_file, output_file, min_confidence,
130 nms_max_overlap, min_detection_height, max_cosine_distance,
132 """Run multi-target tracker on a particular sequence. 137 Path to the MOTChallenge sequence directory. 139 Path to the detections file. 141 Path to the tracking output file. This file will contain the tracking 142 results on completion. 143 min_confidence : float 144 Detection confidence threshold. Disregard all detections that have 145 a confidence lower than this value. 146 nms_max_overlap: float 147 Maximum detection overlap (non-maxima suppression threshold). 148 min_detection_height : int 149 Detection height threshold. Disregard all detections that have 150 a height lower than this value. 151 max_cosine_distance : float 152 Gating threshold for cosine distance metric (object appearance). 153 nn_budget : Optional[int] 154 Maximum size of the appearance descriptor gallery. If None, no budget 157 If True, show visualization of intermediate tracking results. 161 metric = nn_matching.NearestNeighborDistanceMetric(
162 "cosine", max_cosine_distance, nn_budget)
166 def frame_callback(vis, frame_idx):
167 print(
"Processing frame %05d" % frame_idx)
171 seq_info[
"detections"], frame_idx, min_detection_height)
172 detections = [d
for d
in detections
if d.confidence >= min_confidence]
175 boxes = np.array([d.tlwh
for d
in detections])
176 scores = np.array([d.confidence
for d
in detections])
177 indices = preprocessing.non_max_suppression(
178 boxes, nms_max_overlap, scores)
179 detections = [detections[i]
for i
in indices]
183 tracker.update(detections)
188 seq_info[
"image_filenames"][frame_idx], cv2.IMREAD_COLOR)
189 vis.set_image(image.copy())
190 vis.draw_detections(detections)
191 vis.draw_trackers(tracker.tracks)
194 for track
in tracker.tracks:
195 if not track.is_confirmed()
or track.time_since_update > 1:
197 bbox = track.to_tlwh()
199 frame_idx, track.track_id, bbox[0], bbox[1], bbox[2], bbox[3]])
203 visualizer = visualization.Visualization(seq_info, update_ms=5)
205 visualizer = visualization.NoVisualization(seq_info)
206 visualizer.run(frame_callback)
209 f = open(output_file,
'w')
211 print(
'%d,%d,%.2f,%.2f,%.2f,%.2f,1,-1,-1,-1' % (
212 row[0], row[1], row[2], row[3], row[4], row[5]),file=f)
216 """ Parse command line arguments. 218 parser = argparse.ArgumentParser(description=
"Deep SORT")
220 "--sequence_dir", help=
"Path to MOTChallenge sequence directory",
221 default=
None, required=
True)
223 "--detection_file", help=
"Path to custom detections.", default=
None,
226 "--output_file", help=
"Path to the tracking output file. This file will" 227 " contain the tracking results on completion.",
228 default=
"/tmp/hypotheses.txt")
230 "--min_confidence", help=
"Detection confidence threshold. Disregard " 231 "all detections that have a confidence lower than this value.",
232 default=0.8, type=float)
234 "--min_detection_height", help=
"Threshold on the detection bounding " 235 "box height. Detections with height smaller than this value are " 236 "disregarded", default=0, type=int)
238 "--nms_max_overlap", help=
"Non-maxima suppression threshold: Maximum " 239 "detection overlap.", default=1.0, type=float)
241 "--max_cosine_distance", help=
"Gating threshold for cosine distance " 242 "metric (object appearance).", type=float, default=0.2)
244 "--nn_budget", help=
"Maximum size of the appearance descriptors " 245 "gallery. If None, no budget is enforced.", type=int, default=
None)
247 "--display", help=
"Show intermediate tracking results",
248 default=
True, type=bool)
249 return parser.parse_args()
252 if __name__ ==
"__main__":
255 args.sequence_dir, args.detection_file, args.output_file,
256 args.min_confidence, args.nms_max_overlap, args.min_detection_height,
257 args.max_cosine_distance, args.nn_budget, args.display)
def create_detections(detection_mat, frame_idx, min_height=0)
def run(sequence_dir, detection_file, output_file, min_confidence, nms_max_overlap, min_detection_height, max_cosine_distance, nn_budget, display)
def gather_sequence_info(sequence_dir, detection_file)