Modules
Planet Ruler API modules organized by functionality.
planet_ruler
Core Modules
Manual Limb Annotation Tool for Planet Ruler |
|
Automatic extraction of camera parameters from smartphone images. |
|
Validation functions for planet_ruler. |
|
Command-line interface for planet_ruler |
|
Geometry Module
Mathematical functions for planetary geometry calculations.
- planet_ruler.geometry.horizon_distance(r, h)[source]
Estimate the distance to the horizon (limb) given a height and radius.
- planet_ruler.geometry.limb_camera_angle(r, h)[source]
The angle the camera must tilt in theta_x or theta_y to center the limb. Complement of theta (angle of limb down from the x-y plane).
- planet_ruler.geometry.focal_length(w, fov)[source]
The size of the CCD (inferred) based on focal length and field of view.
- planet_ruler.geometry.detector_size(f, fov)[source]
The size of the CCD (inferred) based on focal length and field of view.
- planet_ruler.geometry.field_of_view(f, w)[source]
The size of the CCD (inferred) based on focal length and field of view.
- planet_ruler.geometry.intrinsic_transform(camera_coords, f=1, px=1, py=1, x0=0, y0=0)[source]
Transform from camera coordinates into image coordinates.
- Parameters:
camera_coords (np.ndarray) – Coordinates of the limb in camera space. Array has Nx4 shape where N is the number of x-axis pixels in the image.
f (float) – Focal length of the camera (m).
px (float) – The scale of x pixels.
py (float) – The scale of y pixels.
x0 (float) – The x-axis principle point (should be center of image in pixel coordinates).
y0 (float) – The y-axis principle point. (should be center of image in pixel coordinates).
- Returns:
Coordinates in image space.
- Return type:
pixel_coords (np.ndarray)
- planet_ruler.geometry.extrinsic_transform(world_coords, theta_x=0, theta_y=0, theta_z=0, origin_x=0, origin_y=0, origin_z=0)[source]
Transform from world coordinates into camera coordinates. Note that for a limb calculation we will define origin_x/y/z as the camera position – these should all be set to zero.
- Parameters:
world_coords (np.ndarray) – Coordinates of the limb in the world. Array has Nx4 shape where N is the number of x-axis pixels in the image.
theta_x (float) – Rotation around the x (horizontal) axis, AKA pitch. (radians)
theta_y (float) – Rotation around the y (toward the limb) axis, AKA roll. (radians)
theta_z (float) – Rotation around the z (vertical) axis, AKA yaw. (radians)
origin_x (float) – Horizontal offset from the object in question to the camera (m).
origin_y (float) – Distance from the object in question to the camera (m).
origin_z (float) – Height difference from the object in question to the camera (m).
- Returns:
Coordinates in camera space.
- Return type:
camera_coords (np.ndarray)
- planet_ruler.geometry.limb_arc_sample(r, n_pix_x, n_pix_y, h=1, f=None, fov=None, w=None, x0=0, y0=0, theta_x=0, theta_y=0, theta_z=0, origin_x=0, origin_y=0, origin_z=0, return_full=False, num_sample=5000)[source]
Calculate the limb orientation in an image given the physical parameters of the system.
- Parameters:
n_pix_x (int) – Width of image (pixels).
n_pix_y (int) – Height of image (pixels).
r (float) – Radius of the body in question.
h (float) – Height above surface (units should match radius).
f (float) – Focal length of the camera (m).
fov (float) – Field of view, assuming square (degrees).
w (float) – detector size (float): Width of CCD (m).
x0 (float) – The x-axis principle point.
y0 (float) – The y-axis principle point.
theta_x (float) – Rotation around the x (horizontal) axis, AKA pitch. (radians)
theta_y (float) – Rotation around the y (toward the limb) axis, AKA roll. (radians)
theta_z (float) – Rotation around the z (vertical) axis, AKA yaw. (radians)
origin_x (float) – Horizontal offset from the object in question to the camera (m).
origin_y (float) – Distance from the object in question to the camera (m).
origin_z (float) – Height difference from the object in question to the camera (m).
return_full (bool) – Return both the x and y coordinates of the limb in camera space. Note these will not be interpolated back on to the pixel grid.
num_sample (
int) – The number of points sampled from the simulated limb – will be interpolated onto pixel grid. [default 1000]
- Return type:
- planet_ruler.geometry.get_rotation_matrix(theta_x, theta_y, theta_z)[source]
Compute combined rotation matrix from Euler angles. Extracted from extrinsic_transform for reuse.
- Returns:
3x3 rotation matrix
- Return type:
R
- planet_ruler.geometry.limb_arc(r, n_pix_x, n_pix_y, h=1, f=None, fov=None, w=None, x0=0, y0=0, theta_x=0, theta_y=0, theta_z=0, origin_x=0, origin_y=0, origin_z=0, return_full=False, **kwargs)[source]
Calculate limb position analytically at each pixel x-coordinate.
No sampling or interpolation - directly solves for phi at each column. This eliminates edge artifacts and is sometimes faster than sampling methods.
Mathematical approach: 1. Limb is parameterized by angle phi around circle 2. For each x_pixel, solve: x_pixel = f(phi) for phi 3. This reduces to: a·cos(phi) + b·sin(phi) = c 4. Standard analytical solution exists!
Args: (same as original limb_arc)
- Returns:
Array of y-coordinates for each x-pixel column
- Return type:
y_pixel
Image Processing Module
Computer vision and image analysis functions.
- planet_ruler.image.load_image(filepath)[source]
Load a 3 or 4-channel image from filepath into an array.
- planet_ruler.image.directional_gradient_blur(image, sigma_base=2.0, streak_length=20, decay_rate=0.2, normalize_gradients=True)[source]
Blur along gradient directions to create smooth ‘streaks’ toward edges.
For each pixel, follow its gradient direction outward, averaging pixels along that ray with exponential decay. This: - Smooths noisy/weak gradients (striations with inconsistent directions) - Strengthens coherent gradients (limb where all gradients align) - Creates smooth ‘valleys’ guiding optimizer toward strong edges
- Parameters:
image (np.ndarray) – Input image (H x W or H x W x 3)
sigma_base (float) – Initial gradient smoothing for direction estimation
streak_length (int) – How far to follow gradient direction (pixels)
decay_rate (float) – Exponential decay rate (higher = faster decay)
normalize_gradients (bool) –
True: Use unit vectors (direction only) - RECOMMENDED All pixels sample same distance regardless of gradient strength. Consistent, predictable behavior.
False: Use full gradient magnitude as direction Strong gradients sample further. Can create artifacts.
- Returns:
Blurred gradient magnitude field grad_angle (np.ndarray): Gradient angle field
- Return type:
blurred_grad_mag (np.ndarray)
- Note: This is UNI-directional (samples in one direction only).
Use bidirectional_gradient_blur() to preserve peak locations.
- planet_ruler.image.bilinear_interpolate(array, y, x)[source]
Bilinear interpolation for 2D array at non-integer coordinates.
- Parameters:
array – 2D array to sample from
y – Arrays of y and x coordinates (can be non-integer)
x – Arrays of y and x coordinates (can be non-integer)
- Returns:
Interpolated values at (y, x) positions
- planet_ruler.image.bidirectional_gradient_blur(image, sigma_base=2.0, streak_length=20, decay_rate=0.2, normalize_gradients=True)[source]
Blur in BOTH directions along gradient (forward and backward).
This creates symmetric streaks on both sides of edges, preserving the location of gradient maxima while smoothing the field.
- Parameters:
image – Input image
sigma_base – Initial smoothing for gradient estimation
streak_length – How far to sample in each direction
decay_rate – Exponential decay (higher = faster falloff)
normalize_gradients – Use unit vectors (direction only) vs full magnitude
- Returns:
Smoothed gradient magnitude field grad_angle: Original gradient angle field
- Return type:
blurred_mag
- planet_ruler.image.gradient_break(im_arr, log=False, y_min=0, y_max=-1, window_length=None, polyorder=1, deriv=0, delta=1)[source]
Scan each vertical line of an image for the maximum change in brightness gradient – usually corresponds to a horizon.
- Parameters:
im_arr (np.ndarray) – Image array.
log (bool) – Use the log(gradient). Sometimes good for smoothing.
y_min (int) – Minimum y-position to consider.
y_max (int) – Maximum y-position to consider.
window_length (int) – Width of window to apply smoothing for each vertical. Larger means less noise but less sensitivity.
polyorder (int) – Polynomial order for smoothing.
deriv (int) – Derivative level for smoothing.
delta (int) – Delta for smoothing.
- Returns:
image array (np.ndarray)
- class planet_ruler.image.MaskSegmenter(image, method='sam', downsample_factor=1, interactive=True, **backend_kwargs)[source]
Bases:
objectMethod-agnostic mask-based segmentation.
Supports pluggable backends (SAM, custom algorithms, etc.) with optional downsampling and interactive classification.
- class planet_ruler.image.SegmentationBackend[source]
Bases:
objectBase class for segmentation backends.
- class planet_ruler.image.SAMBackend(model_size='vit_b')[source]
Bases:
SegmentationBackendSegment Anything Model backend.
- class planet_ruler.image.CustomBackend(segment_fn)[source]
Bases:
SegmentationBackendCustom user-provided segmentation backend.
- planet_ruler.image.smooth_limb(y, method='rolling-median', window_length=50, polyorder=1, deriv=0, delta=1)[source]
Smooth the limb position values.
- Parameters:
y (np.ndarray) – Y-locations of the string for each column.
method (str) – Smoothing method. Must be one of [‘bin-interpolate’, ‘savgol’, ‘rolling-mean’, ‘rolling-median’].
window_length (int) – The length of the filter window (i.e., the number of coefficients). If mode is ‘interp’, window_length must be less than or equal to the size of x.
polyorder (float) – The order of the polynomial used to fit the samples. polyorder must be less than window_length.
deriv (int) – The order of the derivative to compute. This must be a non-negative integer. The default is 0, which means to filter the data without differentiating.
delta (int) – The spacing of the samples to which the filter will be applied. This is only used if deriv > 0. Default is 1.0.
- Returns:
Y-locations of the smoothed string for each column.
- Return type:
position (np.ndarray)
- planet_ruler.image.fill_nans(limb)[source]
Fill NaNs for the limb position values.
- Parameters:
limb (np.ndarray) – Y-locations of the limb on the image.
- Returns:
Y-locations of the limb on the image.
- Return type:
limb (np.ndarray)
- planet_ruler.image.gradient_field(image, kernel_smoothing=5.0, directional_smoothing=50, directional_decay_rate=0.15)[source]
Pre-compute gradient field AND its derivatives for fast sub-pixel interpolation. Uses directional blur for enhanced edge detection.
- Parameters:
image (
ndarray) – Input imagekernel_smoothing (
float) – Sigma for initial gradient direction estimationdirectional_smoothing (
int) – Distance to sample in each direction (±pixels). Set to 0 to bypass directional smoothing entirely.directional_decay_rate (
float) – Exponential decay rate for directional blur
- Returns:
- Dictionary containing gradient field components:
grad_mag: Gradient magnitude array
grad_angle: Gradient angle array
grad_sin: Sin of gradient angle (for interpolation)
grad_cos: Cos of gradient angle (for interpolation)
grad_mag_dy, grad_mag_dx: Derivatives of gradient magnitude
grad_sin_dy, grad_sin_dx: Derivatives of sine component
grad_cos_dy, grad_cos_dx: Derivatives of cosine component
image_height, image_width: Dimensions
- Return type:
Observation Module
High-level observation classes and workflows.
- class planet_ruler.observation.PlanetObservation(image_filepath)[source]
Bases:
objectBase class for planet observations.
- Parameters:
image_filepath (str) – Path to image file.
- class planet_ruler.observation.LimbObservation(image_filepath, fit_config, limb_detection='manual', minimizer='differential-evolution')[source]
Bases:
PlanetObservationObservation of a planet’s limb (horizon).
- Parameters:
- __init__(image_filepath, fit_config, limb_detection='manual', minimizer='differential-evolution')[source]
- analyze(detect_limb_kwargs=None, fit_limb_kwargs=None)[source]
Perform complete limb analysis: detection + fitting in one call.
- property radius_km: float
Get the fitted planetary radius in kilometers.
- Returns:
Planetary radius in km, or 0 if not fitted
- Return type:
- property altitude_km: float
Get the observer altitude in kilometers.
- Returns:
Observer altitude in km, or 0 if not fitted
- Return type:
- property focal_length_mm: float
Get the camera focal length in millimeters.
- Returns:
Focal length in mm, or 0 if not fitted
- Return type:
- property radius_uncertainty: float
Get parameter uncertainty for radius.
Automatically selects best method based on minimizer: - differential_evolution: Uses population spread (fast, exact) - dual_annealing/basinhopping: Uses Hessian approximation (fast, approximate)
- Returns:
Radius uncertainty in km (1-sigma), or 0 if not available
- Return type:
- parameter_uncertainty(parameter, method='auto', scale_factor=1.0, confidence_level=0.68, **kwargs)[source]
Get uncertainty for any fitted parameter.
- Parameters:
parameter (
str) – Parameter name (e.g., ‘r’, ‘h’, ‘f’, ‘theta_x’)method (
Literal['auto','hessian','profile','bootstrap']) – Uncertainty method - ‘auto’: Choose based on minimizer (recommended) - ‘hessian’: Fast Hessian approximation - ‘profile’: Slow but accurate profile likelihood - ‘bootstrap’: Multiple fits (very slow)scale_factor (
float) – Scale result (e.g., 1000.0 for m→km)confidence_level (
float) – Confidence level (0.68=1σ, 0.95=2σ)**kwargs – Additional arguments passed to uncertainty calculator
- Return type:
- Returns:
dict with ‘uncertainty’, ‘method’, ‘confidence_level’, ‘additional_info’
Examples
# Radius uncertainty in km (1-sigma) obs.parameter_uncertainty(‘r’, scale_factor=1000.0)
# Altitude uncertainty in km (2-sigma / 95% CI) obs.parameter_uncertainty(‘h’, scale_factor=1000.0, confidence_level=0.95)
# Focal length uncertainty in mm (using profile likelihood) obs.parameter_uncertainty(‘f’, scale_factor=1000.0, method=’profile’)
- plot_3d(**kwargs)[source]
Create 3D visualization of the planetary geometry.
- Parameters:
**kwargs – Arguments passed to plot_3d_solution
- Return type:
- load_fit_config(fit_config)[source]
Load the fit configuration from file, setting all parameters to their initial values. Missing values are filled with defaults.
- register_limb(limb)[source]
Register a detected limb.
- Parameters:
limb (np.ndarray) – Limb vector (y pixel coordinates).
- Return type:
- detect_limb(detection_method=None, log=False, y_min=0, y_max=-1, window_length=501, polyorder=1, deriv=0, delta=1, segmentation_method='sam', downsample_factor=1, interactive=True, **segmentation_kwargs)[source]
Use the instance-defined method to find the limb in our observation. Kwargs are passed to the method.
- Parameters:
detection_method (literal) –
- Detection method. Must be one of
manual
gradient-break
gradient-field
segmentation
Default (None) uses the class attribute self.limb_detection.
log (bool) – Use the log(gradient). Sometimes good for smoothing.
y_min (int) – Minimum y-position to consider.
y_max (int) – Maximum y-position to consider.
window_length (int) – Width of window to apply smoothing for each vertical. Larger means less noise but less sensitivity.
polyorder (int) – Polynomial order for smoothing.
deriv (int) – Derivative level for smoothing.
delta (int) – Delta for smoothing.
segmentation_method (str) – Model used for segmentation. Must be one of [‘sam’].
downsample_factor (int) – Downsampling used for segmentation.
interactive (bool) – Prompts user to verify segmentation via annotation tool.
segmentation_kwargs (dict) – Kwargs passed to segmentation engine.
- Return type:
- smooth_limb(fill_nan=True, **kwargs)[source]
Apply the smooth_limb function to current observation.
- fit_limb(loss_function='l2', max_iter=15000, resolution_stages=None, max_iter_per_stage=None, n_jobs=1, seed=0, image_smoothing=None, kernel_smoothing=5.0, directional_smoothing=50, directional_decay_rate=0.15, prefer_direction=None, minimizer=None, minimizer_preset='balanced', minimizer_kwargs=None, warm_start=False, dashboard=False, dashboard_kwargs=None, target_planet='earth', verbose=False)[source]
Fit the limb to determine planetary parameters.
Supports single-resolution or multi-resolution (coarse-to-fine) optimization. Multi-resolution is recommended for gradient_field loss to avoid local minima.
- Parameters:
loss_function (
Literal['l2','l1','log-l1','gradient_field']) – Loss function type - ‘l2’, ‘l1’, ‘log-l1’: Traditional (requires detected limb) - ‘gradient_field’: Direct gradient alignment (no detection needed)max_iter (
int) – Maximum iterations (for single-resolution or total if multires)resolution_stages (
Union[List[int],Literal['auto'],None]) –Resolution strategy - None: Single resolution (original behavior) - ‘auto’: Auto-determine stages based on image size - List[int]: Custom stages, e.g., [4, 2, 1] = 1/4 → 1/2 → full NOTE: Multi-resolution only works with gradient_field loss functions.
Traditional loss functions (l2, l1, log-l1) require single resolution.
max_iter_per_stage (
Optional[List[int]]) – Iterations per stage (auto if None)n_jobs (
int) – Number of parallel workersseed (
int) – Random seed for reproducibilityimage_smoothing (
Optional[float]) – For gradient_field - Gaussian blur sigma applied to image before gradient computation. Removes high-frequency artifacts (crater rims, striations) that could mislead optimization. Different from kernel_smoothing.kernel_smoothing (
float) – For gradient_field - initial blur for gradient direction estimation. Makes the gradient field smoother for directional sampling.directional_smoothing (
int) – For gradient_field - sampling distance along gradientsdirectional_decay_rate (
float) – For gradient_field - exponential decay for samplesprefer_direction (
Optional[Literal['up','down']]) – For gradient_field - prefer ‘up’ or ‘down’ gradients where ‘up’ means dark-sky/bright-planet and v.v. (None = no preference, choose best gradient regardless of direction)minimizer (str) – Choice of minimizer. Supports ‘differential-evolution’, ‘dual-annealing’, and ‘basinhopping’.
minimizer_preset (
Literal['fast','balanced','robust','scipy-default']) – Optimization strategy - ‘fast’: Quick convergence, may miss global minimum - ‘balanced’: Good trade-off (default) - ‘robust’: Thorough exploration, slowerminimizer_kwargs (
Optional[Dict]) – Override specific minimizer parameters (advanced)warm_start (
bool) – If True, use previous fit’s results as starting point (useful for iterative refinement). If False (default), use original init_parameter_values. Note: Multi-resolution stages always warm-start from previous stages automatically. This parameter is for warm-starting across separate fit_limb() calls.dashboard (
bool) – Show live progress dashboard during optimizationdashboard_kwargs (
Optional[Dict]) – Additional kwargs for FitDashboard - output_capture: OutputCapture instance for print/log display - show_output: Show output section (default True if capture provided) - max_output_lines: Number of output lines to show (default 3) - min_refresh_delay: Fixed refresh delay (0.0 for adaptive, default) - refresh_frequency: Refresh every N iterations (default 1)target_planet (
str) – Reference planet for dashboard comparisons (‘earth’, ‘mars’, ‘jupiter’, ‘saturn’, ‘moon’, ‘pluto’)verbose (
bool) – Print detailed progress
- Returns:
For method chaining
- Return type:
self
Examples
# Simple single-resolution fit obs.fit_limb()
# Auto multi-resolution for gradient field obs.fit_limb(loss_function=’gradient_field’, resolution_stages=’auto’)
# Remove image artifacts before optimization obs.fit_limb(
loss_function=’gradient_field’, resolution_stages=’auto’, image_smoothing=2.0, # Remove crater rims, striations kernel_smoothing=5.0 # Smooth gradient field
)
# Custom stages with robust optimization obs.fit_limb(
loss_function=’gradient_field’, resolution_stages=[8, 4, 2, 1], minimizer_preset=’robust’
)
# Override specific minimizer parameters obs.fit_limb(
loss_function=’gradient_field’, minimizer_kwargs={‘popsize’: 25, ‘atol’: 0.5}
)
# Dashboard with output capture from planet_ruler.dashboard import OutputCapture capture = OutputCapture() with capture:
- obs.fit_limb(
loss_function=’gradient_field’, dashboard=True, dashboard_kwargs={‘output_capture’: capture}
)
# Iterative refinement with warm start obs.fit_limb(loss_function=’gradient_field’, resolution_stages=’auto’) obs.fit_limb(loss_function=’gradient_field’, warm_start=True,
minimizer_preset=’robust’) # Refine with more thorough search
- planet_ruler.observation.package_results(observation)[source]
Consolidate the results of a fit to see final vs. initial values.
- Parameters:
observation (object) – Instance of LimbObservation (must have used differential evolution minimizer).
- Returns:
- DataFrame of results including
fit value
initial value
parameter
- Return type:
results (pd.DataFrame)
Annotation Module
Interactive manual limb detection and annotation.
Manual Limb Annotation Tool for Planet Ruler
Allows users to click points on a horizon image and generate a sparse target for fitting with the existing planet_ruler pipeline.
- class planet_ruler.annotate.ToolTip(widget, text)[source]
Bases:
objectSimple tooltip that appears on hover.
- planet_ruler.annotate.create_tooltip(widget, text)[source]
Helper function to create tooltip for a widget.
- class planet_ruler.annotate.TkLimbAnnotator(image_path, initial_stretch=1.0, initial_zoom=None)[source]
Bases:
objectTkinter-based interactive tool for manually annotating planet limbs.
Features: - Zoom with scroll wheel (fit large images in window) - Vertical stretch buttons (stretch pixels vertically for precision) - Scrollable canvas for navigating - Click to add points, right-click to undo - Save/load points to JSON - Generate sparse target array for CostFunction
- class planet_ruler.annotate.TkMaskSelector(image, masks, initial_zoom=None)[source]
Bases:
objectInteractive mask classification tool for segmentation results.
Works with ANY segmentation method - completely backend-agnostic. Allows users to classify masks as ‘planet’, ‘sky’, or ‘exclude’ for horizon detection. Aligns with Planet Ruler’s educational philosophy of transparency over black-box automation.
- Parameters:
image (
ndarray) – Original image array (H x W x 3)masks (
list) – List of masks in any of these formats: - List of np.ndarray (boolean H x W arrays) - List of dicts with ‘mask’ or ‘segmentation’ key - Mixed formats are OKinitial_zoom (
Optional[float]) – Initial zoom level (None = auto-fit to window)
Camera Module
Automatic camera parameter extraction from EXIF data.
Automatic extraction of camera parameters from smartphone images. Uses EXIF data and a phone camera database.
- planet_ruler.camera.get_focal_length_35mm_equiv(exif_data)[source]
Get 35mm equivalent focal length (more reliable for phones).
- planet_ruler.camera.calculate_sensor_dimensions(focal_length_mm, focal_length_35mm)[source]
Calculate sensor dimensions from focal length ratio. Uses the relationship: focal_length_mm / sensor_width = focal_length_35mm / 36mm
- planet_ruler.camera.get_sensor_statistics_by_type(camera_type)[source]
Calculate sensor dimension statistics for a given camera type. Returns median, min, and max for sensor width and height.
- Return type:
- planet_ruler.camera.infer_camera_type(exif_data)[source]
Try to infer camera type from EXIF data even if exact model unknown.
- planet_ruler.camera.extract_camera_parameters(image_path)[source]
Automatically extract all camera parameters from any camera image. Handles phones, point-and-shoot cameras, DSLRs, mirrorless, etc.
- Returns:
- Camera parameters including:
focal_length_mm: focal length in millimeters
sensor_width_mm: sensor width in millimeters
sensor_height_mm: sensor height in millimeters
sensor_width_min: minimum sensor width (if using type statistics)
sensor_width_max: maximum sensor width (if using type statistics)
image_width_px: image width in pixels
image_height_px: image height in pixels
camera_model: detected camera model
camera_type: ‘phone’, ‘compact’, ‘dslr’, ‘mirrorless’, or ‘unknown’
confidence: ‘high’, ‘medium’, or ‘low’
- Return type:
- planet_ruler.camera.get_gps_altitude(image_path)[source]
Extract GPS altitude from EXIF data if available.
- Returns:
Altitude in meters, or None if not available
- Return type:
- planet_ruler.camera.get_initial_radius(planet='earth', perturbation_factor=0.5, seed=None)[source]
Get initial radius guess with perturbation.
- planet_ruler.camera.create_config_from_image(image_path, altitude_m=None, planet='earth', param_tolerance=0.1, perturbation_factor=0.5, seed=None)[source]
Create a complete planet_ruler configuration from an image. Works with any camera - phones, point-and-shoot, DSLRs, etc.
- Parameters:
image_path (
str) – Path to the imagealtitude_m (
Optional[float]) – Altitude in meters (REQUIRED if not in GPS data)planet (
str) – Planet name for initial radius guess (default: ‘earth’)param_tolerance (
float) – Fractional tolerance for parameter limits (default: 0.1 = ±10%)perturbation_factor (
float) – Initial radius perturbation (default: 0.5 = ±50%)seed (
Optional[int]) – Random seed for reproducibility (default: None = unseeded)
- Returns:
Configuration ready for planet_ruler
- Return type:
- Raises:
ValueError – If altitude cannot be determined from GPS and not provided manually
Notes
Initial radius is randomly perturbed to avoid local minima and prove data-driven results
For uncertainty quantification, consider running multiple times (multi-start optimization)
Theta parameters (orientation) have wide default limits to handle r-h coupling
Fitting Module
Parameter optimization and cost function handling.
- planet_ruler.fit.unpack_parameters(params, template)[source]
Turn a list of parameters back into a dict.
- planet_ruler.fit.pack_parameters(params, template)[source]
Turn a dict of parameters (or defaults) into a list.
- class planet_ruler.fit.CostFunction(target, function, free_parameters, init_parameter_values, loss_function='l2', kernel_smoothing=5.0, directional_smoothing=30, directional_decay_rate=0.15, prefer_direction=None)[source]
Bases:
objectWrapper to simplify interface with the minimization at hand.
- Parameters:
target (np.ndarray) – True value(s), e.g., the actual limb position. For gradient_field loss, this should be the image.
function (Callable) – Function mapping parameters to target of interest.
free_parameters (list) – List of free parameter names.
init_parameter_values (dict) – Initial values for named parameters.
loss_function (str) – Type of loss function, must be one of [‘l2’, ‘l1’, ‘log-l1’, ‘gradient_field’].
kernel_smoothing – For gradient_field - initial blur for gradient direction estimation. Makes the gradient field smoother for directional sampling.
directional_smoothing – For gradient_field - sampling distance along gradients
directional_decay_rate – For gradient_field - exponential decay for samples
prefer_direction (
Optional[str]) – For gradient_field - prefer ‘up’ or ‘down’ gradients where ‘up’ means dark-sky/bright-planet and v.v. (None = no preference, choose best gradient regardless of direction)
- __init__(target, function, free_parameters, init_parameter_values, loss_function='l2', kernel_smoothing=5.0, directional_smoothing=30, directional_decay_rate=0.15, prefer_direction=None)[source]
- planet_ruler.fit.calculate_parameter_uncertainty(observation, parameter='r', method='auto', uncertainty_type='std', scale_factor=1.0)[source]
Calculate parameter uncertainty from fitting results.
Provides a flexible interface for uncertainty estimation that works with different optimization methods and uncertainty metrics.
- Parameters:
observation – LimbObservation object with completed fit
parameter (str) – Parameter name to calculate uncertainty for (default: “r”)
method (str) – Uncertainty calculation method: - “auto”: Automatically detect method from fit results - “differential_evolution”: Use DE population posteriors - “bootstrap”: Use bootstrap resampling (future implementation) - “hessian”: Use Hessian-based uncertainty (future implementation)
uncertainty_type (str) – Type of uncertainty measure: - “std”: Standard deviation of parameter distribution - “ptp”: Peak-to-peak range (max - min) - “iqr”: Interquartile range (75th - 25th percentile) - “ci”: Confidence interval (returns dict with bounds)
scale_factor (float) – Scale factor to apply to results (e.g., 1000 for km units)
- Returns:
- Dictionary containing uncertainty information:
”value”: Fitted parameter value (scaled)
”uncertainty”: Uncertainty estimate (scaled)
”method”: Method used for uncertainty calculation
”type”: Type of uncertainty measure used
”raw_data”: Raw parameter samples if available
- Return type:
- Raises:
ValueError – If uncertainty method is not supported or data is insufficient
AttributeError – If observation doesn’t have required fit results
- planet_ruler.fit.format_parameter_result(uncertainty_result, units='')[source]
Format parameter uncertainty results for display.
- planet_ruler.fit.unpack_diff_evol_posteriors(observation)[source]
Extract the final state population of a differential evolution minimization and organize as a DataFrame.
- Parameters:
observation (object) – Instance of LimbObservation (must have used differential evolution minimizer).
- Returns:
Population (rows) and properties (columns).
- Return type:
population (pd.DataFrame)
Uncertainty Module
Parameter uncertainty estimation using multiple methods.
- planet_ruler.uncertainty.calculate_parameter_uncertainty(observation, parameter, method='auto', scale_factor=1.0, confidence_level=0.68, n_bootstrap=20, **kwargs)[source]
Calculate uncertainty for a fitted parameter using appropriate method.
Automatically selects best method based on minimizer used: - differential_evolution: Population spread (fast, exact) - dual_annealing/basinhopping: Hessian approximation (fast, approximate) - any: Profile likelihood or bootstrap (slow, accurate)
- Parameters:
observation – LimbObservation instance with completed fit
parameter (
str) – Parameter name (e.g., ‘r’, ‘h’, ‘f’)method (
Literal['auto','hessian','profile','bootstrap']) – Uncertainty estimation method - ‘auto’: Choose based on minimizer and available data - ‘hessian’: Inverse Hessian at optimum (fast) - ‘profile’: Profile likelihood (slow but accurate) - ‘bootstrap’: Multiple fits with different seeds (slow)scale_factor (
float) – Scale result (e.g., 1000.0 to convert m→km)confidence_level (
float) – Confidence level (0.68=1σ, 0.95=2σ)n_bootstrap (
int) – Number of bootstrap iterations
- Returns:
‘uncertainty’: The uncertainty value
’method’: Method used
’confidence_level’: Confidence level
’additional_info’: Method-specific details
- Return type:
dict with keys
Plotting Module
Visualization and plotting functions.
- planet_ruler.plot.plot_image(im_arr, gradient=False, show=True)[source]
Display an image using matplotlib.pyplot.imshow.
- planet_ruler.plot.plot_limb(y, show=True, c='y', s=10, alpha=0.2)[source]
Display the limb (usually on top of an image).
- planet_ruler.plot.plot_3d_solution(r, h=1, zoom=1, savefile=None, legend=True, vertical_axis='z', azim=None, roll=None, x_axis=False, y_axis=True, z_axis=False, **kwargs)[source]
Plot a limb solution in 3D.
- Parameters:
r (float) – Radius of the body in question.
h (float) – Height above surface (units should match radius).
zoom (float) – Shrink the height according to a zoom factor to make viewing easier.
savefile (str) – Path to optionally save figure.
legend (bool) – Display the legend.
vertical_axis (str) – Which axis will be used as the vertical (x, y, or z).
azim (float) – Viewing azimuth.
roll (float) – Viewing roll.
x_axis (bool) – Plot the x-axis.
y_axis (bool) – Plot the y-axis.
z_axis (bool) – Plot the z-axis.
kwargs – Absorbs other solution kwargs that don’t matter for physical space.
- Return type:
- planet_ruler.plot.plot_topography(image)[source]
Display the full limb, including the section not seen in the image.
- Parameters:
image (np.ndarray) – Image array.
- Return type:
- planet_ruler.plot.plot_gradient_field_at_limb(y_pixels, image, image_smoothing=None, kernel_smoothing=5.0, directional_smoothing=50, directional_decay_rate=0.15, sample_spacing=50, arrow_scale=20)[source]
Visualize gradient field along a proposed limb curve.
- Parameters:
y_pixels (np.ndarray) – Y-coordinates of limb at each x-position
image (np.ndarray) – Input image (H x W x 3 or H x W)
image_smoothing (int) – For gradient_field - Gaussian blur sigma applied to image before gradient computation. Removes high-frequency artifacts (crater rims, striations) that could mislead optimization. Different from kernel_smoothing.
kernel_smoothing (float) – Initial smoothing for gradient direction estimation
directional_smoothing (int) – How far to sample along gradients
directional_decay_rate (float) – Exponential decay rate for sampling
sample_spacing (int) – Sample every N pixels along x-axis
arrow_scale (float) – Scale factor for arrow lengths
- Returns:
Matplotlib figure and axis objects
- Return type:
fig, ax
- planet_ruler.plot.compare_blur_methods(image, y_pixels=None)[source]
Compare gradient magnitude with different blur methods.
- Parameters:
image – Input image
y_pixels – Optional limb curve to overlay
- planet_ruler.plot.compare_gradient_fields(y_pixels_list, labels, image, image_smoothing=None, kernel_smoothing=5.0, directional_smoothing=30, directional_decay_rate=0.15)[source]
Compare gradient alignment for multiple proposed limbs.
- Parameters:
y_pixels_list (list) – List of y-coordinate arrays (different limb proposals)
labels (list) – Labels for each limb
image (np.ndarray) – Input image
kernel_smoothing (float) – Initial smoothing for gradient direction estimation
directional_smoothing (int) – How far to sample along gradients
directional_decay_rate (float) – Exponential decay rate for sampling
- planet_ruler.plot.plot_diff_evol_posteriors(observation, show_points=False, log=True)[source]
Extract and display the final state population of a differential evolution minimization.
- planet_ruler.plot.plot_full_limb(observation, x_min=None, x_max=None, y_min=None, y_max=None)[source]
Display the full limb, including the section not seen in the image.
- planet_ruler.plot.plot_residuals(observation, show_sparse_markers=True, marker_size=10, alpha=0.6, figsize=(16, 6), show_image=False, image_alpha=0.4, band_size=30)[source]
Plot residuals between the fitted limb and the detected target limb.
- Parameters:
observation – Instance of LimbObservation that has been fitted.
show_sparse_markers (
bool) – Use larger markers for sparse data.marker_size (
int) – Size of markers for sparse data.alpha (
float) – Transparency of residual markers/line.figsize (
tuple) – Figure size (width, height).show_image (
bool) – Show straightened image strip as background.image_alpha (
float) – Transparency of background image.band_size (
int) – Size of band around residuals to plot (in pixels)
- Return type:
- planet_ruler.plot.plot_gradient_field_quiver(image, step=2, scale=0.15, limb_y=None, roi_height=None, image_smoothing=None, kernel_smoothing=5.0, directional_smoothing=50, directional_decay_rate=0.15, downsample_factor=32, figsize=(16, 10), cmap='hot')[source]
Plot gradient field as quiver (arrow) plot.
- Parameters:
image (
ndarray) – Input image array.step (
int) – Spacing between arrows (every Nth pixel).limb_y (
Optional[ndarray]) – Optional limb curve to overlay (y-coordinates).roi_height (
Optional[int]) – If provided, only show ±roi_height pixels around limb.image_smoothing (
Optional[int]) – For gradient_field - Gaussian blur sigma applied to image before gradient computation. Removes high-frequency artifacts (crater rims, striations) that could mislead optimization. Different from kernel_smoothing.kernel_smoothing (
float) – Sigma for initial gradient direction estimation.directional_smoothing (
int) – Distance for directional blur sampling.directional_decay_rate (
float) – Exponential decay for directional blur.downsample_factor (
int) – Downsample image by this factor before computing gradients. Values > 1 reduce resolution (e.g., 2 = half resolution, 4 = quarter). Useful for visualizing gradient field at different optimization stages.figsize (
tuple) – Figure size (width, height).cmap (
str) – Colormap for gradient magnitude.
- Return type:
- planet_ruler.plot.plot_segmentation_masks(observation)[source]
Display all the classes/masks generated by the segmentation.
- planet_ruler.plot.plot_sam_masks(masks, labels=None, colors=None, alpha=0.5, image=None, figsize=(16, 10), title=None, show=True)[source]
Plot multiple SAM segmentation masks as separate labeled objects with legend.
- Parameters:
masks (list) – List of SAM mask dictionaries with ‘segmentation’ keys containing boolean arrays. Can also be a list of boolean arrays directly.
labels (list) – Labels for each mask (for legend). If None, uses “Mask 0”, “Mask 1”, etc.
colors (list) – Colors for each mask. If None, uses a default color cycle.
alpha (float) – Transparency of mask overlays (0=transparent, 1=opaque).
image (np.ndarray) – Optional background image to display under masks.
figsize (tuple) – Figure size in inches.
title (str) – Optional title for the plot.
show (bool) – Whether to display the plot immediately.
- Returns:
(fig, ax) matplotlib figure and axis objects.
- Return type:
Example
>>> masks = [{'segmentation': planet_mask}, {'segmentation': sky_mask}] >>> fig, ax = plot_sam_masks( ... masks, ... labels=['Planet', 'Sky'], ... colors=['yellow', 'cyan'], ... image=observation.image ... )
Validation Module
Configuration validation and consistency checking.
Validation functions for planet_ruler.
- planet_ruler.validation.validate_limb_config(config, strict=True)[source]
Validate that a planet_ruler configuration is internally consistent.
Checks: 1. Initial parameter values are within their specified limits 2. Theta parameter limits are wide enough (avoid r-h coupling issues) 3. Radius limits span reasonable range for robust optimization
- Parameters:
- Raises:
AssertionError – If strict=True and validation fails
- Return type:
Example
>>> config = { ... 'init_parameter_values': {'r': 6371000, 'theta_x': 0.1}, ... 'parameter_limits': {'r': [1e6, 1e8], 'theta_x': [-3.14, 3.14]} ... } >>> validate_config(config) # Passes
Command-Line Interface
CLI tools for command-line access to planet_ruler.
Command-line interface for planet_ruler
This module provides a simple CLI for measuring planetary radii from horizon photographs.
Demo Module
Example scenarios and configuration management.