garmentiq.landmark.derivation.utils

  1import numpy as np
  2from typing import Tuple, Optional, List
  3
  4
  5def _calculate_line1_vector(
  6    p2_coord: Tuple[float, float], p3_coord: Tuple[float, float], direction: str
  7) -> Optional[Tuple[float, float]]:
  8    """
  9    Calculates the direction vector for Line 1 based on p2, p3, and direction.
 10
 11    Args:
 12        p2_coord (Tuple[float, float]): The (x, y) coordinates of the second point.
 13        p3_coord (Tuple[float, float]): The (x, y) coordinates of the third point.
 14        direction (str): The desired direction of Line 1 relative to the vector
 15            from `p2_coord` to `p3_coord`. Must be "parallel" or "perpendicular".
 16
 17    Returns:
 18        Optional[Tuple[float, float]]: The calculated direction vector (dx, dy)
 19            as a tuple of floats, or `None` if the direction is invalid or the
 20            vector (p3-p2) is a zero vector.
 21    """
 22    ref_dx = p3_coord[0] - p2_coord[0]
 23    ref_dy = p3_coord[1] - p2_coord[1]
 24
 25    if direction == "parallel":
 26        v1 = (ref_dx, ref_dy)
 27    elif direction == "perpendicular":
 28        v1 = (-ref_dy, ref_dx)
 29    else:
 30        print(
 31            f"Error: Invalid direction '{direction}'. Use 'parallel' or 'perpendicular'."
 32        )
 33        return None
 34
 35    # Check for zero vector
 36    if np.isclose(v1[0], 0) and np.isclose(v1[1], 0):
 37        print(
 38            f"Warning: Direction vector for Line 1 is zero (p2 and p3 likely coincide)."
 39        )
 40        # Decide if this should be a fatal error or handled downstream
 41        # Returning None signals an issue.
 42        return None
 43
 44    return v1
 45
 46
 47def _find_closest_point(
 48    points_list: List[Tuple[float, float]], target_point: Tuple[float, float]
 49) -> Optional[Tuple[float, float]]:
 50    """
 51    Finds the point in `points_list` that is closest (Euclidean distance) to `target_point`.
 52
 53    Args:
 54        points_list (List[Tuple[float, float]]): A list of 2D points (x, y) to search within.
 55        target_point (Tuple[float, float]): The reference point (x, y) to find the closest point to.
 56
 57    Returns:
 58        Optional[Tuple[float, float]]: The (x, y) coordinates of the closest point from
 59            `points_list` as a tuple of floats, or `None` if `points_list` is empty.
 60    """
 61    if not points_list:
 62        return None
 63
 64    points_np = np.array(points_list)
 65    target_np = np.array(target_point)
 66
 67    distances = np.linalg.norm(points_np - target_np, axis=1)
 68    closest_index = np.argmin(distances)
 69
 70    return tuple(points_np[closest_index])
 71
 72
 73def parse_derivation_args(deriv_dict, json_path, mask_path):
 74    """
 75    Parses a derivation dictionary to extract arguments for a derivation function.
 76
 77    This function is a helper for preparing arguments required by specific derivation
 78    functions (e.g., `derive_keypoint_coord`). It extracts parameters and adds fixed
 79    inputs like `json_path` and `mask_path`.
 80
 81    Args:
 82        deriv_dict (dict): A dictionary containing derivation parameters for a specific landmark.
 83        json_path (str): Path to the JSON file related to the image.
 84        mask_path (str): Path to the mask file related to the image.
 85
 86    Returns:
 87        dict: A dictionary of parsed arguments ready to be passed to a derivation function.
 88    """
 89    args = {}
 90    for k, v in deriv_dict.items():
 91        if k == "function":
 92            continue
 93        # p*_id should be ints, everything else leave as‐is
 94        if k.endswith("_id"):
 95            try:
 96                args[k] = int(v)
 97            except ValueError:
 98                # in case someone uses numbers not strictly digits
 99                args[k] = int(float(v))
100        else:
101            args[k] = v
102    args["json_path"] = json_path
103    args["mask_path"] = mask_path
104    return args
105    return args
def parse_derivation_args(deriv_dict, json_path, mask_path):
 74def parse_derivation_args(deriv_dict, json_path, mask_path):
 75    """
 76    Parses a derivation dictionary to extract arguments for a derivation function.
 77
 78    This function is a helper for preparing arguments required by specific derivation
 79    functions (e.g., `derive_keypoint_coord`). It extracts parameters and adds fixed
 80    inputs like `json_path` and `mask_path`.
 81
 82    Args:
 83        deriv_dict (dict): A dictionary containing derivation parameters for a specific landmark.
 84        json_path (str): Path to the JSON file related to the image.
 85        mask_path (str): Path to the mask file related to the image.
 86
 87    Returns:
 88        dict: A dictionary of parsed arguments ready to be passed to a derivation function.
 89    """
 90    args = {}
 91    for k, v in deriv_dict.items():
 92        if k == "function":
 93            continue
 94        # p*_id should be ints, everything else leave as‐is
 95        if k.endswith("_id"):
 96            try:
 97                args[k] = int(v)
 98            except ValueError:
 99                # in case someone uses numbers not strictly digits
100                args[k] = int(float(v))
101        else:
102            args[k] = v
103    args["json_path"] = json_path
104    args["mask_path"] = mask_path
105    return args
106    return args

Parses a derivation dictionary to extract arguments for a derivation function.

This function is a helper for preparing arguments required by specific derivation functions (e.g., derive_keypoint_coord). It extracts parameters and adds fixed inputs like json_path and mask_path.

Arguments:
  • deriv_dict (dict): A dictionary containing derivation parameters for a specific landmark.
  • json_path (str): Path to the JSON file related to the image.
  • mask_path (str): Path to the mask file related to the image.
Returns:

dict: A dictionary of parsed arguments ready to be passed to a derivation function.