retuve.hip_us.metrics.curvature
Metric: Curvature
An experimental metric that calculates the "curvature" of the hip.
Overtime, there will be different versions of this metric as it is still being developed. Which version will be controlled from the config.
1# Copyright 2024 Adam McArthur 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15""" 16Metric: Curvature 17 18An experimental metric that calculates the "curvature" of the hip. 19 20Overtime, there will be different versions of this metric as it is 21still being developed. Which version will be controlled from the config. 22""" 23 24import math 25from typing import Tuple 26 27import numpy as np 28 29from retuve.classes.draw import Overlay 30from retuve.hip_us.classes.general import HipDataUS, LandmarksUS 31from retuve.keyphrases.config import Config 32from retuve.keyphrases.enums import Curvature, MetricUS 33 34 35def find_curvature( 36 landmarks: LandmarksUS, shape: Tuple, config: Config 37) -> float: 38 """ 39 Calculate the curvature of the hip. 40 41 :param landmarks: LandmarksUS: The landmarks object. 42 :param shape: Tuple: The shape of the image. 43 :param config: Config: The Config object. 44 45 :return: float: The curvature of the hip. 46 """ 47 if not ( 48 landmarks and landmarks.left and landmarks.apex and landmarks.right 49 ): 50 return 0 51 52 if config.hip.curvature_method == Curvature.RADIST: 53 width = shape[1] 54 55 # This normalisation factor can handle bad crmodes, 56 # As well as off-center scans 57 normalise_factor = abs((width // 2) - landmarks.left[0]) 58 59 total_distance = 0 60 61 for a, b in [ 62 (landmarks.left, landmarks.apex), 63 (landmarks.right, landmarks.apex), 64 ]: 65 # Get the distance between two points in 2D space 66 distance_x = abs(a[0] - b[0]) 67 distance_y = abs(a[1] - b[1]) 68 69 # Calculate the distance between the two points 70 distance = math.sqrt(distance_x**2 + distance_y**2) 71 72 # Normalise the distance 73 distance /= normalise_factor 74 75 # Add the distance to the total distance 76 total_distance += distance 77 78 # Calculate the angle of landmarks.left, landmarks.apex, landmarks.right 79 # This is the angle of the triangle 80 A, B, C = ( 81 np.array(landmarks.left), 82 np.array(landmarks.apex), 83 np.array(landmarks.right), 84 ) 85 AB = np.linalg.norm(A - B) 86 BC = np.linalg.norm(B - C) 87 AC = np.linalg.norm(A - C) 88 # in radians 89 angle = np.arccos((BC**2 + AB**2 - AC**2) / (2 * BC * AB)) 90 91 curvature = round(angle / total_distance, 2) 92 93 else: 94 raise ValueError(f"Curvature method {config.hip.curvature} not found") 95 96 return curvature 97 98 99def draw_curvature( 100 hip: HipDataUS, overlay: Overlay, config: Config 101) -> Overlay: 102 """ 103 Draw the curvature of the hip. 104 105 :param hip: HipDataUS: The HipDataUS object. 106 :param overlay: Overlay: The Overlay object. 107 :param config: Config: The Config object. 108 109 :return: Overlay: The Overlay object. 110 """ 111 curvature = hip.get_metric(MetricUS.CURVATURE) 112 113 if config.visuals.display_full_metric_names: 114 title = "Curvature" 115 else: 116 title = "Cur" 117 118 if curvature != 0: 119 overlay.draw_text( 120 f"{title}: {curvature}", 121 int(hip.landmarks.left[0]), 122 int(hip.landmarks.left[1] - 80), 123 header="h2", 124 ) 125 126 return overlay
def
find_curvature( landmarks: retuve.hip_us.classes.general.LandmarksUS, shape: Tuple, config: retuve.keyphrases.config.Config) -> float:
36def find_curvature( 37 landmarks: LandmarksUS, shape: Tuple, config: Config 38) -> float: 39 """ 40 Calculate the curvature of the hip. 41 42 :param landmarks: LandmarksUS: The landmarks object. 43 :param shape: Tuple: The shape of the image. 44 :param config: Config: The Config object. 45 46 :return: float: The curvature of the hip. 47 """ 48 if not ( 49 landmarks and landmarks.left and landmarks.apex and landmarks.right 50 ): 51 return 0 52 53 if config.hip.curvature_method == Curvature.RADIST: 54 width = shape[1] 55 56 # This normalisation factor can handle bad crmodes, 57 # As well as off-center scans 58 normalise_factor = abs((width // 2) - landmarks.left[0]) 59 60 total_distance = 0 61 62 for a, b in [ 63 (landmarks.left, landmarks.apex), 64 (landmarks.right, landmarks.apex), 65 ]: 66 # Get the distance between two points in 2D space 67 distance_x = abs(a[0] - b[0]) 68 distance_y = abs(a[1] - b[1]) 69 70 # Calculate the distance between the two points 71 distance = math.sqrt(distance_x**2 + distance_y**2) 72 73 # Normalise the distance 74 distance /= normalise_factor 75 76 # Add the distance to the total distance 77 total_distance += distance 78 79 # Calculate the angle of landmarks.left, landmarks.apex, landmarks.right 80 # This is the angle of the triangle 81 A, B, C = ( 82 np.array(landmarks.left), 83 np.array(landmarks.apex), 84 np.array(landmarks.right), 85 ) 86 AB = np.linalg.norm(A - B) 87 BC = np.linalg.norm(B - C) 88 AC = np.linalg.norm(A - C) 89 # in radians 90 angle = np.arccos((BC**2 + AB**2 - AC**2) / (2 * BC * AB)) 91 92 curvature = round(angle / total_distance, 2) 93 94 else: 95 raise ValueError(f"Curvature method {config.hip.curvature} not found") 96 97 return curvature
Calculate the curvature of the hip.
Parameters
- landmarks: LandmarksUS: The landmarks object.
- shape: Tuple: The shape of the image.
- config: Config: The Config object.
Returns
float: The curvature of the hip.
def
draw_curvature( hip: retuve.hip_us.classes.general.HipDataUS, overlay: retuve.classes.draw.Overlay, config: retuve.keyphrases.config.Config) -> retuve.classes.draw.Overlay:
100def draw_curvature( 101 hip: HipDataUS, overlay: Overlay, config: Config 102) -> Overlay: 103 """ 104 Draw the curvature of the hip. 105 106 :param hip: HipDataUS: The HipDataUS object. 107 :param overlay: Overlay: The Overlay object. 108 :param config: Config: The Config object. 109 110 :return: Overlay: The Overlay object. 111 """ 112 curvature = hip.get_metric(MetricUS.CURVATURE) 113 114 if config.visuals.display_full_metric_names: 115 title = "Curvature" 116 else: 117 title = "Cur" 118 119 if curvature != 0: 120 overlay.draw_text( 121 f"{title}: {curvature}", 122 int(hip.landmarks.left[0]), 123 int(hip.landmarks.left[1] - 80), 124 header="h2", 125 ) 126 127 return overlay
Draw the curvature of the hip.
Parameters
- hip: HipDataUS: The HipDataUS object.
- overlay: Overlay: The Overlay object.
- config: Config: The Config object.
Returns
Overlay: The Overlay object.