def stereo_capture_procedure() -> cgp.ProcedureSequence:
"""Client-side procedure for stereo image capture."""
root = cgp.GetRootDirectory()
session = root.new_session("G3C")
# Load instruction image
instruction_image = root.new_file("instructions").load(
or_else=cgp.NullProcedure(return_type=cgp.PImage)
)
# Get reference from first session for alignment
reference_session = root.get_first_session("G3C")
# Capture aligned stereo pair
left_photo = cgp.CaptureAlignedImage(
label="Capture Left Photo",
reference_image=reference_session.new_file("left").load(
or_else=cgp.NullProcedure(return_type=cgp.PImage)
),
)
right_photo = cgp.CaptureAlignedImage(
label="Capture Right Photo",
reference_image=reference_session.new_file("right").load(
or_else=cgp.NullProcedure(return_type=cgp.PImage)
),
)
return cgp.ProcedureSequence(
label="G3C Stereo Capture",
procedures=[
session.new_file("left").save(left_photo),
session.new_file("right").save(right_photo),
],
)
def calculate_optimal_slots(target, sessions) -> cg.List:
"""Compute optimal capture times using solar angle scheduling."""
location = target._metadata._capture_location
# Generate candidate times for next 24 hours
candidates = cg.List([])
candidates.date = cgsh.forecast.times(
resolution=timedelta(minutes=1),
span=timedelta(hours=24),
)
# Get weather forecast and solar positions
candidates.weather = cgsh.forecast.nearest_weather(
weather=cgsh.forecast.hourly_weather(location, days=3),
times=candidates.date,
)
candidates.solar_angle = cgsh.forecast.solar_position(location, candidates.date)
# Distance function combining solar angle and weather
distance_fn = cgsh.distance.combine(
solar_angle=cgsh.distance.solar(sigma_deg=2.0),
weather=cgsh.distance.weather(sigma_cloud_cover_ratio=0.4),
)
# Select optimal slots using void-and-cluster
return cgsh.select_sessions(
potential_sessions=candidates,
previous_sessions=sessions,
distance_fn=distance_fn,
energy_fn=cgsh.energy.gaussian(sigma=1),
selections=3,
)