tuned pipeline to 60 fps

This commit is contained in:
ykcheungab
2026-06-14 20:58:46 +08:00
parent 30bebcd439
commit fbee1c37ed
12 changed files with 339 additions and 37 deletions
@@ -14,6 +14,7 @@ import time
import cv2
import numpy as np
import orisys
from orisys.configs import load_config
from orisys.frame_processors import UVUnrollFrameProcessor
from orisys.unroll import (
barycentric_grid,
@@ -23,6 +24,9 @@ from orisys.unroll import (
load_calib_json,
load_exported_data,
recommend_edge_expand,
resolve_uv_runtime_sizes,
scale_camera_geometry,
scaled_map_cache_path,
uv_triangle_to_image,
)
@@ -304,12 +308,18 @@ def open_source(video_path, camera_id):
PERF_TUNING_EPILOG = """
Performance tuning (config JSON + CLI):
tracker.dis_preset medium -> fast/ultrafast faster DIS optical flow
tracker.loop_closure_interval 1 -> 3-5 fewer loop-closure remaps
tracker.hhd_downsample 3 -> 4 smaller HHD Poisson grid
contact.denoise_sigma 12 -> 6 or 0 faster FoE contact step
--masked_poisson_solver sparse vs capfft benchmark HHD solve time
--no-viz skip dashboard/imshow ~20 ms/frame savings
camera.resolution_stitch [280, 300] UV output + SDK flow/HHD grid
camera.source_scale 0.4 shrink source before uv_prep/remap
tracker.dis_preset medium -> fast faster DIS optical flow
tracker.hhd_downsample 5 -> 4 smaller HHD Poisson grid
contact.denoise_sigma 12 -> 6 or 0 faster FoE contact step
--source_scale 0.4 override config source scale
--masked_poisson_solver sparse vs capfft benchmark HHD solve time
--no-viz skip dashboard ~20 ms/frame savings
Recommended dd02-ov fast profile:
resolution_stitch [280, 300], source_scale 0.4, hhd_downsample 5
Delete or rename stale unroll_map_uv.npz after changing output scale.
"""
@@ -349,6 +359,32 @@ def configure_masked_poisson(sensor, args):
sensor.masked_poisson_reg = args.masked_poisson_reg
def resolve_runtime_geometry(args):
"""Apply config defaults and optional source-scale to UV/camera geometry."""
sdk_config = load_config(args.sdk_config)
camera_config = sdk_config.get("camera", {})
out_width, out_height, source_scale = resolve_uv_runtime_sizes(
camera_config,
out_width=args.out_width,
out_height=args.out_height,
source_scale=args.source_scale,
)
stitch = camera_config.get("resolution_stitch")
if stitch and len(stitch) >= 2 and (int(stitch[0]) != out_width or int(stitch[1]) != out_height):
print(
"Warning: UV output "
f"{out_width}x{out_height} differs from resolution_stitch "
f"{int(stitch[0])}x{int(stitch[1])} in {args.sdk_config}; "
"Sensor.get_img will resize again."
)
args.out_width = out_width
args.out_height = out_height
args.source_scale = source_scale
args.map_cache = scaled_map_cache_path(args.map_cache, source_scale)
return sdk_config, camera_config
def main():
parser = argparse.ArgumentParser(
description="Real-time UV-based finger unrolling",
@@ -362,8 +398,14 @@ def main():
# With a 12% UV edge band on each side, only about 76% of each axis is the
# lower-distortion middle region. Use a slightly larger full remap so the
# useful center keeps roughly the same sampling density as the prior 506x550.
parser.add_argument("--out_width", type=int, default=504)
parser.add_argument("--out_height", type=int, default=506)
parser.add_argument("--out_width", type=int, default=None, help="UV flatten width (default: camera.resolution_stitch in sdk config)")
parser.add_argument("--out_height", type=int, default=None, help="UV flatten height (default: camera.resolution_stitch in sdk config)")
parser.add_argument(
"--source_scale",
type=float,
default=None,
help="Resize live source to this fraction before uv_prep/uv_remap; scales K accordingly (default: camera.source_scale or work4[3] in sdk config, else 1.0)",
)
parser.add_argument("--camera_id", type=int, default=0)
parser.add_argument("--video", help="Video file path (overrides camera)")
parser.add_argument("--map_cache", default="unroll_map_uv.npz")
@@ -386,6 +428,7 @@ def main():
help="Skip OpenCV dashboard; print forces and benchmark timings only",
)
args = parser.parse_args()
_, camera_config = resolve_runtime_geometry(args)
print("[benchmark] Startup timing:")
data = benchmark_step("load_exported_data", load_exported_data, args.mesh, args.intrinsics_path, args.pose)
@@ -429,15 +472,29 @@ def main():
if args.calib:
source_K, dist_coeffs, img_size = benchmark_step("load_calib_json", load_calib_json, args.calib)
source_width, source_height = img_size
print(f"Calibration loaded. Live image size: {(source_width, source_height)}")
native_width, native_height = img_size
print(f"Calibration loaded. Live image size: {(native_width, native_height)}")
else:
source_K = data["K"]
dist_coeffs = None
source_width = data["width"]
source_height = data["height"]
native_width = data["width"]
native_height = data["height"]
print("No calibration file provided; using exported intrinsics for projection.")
source_K, source_width, source_height = scale_camera_geometry(
source_K,
native_width,
native_height,
args.source_scale,
)
print(
"UV runtime geometry: "
f"native={native_width}x{native_height}, "
f"source={source_width}x{source_height} (scale={args.source_scale:g}), "
f"output={args.out_width}x{args.out_height}, "
f"map_cache={args.map_cache}"
)
domain = benchmark_step(
"build_or_load_domain",
build_or_load_domain,
@@ -454,6 +511,7 @@ def main():
edge_band=args.edge_band,
edge_expand=edge_expand,
include_surface=True,
source_scale=args.source_scale,
)
remap = domain.remap
remap.ensure_fast_maps()
@@ -495,8 +553,8 @@ def main():
print("Cannot open camera/video source")
sys.exit(1)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, source_width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, source_height)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, native_width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, native_height)
sensor = benchmark_step(
"sensor_init",
@@ -600,8 +658,8 @@ def main():
arrows = orisys.util.draw_arrows(
img,
flow,
threshold=1,
grid_spacing=15,
threshold=0.4,
grid_spacing=10,
arrow_scale=1.0,
)
contact_img = orisys.util.draw_contact(img, contour, centroid)