def horizon_error(ground_truth_horizon, detected_horizon, image_dims):
    """Calculates error in a detected horizon.

    This measures the max distance between the detected horizon line and
    the ground truth horizon line, within the image's x-axis, and
    normalized by image height.

    Args:
        ground_truth_horizon: Tuple with (slope, intercept) for the GT horizon line.
        detected_horizon: Tuple with (slope, intercept) for the detected horizon line.
        image_dims: Tuple of integers, (width, height) of the image, in pixels.

    Returns:
        Float, or None if a horizon is missing altogether.
    """
    if ground_truth_horizon is None or detected_horizon is None:
        return None

    def gt(x):
        return ground_truth_horizon[0] * x + ground_truth_horizon[1]

    def dt(x):
        return detected_horizon[0] * x + detected_horizon[1]

    width, height = image_dims
    return max(abs(gt(0) - dt(0)), abs(gt(width) - dt(width))) / height