Disparity calculation (#12)

* add filter for z < 40

* change figure name

* stereo results in figure

* stereo figure

* pylint

* pylint(2)

* pylint updated
This commit is contained in:
Lorenzo Bertoni 2019-10-07 11:28:54 +02:00 committed by GitHub
parent 4071971e48
commit 39eef3195b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 77 additions and 57 deletions

View File

@ -113,7 +113,7 @@ class EvalKitti:
def printer(self, show, save): def printer(self, show, save):
if save or show: if save or show:
show_results(self.dic_stats, show, save) show_results(self.dic_stats, show, save, stereo=self.stereo)
show_spread(self.dic_stats, show, save) show_spread(self.dic_stats, show, save)
show_task_error(show, save) show_task_error(show, save)
@ -178,7 +178,7 @@ class EvalKitti:
self.update_uncertainty(stds_ale[idx], stds_epi[idx], dds[idx], dds_gt[idx_gt], cat) self.update_uncertainty(stds_ale[idx], stds_epi[idx], dds[idx], dds_gt[idx_gt], cat)
dd_task_error = dds_gt[idx_gt] + (get_task_error(dds_gt[idx_gt]))**2 dd_task_error = dds_gt[idx_gt] + (get_task_error(dds_gt[idx_gt]))**2
self.update_errors(dd_task_error, dds_gt[idx_gt], cat, self.errors['task_error']) self.update_errors(dd_task_error, dds_gt[idx_gt], cat, self.errors['task_error'])
dd_pixel_error = get_pixel_error(dds_gt[idx_gt], zzs_gt[idx_gt]) dd_pixel_error = dds_gt[idx_gt] + get_pixel_error(zzs_gt[idx_gt])
self.update_errors(dd_pixel_error, dds_gt[idx_gt], cat, self.errors['pixel_error']) self.update_errors(dd_pixel_error, dds_gt[idx_gt], cat, self.errors['pixel_error'])
def _compare_error(self, out_gt, methods_out): def _compare_error(self, out_gt, methods_out):
@ -211,7 +211,7 @@ class EvalKitti:
self.update_errors(dd_monoloco, dd_gt, cat, self.errors['monoloco_merged']) self.update_errors(dd_monoloco, dd_gt, cat, self.errors['monoloco_merged'])
self.update_errors(dd_geometric, dd_gt, cat, self.errors['geometric_merged']) self.update_errors(dd_geometric, dd_gt, cat, self.errors['geometric_merged'])
self.update_errors(dd_gt + get_task_error(dd_gt), dd_gt, cat, self.errors['task_error_merged']) self.update_errors(dd_gt + get_task_error(dd_gt), dd_gt, cat, self.errors['task_error_merged'])
dd_pixel = get_pixel_error(dd_gt, zzs_gt[idx_gt]) dd_pixel = dd_gt + get_pixel_error(zzs_gt[idx_gt])
self.update_errors(dd_pixel, dd_gt, cat, self.errors['pixel_error_merged']) self.update_errors(dd_pixel, dd_gt, cat, self.errors['pixel_error_merged'])
for key in self.methods: for key in self.methods:

View File

@ -20,7 +20,7 @@ def baselines_association(baselines, zzs, keypoints, keypoints_right, reid_featu
keypoints, keypoints_right, baselines, reid_features) keypoints, keypoints_right, baselines, reid_features)
# count maximum possible associations # count maximum possible associations
cnt_stereo['max'] = min(keypoints.shape[0], keypoints_r.shape[0]) cnt_stereo['max'] = min(keypoints.shape[0], keypoints_r.shape[0]) # pylint: disable=E1136
# Filter joints disparity and calculate avg disparity # Filter joints disparity and calculate avg disparity
avg_disparities, disparities_x, disparities_y = mask_joint_disparity(keypoints, keypoints_r) avg_disparities, disparities_x, disparities_y = mask_joint_disparity(keypoints, keypoints_r)
@ -161,7 +161,8 @@ def verify_stereo(zz_stereo, zz_mono, disparity_x, disparity_y):
if abs(zz_stereo - zz_mono) < z_max_difference and \ if abs(zz_stereo - zz_mono) < z_max_difference and \
avg_disparity_y < y_max_difference and \ avg_disparity_y < y_max_difference and \
cov < COV_MIN: cov < COV_MIN\
and 4 < zz_stereo < 40:
return True return True
# if not np.isnan(zz_stereo): # if not np.isnan(zz_stereo):
# return True # return True

