diff --git a/motmetrics/apps/eval_detrac.py b/motmetrics/apps/eval_detrac.py index 9da4676..94ab8ef 100644 --- a/motmetrics/apps/eval_detrac.py +++ b/motmetrics/apps/eval_detrac.py @@ -19,6 +19,7 @@ from pathlib import Path import motmetrics as mm +from motmetrics.utils import is_in_region def parse_args(): @@ -67,6 +68,16 @@ def parse_args(): return parser.parse_args() +def filter_dets_by_zone(gt_df, test_df): + ig_region = gt_df[['X_reg', 'Y_reg', 'W_reg', 'H_reg']].dropna().values + dets = test_df[['X', 'Y', 'Width', 'Height']] + for idx, row in dets.iterrows(): + bbox = [dets.at[idx, 'X'], dets.at[idx, 'Y'], dets.at[idx, 'Width'], dets.at[idx, 'Height']] + for reg in ig_region: + if is_in_region(bbox, reg): + test_df.drop([idx], axis=0, inplace=True) + break + def compare_dataframes(gts, ts): """Builds accumulator for each sequence.""" accs = [] @@ -74,6 +85,7 @@ def compare_dataframes(gts, ts): for k, tsacc in ts.items(): if k in gts: logging.info('Comparing %s...', k) + filter_dets_by_zone(gts[k], tsacc) accs.append(mm.utils.compare_to_groundtruth(gts[k], tsacc, 'iou', distth=0.5)) names.append(k) else: diff --git a/motmetrics/io.py b/motmetrics/io.py index ca29c6a..99a6ce1 100644 --- a/motmetrics/io.py +++ b/motmetrics/io.py @@ -19,6 +19,8 @@ import scipy.io import xmltodict +from motmetrics.utils import is_in_region + class Format(Enum): """Enumerates supported file formats.""" @@ -271,6 +273,18 @@ def load_detrac_xml(fname): with io.open(fname) as fd: doc = xmltodict.parse(fd.read()) frameList = doc['sequence']['frame'] + ignored_region_list = doc['sequence']['ignored_region'] + if type(ignored_region_list['box']) != list: + ignored_region_list['box'] = [ignored_region_list['box']] + + parsed_ig = [] + for ig in ignored_region_list['box']: + row = [] + row.append(float(ig['@left'])) + row.append(float(ig['@top'])) + row.append(float(ig['@width'])) + row.append(float(ig['@height'])) + parsed_ig.append(row) parsedGT = [] for f in frameList: @@ -280,6 +294,7 @@ def load_detrac_xml(fname): targetList = [targetList] for t in targetList: + flag_ignore = False row = [] row.append(fid) row.append(int(t['@id'])) @@ -291,10 +306,20 @@ def load_detrac_xml(fname): row.append(-1) row.append(-1) row.append(-1) - parsedGT.append(row) + bbox = [row[2], row[3], row[4], row[5]] + for reg in parsed_ig: + if is_in_region(bbox, reg): + flag_ignore = True + break + if not flag_ignore: + parsedGT.append(row) df = pd.DataFrame(parsedGT, columns=['FrameId', 'Id', 'X', 'Y', 'Width', 'Height', 'Confidence', 'ClassId', 'Visibility', 'unused']) + + df_reg = pd.DataFrame(parsed_ig, columns=['X_reg', 'Y_reg', 'W_reg', 'H_reg']) + df = df.append(df_reg) + df.set_index(['FrameId', 'Id'], inplace=True) # Account for matlab convention. diff --git a/motmetrics/utils.py b/motmetrics/utils.py index 520573a..621595e 100644 --- a/motmetrics/utils.py +++ b/motmetrics/utils.py @@ -12,6 +12,8 @@ from __future__ import print_function import numpy as np +from shapely.geometry import Point +from shapely.geometry.polygon import Polygon from motmetrics.distances import iou_matrix, norm2squared_matrix from motmetrics.mot import MOTAccumulator @@ -176,3 +178,41 @@ def compute_euc(a, b): acc.update(oids, hids, dists, frameid=fid, vf=vflag) return acc, analysis + + +def is_in_region(bbox, reg): + # Check if the 4 points of the bbox are inside region + points = [] + # Center + cx = bbox[0] + (bbox[2] / 2) + cy = bbox[1] + (bbox[3] / 2) + points.append(Point(cx, cy)) + # # Top-left + # x1 = bbox[0] + # y1 = bbox[1] + # points.append(Point(x1, y1)) + # # Top-right + # x1 = bbox[0] + bbox[2] + # y1 = bbox[1] + # points.append(Point(x1, y1)) + # # Bot-right + # x1 = bbox[0] + bbox[2] + # y1 = bbox[1] + bbox[3] + # points.append(Point(x1, y1)) + # # Bot-left + # x1 = bbox[0] + # y1 = bbox[1] + bbox[3] + # points.append(Point(x1, y1)) + + # Region + p_xy0 = (reg[0], reg[1]) + p_xy1 = (reg[0] + reg[2], reg[1]) + p_xy2 = (reg[0] + reg[2], reg[1] + reg[3]) + p_xy3 = (reg[0], reg[1] + reg[3]) + region = [p_xy0, p_xy1, p_xy2, p_xy3] + polygon = Polygon(region) + + flags_inside = [polygon.contains(p) for p in points] + flag_inside = all(flags_inside) + + return flag_inside