Compare commits

...

1 Commits

Author SHA1 Message Date
Peter Bochmann fff437c13c
Let a tower choose its camera's auto-exposure target: --target
The Alvium recipe sets no IntensityControllerTarget, so a camera kept its
default of 50 %, which burns out the sky over a dark forest; staeffelsberg's
colour camera runs at 20 (set by hand in the Viewer), rietschen's Manta at
30. export_camera_profile.py --target <percent> now sets it for either
family (IntensityControllerTarget, or ExposureAutoTarget on a Manta). Without
the option nothing changes. For podrosche, whose migration plans 20 %.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:08:35 +01:00
2 changed files with 24 additions and 1 deletions

View File

@ -696,6 +696,11 @@ property the Viewer workflow exists to provide: GenICam validity is stateful, so
a hand-written XML can be individually plausible and collectively wrong. Here a hand-written XML can be individually plausible and collectively wrong. Here
the camera is the judge, and anything it refused is printed rather than assumed. the camera is the judge, and anything it refused is printed rather than assumed.
`--target <percent>` sets the auto-exposure target, a tower's own choice: the
Alvium recipe sets none, so the camera keeps its default of 50, which burns out
the sky over a dark forest. Staeffelsberg runs at 20, rietschen at 30. The keep
rule reads the target back from the camera, so nothing else has to change.
Read the summary line it prints - it is the number that decides whether the Read the summary line it prints - it is the number that decides whether the
profile can be delivered at all: profile can be delivered at all:

View File

@ -193,6 +193,20 @@ def has_feature(cam, name):
return False return False
def with_target(recipe, family, target):
"""The recipe with its auto-exposure target set to `target` percent.
A tower's own choice, not a recipe's: staeffelsberg's colour camera runs at
20 %, rietschen's at 30, where the Alvium's default of 50 burnt out the sky.
The keep rule reads the target back from the camera, so nothing else needs
to know. An existing target entry is replaced; otherwise it goes last."""
if target is None:
return recipe
name = "ExposureAutoTarget" if family == "gige" else "IntensityControllerTarget"
out = [(n, v) for n, v in recipe if n != name]
return out + [(name, float(target))]
def recipe_family(cam): def recipe_family(cam):
"""'gige' for a camera that only knows the older names, else 'alvium'.""" """'gige' for a camera that only knows the older names, else 'alvium'."""
if not has_feature(cam, "ExposureTime") and has_feature(cam, "ExposureTimeAbs"): if not has_feature(cam, "ExposureTime") and has_feature(cam, "ExposureTimeAbs"):
@ -270,6 +284,9 @@ def main():
ap.add_argument("--camera", default=None, help="camera id (default: the first real one)") ap.add_argument("--camera", default=None, help="camera id (default: the first real one)")
ap.add_argument("--family", default="auto", choices=("auto", "alvium", "gige"), ap.add_argument("--family", default="auto", choices=("auto", "alvium", "gige"),
help="which recipe set (default: from the features the camera has)") help="which recipe set (default: from the features the camera has)")
ap.add_argument("--target", type=float, default=None,
help="auto-exposure target in percent (default: the recipe's, or the "
"camera's own where the recipe sets none)")
ap.add_argument("--dry-run", action="store_true") ap.add_argument("--dry-run", action="store_true")
args = ap.parse_args() args = ap.parse_args()
@ -294,7 +311,8 @@ def main():
with cam: with cam:
family = recipe_family(cam) if args.family == "auto" else args.family family = recipe_family(cam) if args.family == "auto" else args.family
recipe = (GIGE_RECIPES if family == "gige" else RECIPES)[args.profile] recipe = with_target((GIGE_RECIPES if family == "gige" else RECIPES)[args.profile],
family, args.target)
print(f"camera : {cam.get_id()} {cam.get_model()}") print(f"camera : {cam.get_id()} {cam.get_model()}")
print(f"profile : {args.profile} ({family} recipe){' (dry run)' if args.dry_run else ''}") print(f"profile : {args.profile} ({family} recipe){' (dry run)' if args.dry_run else ''}")
refused = [] refused = []