View File

@ -128,7 +128,7 @@ def main():
elif args.command == 'eval': elif args.command == 'eval':
if args.geometric: if args.geometric:
assert args.joints, "joints argument not provided" assert args.joints, "joints argument not provided"
from .eval import geometric_baseline from .eval import geometric_baseline
geometric_baseline(args.joints) geometric_baseline(args.joints)

View File

@ -231,7 +231,7 @@ class Trainer:
# Debug plot for input-output distributions # Debug plot for input-output distributions
if debug: if debug:
debug_plots(inputs, labels) debug_plots(inputs, labels)
exit() sys.exit()
# Forward pass # Forward pass
outputs = self.model(inputs) outputs = self.model(inputs)

View File

@ -93,8 +93,9 @@ def check_conditions(line, category, method, thresh=0.3):
check = True check = True
else: else:
zz = float(line[13])
conf = float(line[15]) conf = float(line[15])
if conf >= thresh: if conf >= thresh and 0.5 < zz < 70:
check = True check = True
return check return check

View File

@ -30,12 +30,12 @@ def get_task_error(dd):
return dd * mm return dd * mm
def get_pixel_error(dd_gt, zz_gt): def get_pixel_error(zz_gt):
"""calculate error in stereo distance due to 1 pixel mismatch (function of depth)""" """calculate error in stereo distance due to 1 pixel mismatch (function of depth)"""
disp = 0.54 * 721 / zz_gt disp = 0.54 * 721 / zz_gt
delta_z = zz_gt - 0.54 * 721 / (disp - 1) error = abs(zz_gt - 0.54 * 721 / (disp - 1))
return dd_gt + delta_z return error
def open_annotations(path_ann): def open_annotations(path_ann):

View File

