Spaces:
Build error
Build error
| import math | |
| import requests | |
| import numpy as np | |
| import json | |
| from io import BytesIO | |
| from fastapi import FastAPI | |
| from pydantic import BaseModel | |
| from ultralytics import YOLO | |
| from PIL import Image | |
| app = FastAPI() | |
| model = YOLO("posmPJSTRIKE_v1.3.pt") | |
| with open("base_width.json", "r") as f: | |
| base_width = json.load(f) | |
| with open("name_conversion.json", "r") as f: | |
| name_convert = json.load(f) | |
| class ImageRequest(BaseModel): | |
| image_url: str | |
| def get_image_from_url(image_url): | |
| response = requests.get(image_url) | |
| image = Image.open(BytesIO(response.content)).convert("RGB") | |
| return np.array(image) | |
| def name_conversion(actual_distances,object_positions, name_convert): | |
| actual_distances_sys = [] | |
| object_positions_sys = {} | |
| for item in actual_distances: | |
| actual_distances_sys.append({'object':(name_convert[list(item.values())[0][0]],name_convert[list(item.values())[0][1]]),'distances': str(list(item.values())[1]) + " cm"}) | |
| for item in object_positions: | |
| object_positions_sys.update({name_convert[item]:{"top": str(object_positions[item]['top']) + " cm", "bottom": str(object_positions[item]['bottom']) + " cm", "left": str(object_positions[item]['left']) + " cm", "right": str(object_positions[item]['right']) + " cm"}}) | |
| return object_positions_sys, actual_distances_sys | |
| def find_position(objects_names_points, par_pix_cm, image): | |
| object_positions = {} | |
| for obj in objects_names_points: | |
| name = list(obj.keys())[0] | |
| points = list(obj.values())[0] | |
| top_distance = round((points[0][1] - 0) * par_pix_cm[name], 2) | |
| bottom_distance = round((image.size[1] - points[3][1]) * par_pix_cm[name], 2) | |
| left_distance = round((points[0][0] - 0) * par_pix_cm[name], 2) | |
| right_distance = round((image.size[0] - points[3][0]) * par_pix_cm[name], 2) | |
| object_positions.update({name: {"top": top_distance, "bottom": bottom_distance, "left": left_distance, "right": right_distance}}) | |
| return object_positions | |
| def get_actual_distance(closest_points, par_pix_cm): | |
| actual_results_n_distance = [] | |
| for i in closest_points: | |
| avg_px_cm = ((par_pix_cm[i[0]] + par_pix_cm[i[1]]) / 2) | |
| actual_results_n_distance.append({'object': i, 'distances': round(closest_points[i] * avg_px_cm, 2)}) | |
| return actual_results_n_distance | |
| def pixel_per_cm(objects_names_width_pix): | |
| par_pix_cm = {} | |
| for i in objects_names_width_pix: | |
| par_pix_cm_width = base_width[i][0] / objects_names_width_pix[i][0] | |
| par_pix_cm_height = base_width[i][1] / objects_names_width_pix[i][1] | |
| avg_par_pix_cm = (par_pix_cm_width + par_pix_cm_height) / 2 | |
| par_pix_cm.update({i: avg_par_pix_cm}) | |
| return par_pix_cm | |
| def get_points_n_names(results): | |
| objects_names_points = [] | |
| objects_names_width_pix = {} | |
| for box, cls in zip(results[0].boxes.xyxy, results[0].boxes.cls): | |
| x1, y1, x2, y2 = map(int, box) | |
| class_name = results[0].names[int(cls)] | |
| width = x2 - x1 | |
| height = y2 - y1 | |
| objects_names_points.append({class_name: [(x1, y1), (x2, y1), (x1, y2), (x2, y2)]}) | |
| objects_names_width_pix.update({class_name: [width, height]}) | |
| return objects_names_points, objects_names_width_pix | |
| def euclidean_distance(point1, point2): | |
| dist_pixels = math.sqrt((point2[0] - point1[0])**2 + (point2[1] - point1[1])**2) | |
| return dist_pixels | |
| def find_closest_points(lst): | |
| closest_points = {} | |
| for i in range(len(lst)): | |
| for j in range(i + 1, len(lst)): | |
| list1 = lst[i] | |
| list2 = lst[j] | |
| min_distance = float('inf') | |
| closest_objects_pair = None | |
| for obj1 in list1.values(): | |
| points1 = obj1 | |
| for obj2 in list2.values(): | |
| points2 = obj2 | |
| for point1 in points1: | |
| for point2 in points2: | |
| distance = euclidean_distance(point1, point2) | |
| if distance < min_distance: | |
| min_distance = distance | |
| closest_objects_pair = (list1.keys(), list2.keys()) | |
| closest_points.update({(list(closest_objects_pair[0])[0], list(closest_objects_pair[1])[0]): round(min_distance, 2)}) | |
| return closest_points | |
| def process_image(request: ImageRequest): | |
| image = get_image_from_url(request.image_url) | |
| image = Image.fromarray(image) | |
| size = (640, 640) | |
| image.thumbnail(size) | |
| res = model(image) | |
| objects_names_points, objects_names_width_pix = get_points_n_names(res) | |
| par_pix_cm = pixel_per_cm(objects_names_width_pix) | |
| closest_points = find_closest_points(objects_names_points) | |
| actual_distances = get_actual_distance(closest_points, par_pix_cm) | |
| object_positions = find_position(objects_names_points, par_pix_cm, image) | |
| # Remove the distance between the same object | |
| for item in actual_distances[:]: | |
| if item['object'][0] == item['object'][1]: | |
| actual_distances.remove(item) | |
| # Convert the object names to the system names | |
| object_positions_sys, actual_distances_sys = name_conversion(actual_distances,object_positions, name_convert) | |
| return { | |
| "object_positions": object_positions_sys, | |
| "actual_distances": actual_distances_sys | |
| } |