Commit 313276ef authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: fopen_pose_compare.py — clean CSV/TSV output for Calc analysis

- flat column names (no _x_y_z suffix, single comparison set)
- XML angles in degrees (not radians) — more useful for Calc plotting
- auto TSV when --out ends in .tsv, CSV otherwise
- column comment block documents layout in the source
Co-authored-by: 's avatarClaude <claude@elphel.com>
parent 3c05de2f
......@@ -495,67 +495,68 @@ def main():
# ── CSV ────────────────────────────────────────────────────────────────
if args.out:
base_fields = [
# Column layout (all angles in degrees for easy Calc analysis):
# Identity : frame (0-based COLMAP), timestamp (seconds)
# COLMAP pos : colmap_X/Y/Z (native COLMAP units)
# XML pos (m) : xml_x/y/z (metres, relative to reference scene)
# XML angles : xml_az/tilt/roll (degrees; radians in source XML)
# Sim(3) align : aligned_X/Y/Z (XML pos mapped to COLMAP units)
# Pos residual : pos_res(colmap), pos_res(m)
# COLMAP orient: colmap_yaw/pitch/roll (deg, in Sim3-aligned GPS frame)
# Inter-frame Δ: delta_colmap/xml/diff (deg, convention-independent)
# Cumulative : cum_colmap/xml/diff (deg, integrated from frame 0)
fieldnames = [
'frame', 'timestamp',
'colmap_X', 'colmap_Y', 'colmap_Z',
'xml_x', 'xml_y', 'xml_z',
'xml_az_rad', 'xml_tilt_rad', 'xml_roll_rad',
'xml_az(deg)', 'xml_tilt(deg)', 'xml_roll(deg)',
'aligned_X', 'aligned_Y', 'aligned_Z',
'pos_res(colmap)', 'pos_res(m)',
'colmap_yaw(deg)', 'colmap_pitch(deg)', 'colmap_roll(deg)',
'delta_colmap(deg)', 'delta_xml(deg)', 'delta_diff(deg)',
'cum_colmap(deg)', 'cum_xml(deg)', 'cum_diff(deg)',
]
extra_fields = []
for label, _, _, _ in col_specs:
if label not in pos_results:
continue
k = label.replace(' ', '_').replace('/', '_')
extra_fields += [
f'pos_res_{k}(colmap)', f'pos_res_{k}(m)',
f'aligned_{k}_X', f'aligned_{k}_Y', f'aligned_{k}_Z',
f'colmap_yaw_{k}(deg)', f'colmap_pitch_{k}(deg)', f'colmap_roll_{k}(deg)',
f'delta_colmap_{k}(deg)', f'delta_ers_{k}(deg)', f'delta_diff_{k}(deg)',
f'cum_colmap_{k}(deg)', f'cum_ers_{k}(deg)', f'cum_diff_{k}(deg)',
]
fieldnames = base_fields + extra_fields
sep = '\t' if args.out.endswith('.tsv') else ','
with open(args.out, 'w', newline='') as f:
w = csv.DictWriter(f, fieldnames=fieldnames)
w = csv.DictWriter(f, fieldnames=fieldnames, delimiter=sep)
w.writeheader()
# There is only one col_spec (x/y/z); iterate for forward-compat.
label = col_specs[0][0]
if label in pos_results:
s, R_align, t, res = pos_results[label]
for i, (ce, er) in enumerate(pairs):
Qi = np.array([[er['x'], er['y'], er['z']]])
aligned = apply_sim3(s, R_align, t, Qi)[0]
od = ori_results[label][i]
def _f(v): return v if np.isfinite(v) else ''
row = {
'frame': ce['frame'],
'timestamp': er['timestamp'],
'colmap_X': ce['center'][0],
'colmap_Y': ce['center'][1],
'colmap_Z': ce['center'][2],
'xml_x': er['x'], 'xml_y': er['y'], 'xml_z': er['z'],
'xml_az_rad': er['az'],
'xml_tilt_rad': er['tilt'],
'xml_roll_rad': er['roll'],
'xml_x': er['x'],
'xml_y': er['y'],
'xml_z': er['z'],
'xml_az(deg)': np.degrees(er['az']),
'xml_tilt(deg)': np.degrees(er['tilt']),
'xml_roll(deg)': np.degrees(er['roll']),
'aligned_X': aligned[0],
'aligned_Y': aligned[1],
'aligned_Z': aligned[2],
'pos_res(colmap)': _f(res[i]),
'pos_res(m)': _f(res[i] / s),
'colmap_yaw(deg)': od['colmap_yaw_deg'],
'colmap_pitch(deg)': od['colmap_pitch_deg'],
'colmap_roll(deg)': od['colmap_roll_deg'],
'delta_colmap(deg)': _f(od['delta_colmap_deg']),
'delta_xml(deg)': _f(od['delta_ers_deg']),
'delta_diff(deg)': _f(od['delta_diff_deg']),
'cum_colmap(deg)': od['cum_colmap_deg'],
'cum_xml(deg)': od['cum_ers_deg'],
'cum_diff(deg)': _f(od['cum_diff_deg']),
}
for label, kx, ky, kz in col_specs:
if label not in pos_results:
continue
s, R_align, t, res = pos_results[label]
k = label.replace(' ', '_').replace('/', '_')
Qi = np.array([[er[kx], er[ky], er[kz]]])
aligned = apply_sim3(s, R_align, t, Qi)[0]
row[f'pos_res_{k}(colmap)'] = res[i] if np.isfinite(res[i]) else ''
row[f'pos_res_{k}(m)'] = (res[i]/s) if np.isfinite(res[i]) else ''
row[f'aligned_{k}_X'] = aligned[0]
row[f'aligned_{k}_Y'] = aligned[1]
row[f'aligned_{k}_Z'] = aligned[2]
od = ori_results[label][i]
row[f'colmap_yaw_{k}(deg)'] = od['colmap_yaw_deg']
row[f'colmap_pitch_{k}(deg)'] = od['colmap_pitch_deg']
row[f'colmap_roll_{k}(deg)'] = od['colmap_roll_deg']
row[f'delta_colmap_{k}(deg)'] = od['delta_colmap_deg'] \
if np.isfinite(od['delta_colmap_deg']) else ''
row[f'delta_ers_{k}(deg)'] = od['delta_ers_deg'] \
if np.isfinite(od['delta_ers_deg']) else ''
row[f'delta_diff_{k}(deg)'] = od['delta_diff_deg'] \
if np.isfinite(od['delta_diff_deg']) else ''
row[f'cum_colmap_{k}(deg)'] = od['cum_colmap_deg']
row[f'cum_ers_{k}(deg)'] = od['cum_ers_deg']
row[f'cum_diff_{k}(deg)'] = od['cum_diff_deg'] \
if np.isfinite(od['cum_diff_deg']) else ''
w.writerow(row)
print(f"\nSaved: {args.out}")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment