Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import cv2 | |
| import numpy as np | |
| import json | |
| def preprocess(img): | |
| # Convert to grayscale | |
| img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) | |
| cv2.imwrite("1_gray.png", img_gray) | |
| # Blur the image | |
| img_blur = cv2.GaussianBlur(img_gray, (3, 3), 1) | |
| cv2.imwrite("2_blur.png", img_blur) | |
| # Detect edges with Canny | |
| img_canny = cv2.Canny(img_blur, 100, 200) | |
| cv2.imwrite("3_canny.png", img_canny) | |
| # Dilate the edges | |
| kernel = np.ones((3, 3)) | |
| img_dilate = cv2.dilate(img_canny, kernel, iterations=2) | |
| cv2.imwrite("4_dilate.png", img_dilate) | |
| # Erode the dilated edges | |
| img_erode = cv2.erode(img_dilate, kernel, iterations=1) | |
| cv2.imwrite("5_erode.png", img_erode) | |
| return img_erode | |
| def find_tip(points, convex_hull): | |
| length = len(points) | |
| indices = np.setdiff1d(range(length), convex_hull) | |
| for i in range(2): | |
| j = indices[i] + 2 | |
| if j > length - 1: | |
| j = length - j | |
| if np.all(points[j] == points[indices[i - 1] - 2]): | |
| return tuple(points[j]) | |
| def get_length(p1, p2): | |
| line_length = ((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2) ** 0.5 | |
| return line_length | |
| def get_angle(tip, tail): | |
| return (np.degrees(np.arctan2(tip[1] - tail[1], tip[0] - tail[0]))*-1) | |
| def get_max_distance_point(cnt, tip): | |
| max_distance = 0 | |
| max_point = None | |
| for [x, y] in cnt: | |
| distance = get_length((x, y), tip) | |
| if distance > max_distance: | |
| max_distance = distance | |
| max_point = (x, y) | |
| return max_point | |
| def find_tail(points, tip): | |
| tip = np.array(tip, dtype=np.float32) | |
| points = np.array(points, dtype=np.int32) | |
| # Find the tail point based on maximum distance | |
| tail_point = get_max_distance_point(points, tip) | |
| # Ensure that the tail point is sufficiently different from the tip | |
| if np.linalg.norm(np.array(tail_point) - np.array(tip)) > 5: | |
| return tail_point | |
| return None | |
| def draw_arrow(img_result, tip, tail, length, angle): | |
| # Draw arrow on the blank image with inverted tip and tail | |
| cv2.arrowedLine(img_result, tuple(tail), tuple(tip), (0, 255, 0), 3) | |
| """ | |
| # Add length and angle as text next to the tip point | |
| text_length = f"Length: {length:.2f}" | |
| text_angle = f"Angle: {angle:.2f}" | |
| cv2.putText(img_result, text_length, (tip[0] + 10, tip[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1, cv2.LINE_AA) | |
| cv2.putText(img_result, text_angle, (tip[0] + 10, tip[1] - 30), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1, cv2.LINE_AA) | |
| """ | |
| def infer(image_in): | |
| img = cv2.imread(image_in) | |
| contours, hierarchy = cv2.findContours(preprocess(img), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) | |
| # Create a blank image to accumulate arrows | |
| img_result = np.zeros_like(img) | |
| arrows_coordinates = [] | |
| for cnt in contours: | |
| peri = cv2.arcLength(cnt, True) | |
| approx = cv2.approxPolyDP(cnt, 0.025 * peri, True) | |
| hull = cv2.convexHull(approx, returnPoints=False) | |
| sides = len(hull) | |
| if 6 > sides > 3 and sides + 2 == len(approx): | |
| arrow_tip = find_tip(approx[:,0,:], hull.squeeze()) | |
| if arrow_tip : | |
| cv2.drawContours(img, [cnt], -1, (0, 255, 0), 3) | |
| cv2.circle(img, arrow_tip, 3, (0, 0, 255), cv2.FILLED) | |
| arrow_tail = find_tail(approx[:,0,:], arrow_tip) | |
| if arrow_tail : | |
| arrows_coordinates.append([list(arrow_tail), list(arrow_tip)]) | |
| cv2.circle(img, arrow_tail, 3, (255, 0, 0), cv2.FILLED) | |
| # Calculate length and angle | |
| arrow_length = get_length(arrow_tip, arrow_tail) | |
| arrow_angle = get_angle(arrow_tip, arrow_tail) | |
| # Draw arrow on the same blank image | |
| draw_arrow(img_result, arrow_tip, arrow_tail, arrow_length, arrow_angle) | |
| cv2.imwrite("Image_result.png", img) | |
| cv2.imwrite("Arrows_on_same_blank.png", img_result) | |
| print(f"arrows coordinates: {arrows_coordinates}") | |
| result_list = json.loads(f"{arrows_coordinates}") | |
| print(result_list) | |
| return "Image_result.png", "Arrows_on_same_blank.png", f"{arrows_coordinates}" | |
| gr.Interface( | |
| fn=infer, | |
| inputs=gr.Image( | |
| sources=["upload"], | |
| type="filepath" | |
| ), | |
| outputs=[ | |
| gr.Image(label="detected arrows"), | |
| gr.Image(label="vectors"), | |
| gr.Textbox(label="arrows coordinates") | |
| ], | |
| examples = ["example.png"] | |
| ).launch() |