|
@@ -0,0 +1,58 @@
|
|
|
|
|
+import argparse
|
|
|
|
|
+import json
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def load_mapping(path: str):
|
|
|
|
|
+ with open(path, 'r', encoding='utf-8') as f:
|
|
|
|
|
+ data = json.load(f)
|
|
|
|
|
+ pan_lookup = data['pan_lookup']
|
|
|
|
|
+ tilt_lookup = data['tilt_lookup']
|
|
|
|
|
+
|
|
|
|
|
+ def interp(lookup, ratio):
|
|
|
|
|
+ if not lookup:
|
|
|
|
|
+ return 0.0
|
|
|
|
|
+ if len(lookup) == 1:
|
|
|
|
|
+ return lookup[0][1]
|
|
|
|
|
+ if ratio <= lookup[0][0]:
|
|
|
|
|
+ return lookup[0][1]
|
|
|
|
|
+ if ratio >= lookup[-1][0]:
|
|
|
|
|
+ return lookup[-1][1]
|
|
|
|
|
+ lo, hi = 0, len(lookup) - 1
|
|
|
|
|
+ while lo < hi - 1:
|
|
|
|
|
+ mid = (lo + hi) // 2
|
|
|
|
|
+ if lookup[mid][0] <= ratio:
|
|
|
|
|
+ lo = mid
|
|
|
|
|
+ else:
|
|
|
|
|
+ hi = mid
|
|
|
|
|
+ x0, v0 = lookup[lo]
|
|
|
|
|
+ x1, v1 = lookup[hi]
|
|
|
|
|
+ if abs(x1 - x0) < 1e-10:
|
|
|
|
|
+ return v0
|
|
|
|
|
+ return v0 + (ratio - x0) / (x1 - x0) * (v1 - v0)
|
|
|
|
|
+
|
|
|
|
|
+ def transform(x: int, y: int):
|
|
|
|
|
+ x_ratio = x / 3840.0
|
|
|
|
|
+ y_ratio = y / 1080.0
|
|
|
|
|
+ pan = interp(pan_lookup, x_ratio) % 360
|
|
|
|
|
+ tilt = max(-90, min(90, interp(tilt_lookup, y_ratio)))
|
|
|
|
|
+ return pan, tilt
|
|
|
|
|
+
|
|
|
|
|
+ return transform, data
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def main():
|
|
|
|
|
+ parser = argparse.ArgumentParser()
|
|
|
|
|
+ parser.add_argument('--mapping', default='calibration_group1.json')
|
|
|
|
|
+ parser.add_argument('--x', type=int, default=1920)
|
|
|
|
|
+ parser.add_argument('--y', type=int, default=540)
|
|
|
|
|
+ args = parser.parse_args()
|
|
|
|
|
+
|
|
|
|
|
+ transform, data = load_mapping(args.mapping)
|
|
|
|
|
+ pan, tilt = transform(args.x, args.y)
|
|
|
|
|
+ print(f'Input: ({args.x}, {args.y})')
|
|
|
|
|
+ print(f'Output: pan={pan:.2f}°, tilt={tilt:.2f}°')
|
|
|
|
|
+ print(f'RMS error: {data.get("rms_error", -1):.2f}°')
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+if __name__ == '__main__':
|
|
|
|
|
+ main()
|