arrow-detek / app.py
fffiloni's picture
Update app.py
4128b26 verified
raw
history blame
4.19 kB
import gradio as gr
import cv2
import numpy as np
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=1)
cv2.imwrite("4_dilate.png", img_dilate)
# Erode the dilated edges
img_erode = cv2.erode(img_dilate, kernel, iterations=0)
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_clockwise_angle(tip, tail):
return np.arctan2(tail[1] - tip[1], tail[0] - tip[0])
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)
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 8 >= 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 :
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_clockwise_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)
return "Image_result.png", "Arrows_on_same_blank.png"
gr.Interface(
fn=infer,
inputs=gr.Image(
sources=["upload"],
type="filepath"
),
outputs=[
gr.Image(),
gr.Image(),
]
).launch()