From 852168006916d194794568fde19957dadceff7c0 Mon Sep 17 00:00:00 2001 From: s460930 Date: Sat, 16 Jan 2021 15:04:34 +0100 Subject: [PATCH] SMART-61 rysowanie ruchem palca po canvasie i zapisywanie obrazka na dysk --- client/gestures/gesture_recognition.py | 10 ++-- client/gestures/simple_gestures_lib.py | 57 +++++++++++++++--- client/image.png | Bin 0 -> 1234 bytes client/test.py | 78 ------------------------- client/test2.py | 33 ----------- client/views/project_view.py | 78 ++++++++++++++----------- rest-app/db.sqlite3 | Bin 172032 -> 172032 bytes 7 files changed, 100 insertions(+), 156 deletions(-) create mode 100644 client/image.png delete mode 100644 client/test.py delete mode 100644 client/test2.py diff --git a/client/gestures/gesture_recognition.py b/client/gestures/gesture_recognition.py index 5b92954..2606f01 100644 --- a/client/gestures/gesture_recognition.py +++ b/client/gestures/gesture_recognition.py @@ -35,13 +35,15 @@ class MyVideoCapture: self.mp_drawing.draw_landmarks( image, hand_landmarks, self.mp_hands.HAND_CONNECTIONS) # if cv2.waitKey(33) == ord('s'): - fingers = {'index': (), 'middle': (), 'ring': (), 'pinky': ()} + # fingers = {'index': (), 'middle': (), 'ring': (), 'pinky': ()} + fingers = {} if results.multi_hand_landmarks: for hand_landmarks in results.multi_hand_landmarks: fingers['index'] = sgest.check_index_finger(hand_landmarks) - fingers['middle'] = sgest.check_middle_finger(hand_landmarks) - fingers['ring'] = sgest.check_ring_finger(hand_landmarks) - fingers['pinky'] = sgest.check_pinky_finger(hand_landmarks) + fingers['start_stop'] = sgest.get_start_stop(hand_landmarks) + # fingers['middle'] = sgest.check_middle_finger(hand_landmarks) + # fingers['ring'] = sgest.check_ring_finger(hand_landmarks) + # fingers['pinky'] = sgest.check_pinky_finger(hand_landmarks) else: fingers = None return fingers, image, success diff --git a/client/gestures/simple_gestures_lib.py b/client/gestures/simple_gestures_lib.py index 0121b91..37738e1 100644 --- a/client/gestures/simple_gestures_lib.py +++ b/client/gestures/simple_gestures_lib.py @@ -1,28 +1,62 @@ from math import sqrt +INDEX_FINGER_TOP = 8 +INDEX_FINGER_BOTTOM = 5 +MIDDLE_FINGER_TOP = 12 +MIDDLE_FINGER_BOTTOM = 9 +RING_FINGER_TOP = 16 +RING_FINGER_BOTTOM = 13 +PINKY_FINGER_TOP = 20 +PINKY_FINGER_BOTTOM = 17 +THUMB_TOP = 4 +THUMB_CENTER = 3 +THUMB_BOTTOM = 2 + def calculate_distance(ax, ay, bx, by): distance = sqrt(((bx - ax) ** 2 + (by - ay) ** 2)) return distance +def get_start_stop(hand_landmarks): + index_finger = check_index_finger(hand_landmarks) + middle_finger = check_middle_finger(hand_landmarks) + ring_finger = check_ring_finger(hand_landmarks) + pinky_finger = check_pinky_finger(hand_landmarks) + is_thumb_near_index = is_thumb_near_index_finger(hand_landmarks) + + if not index_finger['straight'] and middle_finger['straight'] and ring_finger['straight'] and pinky_finger['straight'] and is_thumb_near_index: + return 'start' + else: + thumb_top_y = hand_landmarks.landmark[THUMB_TOP].y + thumb_bottom_y = hand_landmarks.landmark[THUMB_BOTTOM].y + is_thumb_straight = check_finger(hand_landmarks, THUMB_TOP, THUMB_BOTTOM)['straight'] + if is_thumb_straight: + if thumb_bottom_y < thumb_top_y: + return 'stop' + else: + return 'nothing' + else: + return 'nothing' + + def check_index_finger(hand_landmarks): - return check_finger(hand_landmarks, 8, 5, 'wskazujacy') + return check_finger(hand_landmarks, INDEX_FINGER_TOP, INDEX_FINGER_BOTTOM) def check_middle_finger(hand_landmarks): - return check_finger(hand_landmarks, 12, 9, 'srodkowy') + return check_finger(hand_landmarks, MIDDLE_FINGER_TOP, MIDDLE_FINGER_BOTTOM) def check_ring_finger(hand_landmarks): - return check_finger(hand_landmarks, 16, 13, 'serdeczny') + return check_finger(hand_landmarks, RING_FINGER_TOP, RING_FINGER_BOTTOM) def check_pinky_finger(hand_landmarks): - return check_finger(hand_landmarks, 20, 17, 'maly') + return check_finger(hand_landmarks, PINKY_FINGER_TOP, PINKY_FINGER_BOTTOM) -def check_finger(hand_landmarks, top_idx, bottom_idx, name): +def check_finger(hand_landmarks, top_idx, bottom_idx): ax = hand_landmarks.landmark[top_idx].x ay = hand_landmarks.landmark[top_idx].y bx = hand_landmarks.landmark[bottom_idx].x @@ -35,7 +69,14 @@ def check_finger(hand_landmarks, top_idx, bottom_idx, name): distance_bottom_start = calculate_distance(ax, ay, bx, by) if distance_bottom_start < distance_top_bottom + 0.1: - result = name + '_wyprostowany' + straight = True else: - result = name + '_niewyprostowany' - return result, hand_landmarks.landmark[top_idx].x, hand_landmarks.landmark[top_idx].y + straight = False + return {'straight': straight, 'x': hand_landmarks.landmark[top_idx].x, 'y': hand_landmarks.landmark[top_idx].y} + + +def is_thumb_near_index_finger(hand_landmarks): + thumb_top = hand_landmarks.landmark[THUMB_TOP] + index_finger_top = hand_landmarks.landmark[INDEX_FINGER_TOP] + distance = calculate_distance(thumb_top.x, thumb_top.y, index_finger_top.x, index_finger_top.y) + return distance < 0.1 diff --git a/client/image.png b/client/image.png new file mode 100644 index 0000000000000000000000000000000000000000..43c179d309d54cb9f92790124c483e633b677aa0 GIT binary patch literal 1234 zcmeAS@N?(olHy`uVBq!ia0y~yV2Wa3V6@_30*W}QW>+yVu*~#yaSW-L^Y+%ktk(tt z4i~Le|NlQ-#qF%Qbj$h)AsdU&ojQH9ndvGv+JNrr^Y+WGAaALhqtx3BYO{4wct5JSbrw*n0N zfX-6@BXV3EaJP*AL$+~o&6=&>{Fn};_N-uN0Gd3(8H7Ce7!@p88lDI+Od92khQWZO zgIC+C86Kp=5@@)opE$z~9aaWQ79b)mWv0 z$NBSR91L|!8`)>i{Qg#;B5Ip6!-q1C`a_=;Z7gpq-Z{QpI#8Ya+)*I&rl6C5TY=s- z=L!+=B?U@F9QCg{#LR~G;P literal 0 HcmV?d00001 diff --git a/client/test.py b/client/test.py deleted file mode 100644 index d0b21ed..0000000 --- a/client/test.py +++ /dev/null @@ -1,78 +0,0 @@ -import PIL.Image -import PIL.ImageTk -import cv2 -import time -import tkinter - - -class App: - def __init__(self, window, window_title, video_source=0): - self.window = window - - self.window.title(window_title) - self.video_source = video_source - - # open video source (by default this will try to open the computer webcam) - self.vid = MyVideoCapture(self.video_source) - - # Create a canvas that can fit the above video source size - self.canvas = tkinter.Canvas(window, width=self.vid.width, height=self.vid.height) - self.canvas.pack() - - # Button that lets the user take a snapshot - self.btn_snapshot = tkinter.Button(window, text="Snapshot", width=50, command=self.snapshot) - self.btn_snapshot.pack(anchor=tkinter.CENTER, expand=True) - - # After it is called once, the update method will be automatically called every delay milliseconds - self.delay = 15 - self.update() - - self.window.mainloop() - - def snapshot(self): - # Get a frame from the video source - ret, frame = self.vid.get_frame() - - if ret: - cv2.imwrite("frame-" + time.strftime("%d-%m-%Y-%H-%M-%S") + ".jpg", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)) - - def update(self): - # Get a frame from the video source - ret, frame = self.vid.get_frame() - - if ret: - self.photo = PIL.ImageTk.PhotoImage(image=PIL.Image.fromarray(frame)) - self.canvas.create_image(0, 0, image=self.photo, anchor=tkinter.NW) - - self.window.after(self.delay, self.update) - - -class MyVideoCapture: - def __init__(self, video_source=0): - # Open the video source - self.vid = cv2.VideoCapture(video_source) - if not self.vid.isOpened(): - raise ValueError("Unable to open video source", video_source) - - # Get video source width and height - self.width = self.vid.get(cv2.CAP_PROP_FRAME_WIDTH) - self.height = self.vid.get(cv2.CAP_PROP_FRAME_HEIGHT) - - def get_frame(self): - if self.vid.isOpened(): - ret, frame = self.vid.read() - if ret: - # Return a boolean success flag and the current frame converted to BGR - return (ret, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) - else: - return (ret, None) - else: - return (ret, None) - - # Release the video source when the object is destroyed - def __del__(self): - if self.vid.isOpened(): - self.vid.release() - - -App(tkinter.Tk(), "Tkinter and OpenCV") diff --git a/client/test2.py b/client/test2.py deleted file mode 100644 index b873eee..0000000 --- a/client/test2.py +++ /dev/null @@ -1,33 +0,0 @@ -import cv2 -import tkinter as tk -from PIL import Image, ImageTk - - -class MainWindow(): - def __init__(self, window, cap): - self.window = window - self.cap = cap - self.width = self.cap.get(cv2.CAP_PROP_FRAME_WIDTH) - self.height = self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT) - self.interval = 20 # Interval in ms to get the latest frame - # Create canvas for image - self.canvas = tk.Canvas(self.window, width=self.width, height=self.height) - self.canvas.grid(row=0, column=0) - # Update image on canvas - self.update_image() - - def update_image(self): - # Get the latest frame and convert image format - self.image = cv2.cvtColor(self.cap.read()[1], cv2.COLOR_BGR2RGB) # to RGB - self.image = Image.fromarray(self.image) # to PIL format - self.image = ImageTk.PhotoImage(self.image) # to ImageTk format - # Update image - self.canvas.create_image(0, 0, anchor=tk.NW, image=self.image) - # Repeat every 'interval' ms - self.window.after(self.interval, self.update_image) - - -if __name__ == "__main__": - root = tk.Tk() - MainWindow(root, cv2.VideoCapture(0)) - root.mainloop() diff --git a/client/views/project_view.py b/client/views/project_view.py index 2b6e08b..ae936bc 100644 --- a/client/views/project_view.py +++ b/client/views/project_view.py @@ -1,8 +1,9 @@ import PIL.Image import PIL.ImageTk import tkinter as tk +import os -from constants import PROJECT_VIEW_NAME, FONT_SM, FONT, PROJECTS_VIEW_NAME +from constants import PROJECT_VIEW_NAME, FONT, PROJECTS_VIEW_NAME from gestures.gesture_recognition import MyVideoCapture from views.abstract_view import AbstractView @@ -15,14 +16,15 @@ class ProjectView(tk.Frame, AbstractView): self.window = controller self.main_view_controller = main_view_controller self.delay = 20 + self.canvas_width = 800 + self.canvas_height = 415 + self.start_draw = False self.vid = None self.vid_canvas = None self.canvas = None - self.index_label = None - self.middle_label = None - self.ring_label = None - self.pinky_label = None self.back_button = None + self.clear_button = None + self.save_button = None self.bottom_frame = None self.top_frame = None @@ -32,35 +34,29 @@ class ProjectView(tk.Frame, AbstractView): def start(self): self.vid = MyVideoCapture() - + self.canvas_width = self.window.winfo_width() + self.canvas_height = self.window.winfo_height() - 185 self.top_frame = tk.Frame(self, relief=tk.RAISED, borderwidth=0) self.top_frame.pack(fill=tk.BOTH, side=tk.TOP) - self.top_frame.columnconfigure(0, weight=2) - self.top_frame.columnconfigure(1, weight=1) - print(self.top_frame['width']) - print(self.top_frame['height']) - self.canvas = tk.Canvas(self.top_frame, width=465, height=415, bg="blue") - coord = 10, 50, 240, 210 - self.canvas.create_arc(coord, start=0, extent=150, fill="red") - self.canvas.grid(row=0, column=0, sticky=tk.W, rowspan=4) - self.index_label = tk.Label(self.top_frame, font=FONT_SM) - self.index_label.grid(row=0, column=1) - self.middle_label = tk.Label(self.top_frame, font=FONT_SM) - self.middle_label.grid(row=1, column=1) - self.ring_label = tk.Label(self.top_frame, font=FONT_SM) - self.ring_label.grid(row=2, column=1) - self.pinky_label = tk.Label(self.top_frame, font=FONT_SM) - self.pinky_label.grid(row=3, column=1) + self.canvas = tk.Canvas(self.top_frame, width=self.canvas_width, height=self.canvas_height, bg="white") + self.canvas.grid(row=0, column=0) self.bottom_frame = tk.Frame(self, relief=tk.RAISED, borderwidth=1) self.bottom_frame.pack(fill=tk.BOTH, side=tk.BOTTOM) self.bottom_frame.columnconfigure(0, weight=1) self.bottom_frame.columnconfigure(1, weight=1) + self.bottom_frame.columnconfigure(2, weight=15) self.back_button = tk.Button(self.bottom_frame, text="Back", font=FONT, command=lambda: self.back_to_projects_view()) - self.back_button.grid(row=0, column=0, sticky=tk.SW) + self.back_button.grid(row=0, column=0, sticky=tk.SW, pady=10, padx=5) + self.clear_button = tk.Button(self.bottom_frame, text="Clear", font=FONT, + command=lambda: self.clear_canvas()) + self.clear_button.grid(row=0, column=1, sticky=tk.SW, pady=10, padx=5) + self.save_button = tk.Button(self.bottom_frame, text="Save", font=FONT, + command=lambda: self.save()) + self.save_button.grid(row=0, column=2, sticky=tk.SW, pady=10, padx=5) self.vid_canvas = tk.Canvas(self.bottom_frame, width=self.vid.width, height=self.vid.height) - self.vid_canvas.grid(row=0, column=1, sticky=tk.E) + self.vid_canvas.grid(row=0, column=3, sticky=tk.E) self.update() @@ -69,11 +65,19 @@ class ProjectView(tk.Frame, AbstractView): if self.vid is not None: fingers, frame, success = self.vid.get_frame() if fingers is not None: - self.index_label['text'] = fingers['index'][0] - self.middle_label['text'] = fingers['middle'][0] - self.ring_label['text'] = fingers['ring'][0] - self.pinky_label['text'] = fingers['pinky'][0] - + index_finger = fingers['index'] + start_stop = fingers['start_stop'] + if start_stop == 'start': + print('start') + self.start_draw = True + elif start_stop == 'stop': + print('stop') + self.start_draw = False + if self.start_draw and index_finger['straight']: + x = index_finger['x'] + y = index_finger['y'] + x, y = self.scale_points(x, y) + self.canvas.create_line(x, y, x+1, y, x-1, y, tags='point', width=3) if success: self.photo = PIL.ImageTk.PhotoImage(image=PIL.Image.fromarray(frame)) self.vid_canvas.create_image(0, 0, image=self.photo, anchor=tk.NW) @@ -85,14 +89,22 @@ class ProjectView(tk.Frame, AbstractView): self.vid.release() self.destroy_widgets() + def clear_canvas(self): + self.canvas.delete('all') + + def save(self): + self.canvas.postscript(file='image.eps') + img = PIL.Image.open('image.eps') + img.save('image.png', 'png') + os.remove('image.eps') + def destroy_widgets(self): self.vid = None self.top_frame.destroy() self.canvas.destroy() self.bottom_frame.destroy() self.vid_canvas.destroy() - self.index_label.destroy() - self.middle_label.destroy() - self.ring_label.destroy() - self.pinky_label.destroy() self.back_button.destroy() + + def scale_points(self, x, y): + return x*self.canvas_width, y*self.canvas_height diff --git a/rest-app/db.sqlite3 b/rest-app/db.sqlite3 index fd1533f37f7b1cc9f15cf6ed458f24fefd857b34..67c44a64b22461af2d4b4af41e13b891cbd5907b 100644 GIT binary patch delta 57 zcmZoTz}0YoYl0LLBmYDhCm`9F(3-%wHG!#`SIE#z!O+CYz{twTT+i6h!rahodZ9d% L!ggLhrq2@rx;hU2 delta 57 zcmZoTz}0YoYl0LL!=Z^XPC&9Tp*4YVYXVa>uaJScf{~$>p^=rbk)D~QiLr&@^g?+i Mh3&k2OrIwL0QX=JVgLXD