@ -1,4 +1,3 @@
# pylint: disable=R0915 # pylint: disable=R0915
import math import math
@ -9,11 +8,10 @@ import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse from matplotlib.patches import Ellipse
from ..utils import get_task_error from ..utils import get_task_error, get_pixel_error
def show_results(dic_stats, show=False, save=False): def show_results(dic_stats, show=False, save=False, stereo=False):
""" """
Visualize error as function of the distance and compare it with target errors based on human height analyses Visualize error as function of the distance and compare it with target errors based on human height analyses
""" """
@ -22,40 +20,41 @@ def show_results(dic_stats, show=False, save=False):
phase = 'test' phase = 'test'
x_min = 0 x_min = 0
x_max = 38 x_max = 38
y_min = 0
y_max = 4.7
xx = np.linspace(0, 60, 100) xx = np.linspace(0, 60, 100)
excl_clusters = ['all', '50', '>50', 'easy', 'moderate', 'hard'] excl_clusters = ['all', '50', '>50', 'easy', 'moderate', 'hard']
clusters = tuple([clst for clst in dic_stats[phase]['monoloco'] if clst not in excl_clusters]) clusters = tuple([clst for clst in dic_stats[phase]['monoloco'] if clst not in excl_clusters])
yy_gender = get_task_error(xx) yy_gender = get_task_error(xx)
plt.figure(0) styles = printing_styles(stereo)
plt.grid(linewidth=0.2) for idx_style, (key, style) in enumerate(styles.items()):
plt.xlabel("Ground-truth distance [m]") plt.figure(idx_style)
plt.ylabel("Average localization error [m]") plt.grid(linewidth=0.2)
plt.xlim(x_min, x_max) plt.xlim(x_min, x_max)
labels = ['Mono3D', 'Geometric Baseline', 'MonoDepth', 'Our MonoLoco', '3DOP (stereo)'] plt.ylim(y_min, y_max)
mks = ['*', '^', 'p', 's', 'o'] plt.xlabel("Ground-truth distance [m]")
mksizes = [6, 6, 6, 6, 6] plt.ylabel("Average localization error [m]")
lws = [1.5, 1.5, 1.5, 2.2, 1.6] for idx, method in enumerate(style['methods']):
colors = ['r', 'deepskyblue', 'grey', 'b', 'darkorange'] errs = [dic_stats[phase][method][clst]['mean'] for clst in clusters]
lstyles = ['solid', 'solid', 'solid', 'solid', 'dashdot'] assert errs, "method %s empty" % method
xxs = get_distances(clusters)
for idx, method in enumerate(['m3d_merged', 'geometric_merged', 'monodepth_merged', 'monoloco_merged', plt.plot(xxs, errs, marker=style['mks'][idx], markersize=style['mksizes'][idx], linewidth=style['lws'][idx],
'3dop_merged']): label=style['labels'][idx], linestyle=style['lstyles'][idx], color=style['colors'][idx])
errs = [dic_stats[phase][method][clst]['mean'] for clst in clusters] plt.plot(xx, yy_gender, '--', label="Task error", color='lightgreen', linewidth=2.5)
assert errs, "method %s empty" % method if key == 'stereo':
xxs = get_distances(clusters) yy_stereo = get_pixel_error(xx)
plt.plot(xx, yy_stereo, linewidth=1.7, color='k', label='Pixel error')
plt.plot(xxs, errs, marker=mks[idx], markersize=mksizes[idx], linewidth=lws[idx], label=labels[idx], plt.legend(loc='upper left')
linestyle=lstyles[idx], color=colors[idx]) if save:
plt.plot(xx, yy_gender, '--', label="Task error", color='lightgreen', linewidth=2.5) path_fig = os.path.join(dir_out, 'results_' + key + '.png')
plt.legend(loc='upper left') plt.savefig(path_fig)
if save: print("Figure of results " + key + " saved in {}".format(path_fig))
path_fig = os.path.join(dir_out, 'results.png') if show:
plt.savefig(path_fig) plt.show()
print("Figure of results saved in {}".format(path_fig)) plt.close()
if show:
plt.show()
plt.close()
def show_spread(dic_stats, show=False, save=False): def show_spread(dic_stats, show=False, save=False):
@ -66,7 +65,7 @@ def show_spread(dic_stats, show=False, save=False):
excl_clusters = ['all', '50', '>50', 'easy', 'moderate', 'hard'] excl_clusters = ['all', '50', '>50', 'easy', 'moderate', 'hard']
clusters = tuple([clst for clst in dic_stats[phase]['our'] if clst not in excl_clusters]) clusters = tuple([clst for clst in dic_stats[phase]['our'] if clst not in excl_clusters])
plt.figure(1) plt.figure(2)
fig, ax = plt.subplots(2, sharex=True) fig, ax = plt.subplots(2, sharex=True)
plt.xlabel("Distance [m]") plt.xlabel("Distance [m]")
plt.ylabel("Aleatoric uncertainty [m]") plt.ylabel("Aleatoric uncertainty [m]")
@ -80,10 +79,10 @@ def show_spread(dic_stats, show=False, save=False):
yys = get_task_error(np.array(xxs)) yys = get_task_error(np.array(xxs))
ax[1].plot(xxs, bbs, marker='s', color='b', label="Spread b") ax[1].plot(xxs, bbs, marker='s', color='b', label="Spread b")
ax[1].plot(xxs, yys, '--', color='lightgreen', label="Task error", linewidth=2.5) ax[1].plot(xxs, yys, '--', color='lightgreen', label="Task error", linewidth=2.5)
yys_up = [rec_c + ar/2 * scale * yy for yy in yys] yys_up = [rec_c + ar / 2 * scale * yy for yy in yys]
bbs_up = [rec_c + ar/2 * scale * bb for bb in bbs] bbs_up = [rec_c + ar / 2 * scale * bb for bb in bbs]
yys_down = [rec_c - ar/2 * scale * yy for yy in yys] yys_down = [rec_c - ar / 2 * scale * yy for yy in yys]
bbs_down = [rec_c - ar/2 * scale * bb for bb in bbs] bbs_down = [rec_c - ar / 2 * scale * bb for bb in bbs]
if plots_line: if plots_line:
ax[0].plot(xxs, yys_up, '--', color='lightgreen', markersize=5, linewidth=1.4) ax[0].plot(xxs, yys_up, '--', color='lightgreen', markersize=5, linewidth=1.4)
@ -92,8 +91,8 @@ def show_spread(dic_stats, show=False, save=False):
ax[0].plot(xxs, bbs_down, marker='s', color='b', markersize=5, linewidth=0.7) ax[0].plot(xxs, bbs_down, marker='s', color='b', markersize=5, linewidth=0.7)
for idx, xx in enumerate(xxs): for idx, xx in enumerate(xxs):
te = Ellipse((xx, rec_c), width=yys[idx]*ar*scale, height=scale, angle=90, color='lightgreen', fill=True) te = Ellipse((xx, rec_c), width=yys[idx] * ar * scale, height=scale, angle=90, color='lightgreen', fill=True)
bi = Ellipse((xx, rec_c), width=bbs[idx]*ar*scale, height=scale, angle=90, color='b', linewidth=1.8, bi = Ellipse((xx, rec_c), width=bbs[idx] * ar * scale, height=scale, angle=90, color='b', linewidth=1.8,
fill=False) fill=False)
ax[0].add_patch(te) ax[0].add_patch(te)
@ -113,9 +112,9 @@ def show_spread(dic_stats, show=False, save=False):
def show_task_error(show, save): def show_task_error(show, save):
"""Task error figure""" """Task error figure"""
plt.figure(2) plt.figure(3)
dir_out = 'docs' dir_out = 'docs'
xx = np.linspace(0, 40, 100) xx = np.linspace(0.1, 50, 100)
mu_men = 178 mu_men = 178
mu_women = 165 mu_women = 165
mu_child_m = 164 mu_child_m = 164
@ -128,12 +127,14 @@ def show_task_error(show, save):
yy_young_male = target_error(xx, mm_young_male) yy_young_male = target_error(xx, mm_young_male)
yy_young_female = target_error(xx, mm_young_female) yy_young_female = target_error(xx, mm_young_female)
yy_gender = target_error(xx, mm_gmm) yy_gender = target_error(xx, mm_gmm)
yy_stereo = get_pixel_error(xx)
plt.grid(linewidth=0.3) plt.grid(linewidth=0.3)
plt.plot(xx, yy_young_male, linestyle='dotted', linewidth=2.1, color='b', label='Adult/young male') plt.plot(xx, yy_young_male, linestyle='dotted', linewidth=2.1, color='b', label='Adult/young male')
plt.plot(xx, yy_young_female, linestyle='dotted', linewidth=2.1, color='darkorange', label='Adult/young female') plt.plot(xx, yy_young_female, linestyle='dotted', linewidth=2.1, color='darkorange', label='Adult/young female')
plt.plot(xx, yy_gender, '--', color='lightgreen', linewidth=2.8, label='Generic adult (task error)') plt.plot(xx, yy_gender, '--', color='lightgreen', linewidth=2.8, label='Generic adult (task error)')
plt.plot(xx, yy_female, '-.', linewidth=1.7, color='darkorange', label='Adult female') plt.plot(xx, yy_female, '-.', linewidth=1.7, color='darkorange', label='Adult female')
plt.plot(xx, yy_male, '-.', linewidth=1.7, color='b', label='Adult male') plt.plot(xx, yy_male, '-.', linewidth=1.7, color='b', label='Adult male')
plt.plot(xx, yy_stereo, linewidth=1.7, color='k', label='Pixel error')
plt.xlim(np.min(xx), np.max(xx)) plt.xlim(np.min(xx), np.max(xx))
plt.xlabel("Ground-truth distance from the camera $d_{gt}$ [m]") plt.xlabel("Ground-truth distance from the camera $d_{gt}$ [m]")
plt.ylabel("Localization error $\hat{e}$ due to human height variation [m]") # pylint: disable=W1401 plt.ylabel("Localization error $\hat{e}$ due to human height variation [m]") # pylint: disable=W1401
@ -193,7 +194,6 @@ def calculate_gmm():
def get_confidence(xx, zz, std): def get_confidence(xx, zz, std):
theta = math.atan2(zz, xx) theta = math.atan2(zz, xx)
delta_x = std * math.cos(theta) delta_x = std * math.cos(theta)
@ -215,11 +215,9 @@ def get_distances(clusters):
def get_confidence_points(confidences, distances, errors): def get_confidence_points(confidences, distances, errors):
confidence_points = [] confidence_points = []
distance_points = [] distance_points = []
for idx, dd in enumerate(distances): for idx, dd in enumerate(distances):
conf_perc = confidences[idx] conf_perc = confidences[idx]
confidence_points.append(errors[idx] + conf_perc) confidence_points.append(errors[idx] + conf_perc)
confidence_points.append(errors[idx] - conf_perc) confidence_points.append(errors[idx] - conf_perc)
@ -230,7 +228,6 @@ def get_confidence_points(confidences, distances, errors):
def height_distributions(): def height_distributions():
mu_men = 178 mu_men = 178
std_men = 7 std_men = 7
mu_women = 165 mu_women = 165
@ -256,7 +253,7 @@ def expandgrid(*itrs):
def plot_dist(dist_gmm, dist_men, dist_women): def plot_dist(dist_gmm, dist_men, dist_women):
try: try:
import seaborn as sns import seaborn as sns # pylint: disable=C0415
sns.distplot(dist_men, hist=False, rug=False, label="Men") sns.distplot(dist_men, hist=False, rug=False, label="Men")
sns.distplot(dist_women, hist=False, rug=False, label="Women") sns.distplot(dist_women, hist=False, rug=False, label="Women")
sns.distplot(dist_gmm, hist=False, rug=False, label="GMM") sns.distplot(dist_gmm, hist=False, rug=False, label="GMM")
@ -273,9 +270,30 @@ def get_percentile(dist_gmm):
dd_gt = 1000 dd_gt = 1000
mu_gmm = np.mean(dist_gmm) mu_gmm = np.mean(dist_gmm)
dist_d = dd_gt * mu_gmm / dist_gmm dist_d = dd_gt * mu_gmm / dist_gmm
perc_d, _ = np.nanpercentile(dist_d, [18.5, 81.5]) # Laplace bi => 63% perc_d, _ = np.nanpercentile(dist_d, [18.5, 81.5]) # Laplace bi => 63%
perc_d2, _ = np.nanpercentile(dist_d, [23, 77]) perc_d2, _ = np.nanpercentile(dist_d, [23, 77])
mu_d = np.mean(dist_d) mu_d = np.mean(dist_d)
# mm_bi = (mu_d - perc_d) / mu_d # mm_bi = (mu_d - perc_d) / mu_d
# mm_test = (mu_d - perc_d2) / mu_d # mm_test = (mu_d - perc_d2) / mu_d
# mad_d = np.mean(np.abs(dist_d - mu_d)) # mad_d = np.mean(np.abs(dist_d - mu_d))
def printing_styles(stereo):
style = {'mono': {"labels": ['Mono3D', 'Geometric Baseline', 'MonoDepth', 'Our MonoLoco', '3DOP (stereo)'],
"methods": ['m3d_merged', 'geometric_merged', 'monodepth_merged', 'monoloco_merged',
'3dop_merged'],
"mks": ['*', '^', 'p', 's', 'o'],
"mksizes": [6, 6, 6, 6, 6], "lws": [1.5, 1.5, 1.5, 2.2, 1.6],
"colors": ['r', 'deepskyblue', 'grey', 'b', 'darkorange'],
"lstyles": ['solid', 'solid', 'solid', 'solid', 'dashdot']}}
if stereo:
style['stereo'] = {"labels": ['3DOP', 'Pose Baseline', 'ReiD Baseline', 'Our MonoLoco (monocular)',
'Our Stereo Baseline'],
"methods": ['3dop_merged', 'pose_merged', 'reid_merged', 'monoloco_merged',
'ml_stereo_merged'],
"mks": ['o', '^', 'p', 's', 's'],
"mksizes": [6, 6, 6, 4, 6], "lws": [1.5, 1.5, 1.5, 1.2, 1.5],
"colors": ['darkorange', 'lightblue', 'red', 'b', 'b'],
"lstyles": ['solid', 'solid', 'solid', 'dashed', 'solid']}
return style