feat: auto-select blender based on camera type
- NavCam -> enblend --pre-assemble (better vignette/horizon handling) - Mastcam-Z -> verdandi (eliminates overexposure at seam transitions) - Based on visual comparison: enblend default is best for NavCam, verdandi is best for MCZ (user confirmed) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -278,8 +278,20 @@ def build_pto(pto_path, img_paths, azs, els, img_w, img_h, fov, ref_idx=None):
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
def run_pipeline(work_dir, clahe_images, original_images, azs, els,
|
def run_pipeline(work_dir, clahe_images, original_images, azs, els,
|
||||||
img_w, img_h, fov, output_name):
|
img_w, img_h, fov, output_name, blender="auto", camera=None):
|
||||||
"""Full pipeline: cpfind(CLAHE) -> swap(originals) -> optimize(geo) -> nona -> verdandi."""
|
"""Full pipeline: cpfind(CLAHE) -> swap(originals) -> optimize(geo) -> nona -> blend.
|
||||||
|
|
||||||
|
Blender selection:
|
||||||
|
- auto: enblend for NavCam (better vignette/horizon), verdandi for Mastcam-Z (no seam overexposure)
|
||||||
|
- enblend: force enblend --pre-assemble
|
||||||
|
- verdandi: force verdandi
|
||||||
|
"""
|
||||||
|
# Select blender
|
||||||
|
if blender == "auto":
|
||||||
|
if camera and "MCZ" in camera:
|
||||||
|
blender = "verdandi"
|
||||||
|
else:
|
||||||
|
blender = "enblend"
|
||||||
|
|
||||||
timings = {}
|
timings = {}
|
||||||
|
|
||||||
@@ -351,13 +363,16 @@ def run_pipeline(work_dir, clahe_images, original_images, azs, els,
|
|||||||
print(" ERROR: nona produced no output")
|
print(" ERROR: nona produced no output")
|
||||||
return None, timings
|
return None, timings
|
||||||
|
|
||||||
# verdandi (better transitions than enblend, no overexposure at seams)
|
# Blend: verdandi for MCZ (no seam overexposure), enblend for NavCam (better vignette)
|
||||||
print(" verdandi...", flush=True)
|
print(f" {blender}...", flush=True)
|
||||||
out_tif = os.path.join(work_dir, f"{output_name}.tif")
|
out_tif = os.path.join(work_dir, f"{output_name}.tif")
|
||||||
tif_list = " ".join([f'"{t}"' for t in tifs])
|
tif_list = " ".join([f'"{t}"' for t in tifs])
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
|
if blender == "verdandi":
|
||||||
run_hugin("verdandi", f'-o "{out_tif}" {tif_list}', cwd=work_dir)
|
run_hugin("verdandi", f'-o "{out_tif}" {tif_list}', cwd=work_dir)
|
||||||
timings["verdandi"] = time.time() - t0
|
else:
|
||||||
|
run_hugin("enblend", f'--pre-assemble -o "{out_tif}" {tif_list}', cwd=work_dir)
|
||||||
|
timings["blend"] = time.time() - t0
|
||||||
|
|
||||||
# Convert to PNG
|
# Convert to PNG
|
||||||
out_png = os.path.join(work_dir, f"{output_name}.png")
|
out_png = os.path.join(work_dir, f"{output_name}.png")
|
||||||
@@ -456,7 +471,8 @@ def process_navcam(sol, camera, rover, data_dir, output_dir):
|
|||||||
|
|
||||||
output_name = f"panorama_sol{sol}"
|
output_name = f"panorama_sol{sol}"
|
||||||
result, timings = run_pipeline(work_dir, clahe_imgs, originals,
|
result, timings = run_pipeline(work_dir, clahe_imgs, originals,
|
||||||
azs, els, img_w, img_h, fov, output_name)
|
azs, els, img_w, img_h, fov, output_name,
|
||||||
|
camera=camera)
|
||||||
|
|
||||||
print_timings(timings)
|
print_timings(timings)
|
||||||
return result
|
return result
|
||||||
@@ -536,7 +552,8 @@ def process_mastcamz(sol, camera, rover, data_dir, output_dir):
|
|||||||
|
|
||||||
output_name = f"panorama_sol{sol}_mcz"
|
output_name = f"panorama_sol{sol}_mcz"
|
||||||
result, timings = run_pipeline(work_dir, clahe_imgs, originals,
|
result, timings = run_pipeline(work_dir, clahe_imgs, originals,
|
||||||
azs, els, img_w, img_h, fov, output_name)
|
azs, els, img_w, img_h, fov, output_name,
|
||||||
|
camera=camera)
|
||||||
|
|
||||||
print_timings(timings)
|
print_timings(timings)
|
||||||
return result
|
return result
|
||||||
|
|||||||
Reference in New Issue
Block a user