Download utils/utils_lines.py from 2nzi/PnLCalib: direct link, hf CLI and curl.
- Browser
- Download file 10.8 kB
-
https://huggingface.co/spaces/2nzi/PnLCalib/resolve/main/utils/utils_lines.py
- Command line
-
hf download hf://spaces/2nzi/PnLCalib/utils/utils_lines.py
-
curl -L -o utils_lines.py https://huggingface.co/spaces/2nzi/PnLCalib/resolve/main/utils/utils_lines.py
10.8 kB
| import sys | |
| import math | |
| import itertools | |
| import numpy as np | |
| from utils.utils_geometry import line_intersection | |
| from utils.utils_heatmap import generate_gaussian_array_vectorized_l | |
| class LineKeypointsDB(object): | |
| def __init__(self, data, image): | |
| self.lines_list = ["Big rect. left bottom", | |
| "Big rect. left main", | |
| "Big rect. left top", | |
| "Big rect. right bottom", | |
| "Big rect. right main", | |
| "Big rect. right top", | |
| "Goal left crossbar", | |
| "Goal left post left ", | |
| "Goal left post right", | |
| "Goal right crossbar", | |
| "Goal right post left", | |
| "Goal right post right", | |
| "Middle line", | |
| "Side line bottom", | |
| "Side line left", | |
| "Side line right", | |
| "Side line top", | |
| "Small rect. left bottom", | |
| "Small rect. left main", | |
| "Small rect. left top", | |
| "Small rect. right bottom", | |
| "Small rect. right main", | |
| "Small rect. right top"] | |
| self.keypoint_pair_list = [['Side line top', 'Side line left'], | |
| ['Side line top', 'Middle line'], | |
| ['Side line right', 'Side line top'], | |
| ['Side line left', 'Big rect. left top'], | |
| ['Big rect. left top', 'Big rect. left main'], | |
| ['Big rect. right top', 'Big rect. right main'], | |
| ['Side line right', 'Big rect. right top'], | |
| ['Side line left', 'Small rect. left top'], | |
| ['Small rect. left top', 'Small rect. left main'], | |
| ['Small rect. right top', 'Small rect. right main'], | |
| ['Side line right', 'Small rect. right top'], | |
| ['Goal left crossbar', 'Goal left post right'], | |
| ['Side line left', 'Goal left post right'], | |
| ['Side line right', 'Goal right post left'], | |
| ['Goal right crossbar', 'Goal right post left'], | |
| ['Goal left crossbar', 'Goal left post left '], | |
| ['Side line left', 'Goal left post left '], | |
| ['Side line right', 'Goal right post right'], | |
| ['Goal right crossbar', 'Goal right post right'], | |
| ['Side line left', 'Small rect. left bottom'], | |
| ['Small rect. left bottom', 'Small rect. left main'], | |
| ['Small rect. right bottom', 'Small rect. right main'], | |
| ['Side line right', 'Small rect. right bottom'], | |
| ['Side line left', 'Big rect. left bottom'], | |
| ['Big rect. left bottom', 'Big rect. left main'], | |
| ['Big rect. right main', 'Big rect. right bottom'], | |
| ['Side line right', 'Big rect. right bottom'], | |
| ['Side line left', 'Side line bottom'], | |
| ['Side line bottom', 'Middle line'], | |
| ['Side line bottom', 'Side line right']] | |
| self.line_keypoints_dict = {1: [24, 25], | |
| 2: [5, 25], | |
| 3: [4, 5], | |
| 4: [26, 27], | |
| 5: [6, 26], | |
| 6: [6, 7], | |
| 7: [12, 16], | |
| 8: [16, 17], | |
| 9: [12, 13], | |
| 10: [15, 19], | |
| 11: [14, 15], | |
| 12: [18, 19], | |
| 13: [2, 29], | |
| 14: [28, 30], | |
| 15: [1, 28], | |
| 16: [3, 30], | |
| 17: [1, 3], | |
| 18: [20, 21], | |
| 19: [9, 21], | |
| 20: [8, 9], | |
| 21: [22, 23], | |
| 22: [10, 22], | |
| 23: [10, 11]} | |
| self.data = data | |
| self.image = image | |
| _, self.h, self.w = self.image.size() | |
| self.size = (self.w, self.h) | |
| self.num_channels = len(self.lines_list) | |
| self.lines = {} | |
| self.keypoints = {} | |
| def get_tensor(self): | |
| self.get_lines() | |
| self.refine_point_lines() | |
| heatmap_tensor = generate_gaussian_array_vectorized_l(self.num_channels, self.lines, self.size, down_ratio=2, | |
| sigma=2) | |
| return heatmap_tensor | |
| def find_most_distanced_points(self, segment): | |
| # Generate all pairs of points in the segment | |
| point_pairs = list(itertools.combinations(segment, 2)) | |
| # Calculate the Euclidean distance for each pair of points | |
| distances = [math.dist((pair[0]['x'], pair[0]['y']), (pair[1]['x'], pair[1]['y'])) for pair in point_pairs] | |
| # Find the indices of the pair with the maximum distance | |
| max_distance_index = distances.index(max(distances)) | |
| # Extract the points from the pair with the maximum distance | |
| most_distanced_points = list(point_pairs[max_distance_index]) | |
| return most_distanced_points | |
| def get_main_keypoints(self): | |
| for count, pair in enumerate(self.keypoint_pair_list): | |
| if all(x in self.data.keys() for x in pair): | |
| x, y = line_intersection(self.data, pair, self.w, self.h) | |
| if not np.isnan(x): | |
| if (0 <= x < self.w and 0 <= y < self.h): | |
| self.keypoints[count + 1] = {'x': x, 'y': y, 'in_frame': True} | |
| else: | |
| self.keypoints[count + 1] = {'x': x, 'y': y, 'in_frame': False} | |
| else: | |
| self.keypoints[count + 1] = {'in_frame': False} | |
| else: | |
| self.keypoints[count + 1] = {'in_frame': False} | |
| def get_lines(self): | |
| for line in self.data.keys(): | |
| if line in self.lines_list: | |
| if len(self.data[line]) > 1: | |
| points = self.find_most_distanced_points(self.data[line]) | |
| x1, y1, x2, y2 = points[0]['x'], points[0]['y'], points[1]['x'], points[1]['y'] | |
| self.lines[self.lines_list.index(line) + 1] = {'x_1': x1 * self.w, 'y_1': y1 * self.h, | |
| 'x_2': x2 * self.w, 'y_2': y2 * self.h} | |
| def refine_point_lines(self): | |
| self.get_main_keypoints() | |
| for line in self.lines.keys(): | |
| p1 = np.array([self.lines[line]['x_1'], self.lines[line]['y_1']]) | |
| p2 = np.array([self.lines[line]['x_2'], self.lines[line]['y_2']]) | |
| kp_to_refine = self.line_keypoints_dict[line] | |
| kp1 = np.array([self.keypoints[kp_to_refine[0]]['x'], self.keypoints[kp_to_refine[0]]['y']]) if \ | |
| self.keypoints[kp_to_refine[0]]['in_frame'] else \ | |
| np.array([np.nan, np.nan]) | |
| kp2 = np.array([self.keypoints[kp_to_refine[1]]['x'], self.keypoints[kp_to_refine[1]]['y']]) if \ | |
| self.keypoints[kp_to_refine[1]]['in_frame'] else \ | |
| np.array([np.nan, np.nan]) | |
| if all(np.isnan(kp1)) and all(np.isnan(kp2)): | |
| continue | |
| elif not all(np.isnan(kp1)) and all(np.isnan(kp2)): | |
| dist1 = np.linalg.norm(p1 - kp1) | |
| dist2 = np.linalg.norm(p2 - kp1) | |
| if dist1 < dist2: | |
| self.lines[line]['x_1'] = kp1[0] | |
| self.lines[line]['y_1'] = kp1[1] | |
| else: | |
| self.lines[line]['x_2'] = kp1[0] | |
| self.lines[line]['y_2'] = kp1[1] | |
| elif all(np.isnan(kp1)) and not all(np.isnan(kp2)): | |
| dist1 = np.linalg.norm(p1 - kp2) | |
| dist2 = np.linalg.norm(p2 - kp2) | |
| if dist1 < dist2: | |
| self.lines[line]['x_1'] = kp2[0] | |
| self.lines[line]['y_1'] = kp2[1] | |
| else: | |
| self.lines[line]['x_2'] = kp2[0] | |
| self.lines[line]['y_2'] = kp2[1] | |
| else: | |
| dis11 = np.linalg.norm(p1 - kp1) | |
| dis12 = np.linalg.norm(p1 - kp2) | |
| dis21 = np.linalg.norm(p2 - kp1) | |
| dis22 = np.linalg.norm(p2 - kp2) | |
| min_distance_p1 = min(dis11, dis12) | |
| min_distance_p2 = min(dis21, dis22) | |
| if min_distance_p1 < min_distance_p2: | |
| if dis11 < dis12: | |
| self.lines[line]['x_1'] = kp1[0] | |
| self.lines[line]['y_1'] = kp1[1] | |
| self.lines[line]['x_2'] = kp2[0] | |
| self.lines[line]['y_2'] = kp2[1] | |
| else: | |
| self.lines[line]['x_1'] = kp2[0] | |
| self.lines[line]['y_1'] = kp2[1] | |
| self.lines[line]['x_2'] = kp1[0] | |
| self.lines[line]['y_2'] = kp1[1] | |
| else: | |
| if dis11 < dis21: | |
| self.lines[line]['x_1'] = kp1[0] | |
| self.lines[line]['y_1'] = kp1[1] | |
| self.lines[line]['x_2'] = kp2[0] | |
| self.lines[line]['y_2'] = kp2[1] | |
| else: | |
| self.lines[line]['x_1'] = kp2[0] | |
| self.lines[line]['y_1'] = kp2[1] | |
| self.lines[line]['x_2'] = kp1[0] | |
| self.lines[line]['y_2'] = kp1[1] | |