-
Notifications
You must be signed in to change notification settings - Fork 0
/
HandCheckAI.py
179 lines (130 loc) · 5.5 KB
/
HandCheckAI.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# from PIL import Image
# img = Image.open(r"D:\New folder (2)\3226.png")
#
# angle = -4.6
# rotate_img= img.rotate(angle, expand = True)
# rotate_img.show()
import cv2
import mediapipe as mp
import numpy as np
import tkinter as tk
from tkinter import filedialog, ttk, Scrollbar
from PIL import Image, ImageTk
import os
import openpyxl
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(static_image_mode=False, max_num_hands=1, min_detection_confidence=0.4,
min_tracking_confidence=0.4)
mp_drawing = mp.solutions.drawing_utils
def calculate_angle_with_vertical(a, b):
a = np.array(a)
b = np.array(b)
vertical_vector = np.array([0, -1])
hand_vector = b - a
hand_vector = hand_vector / np.linalg.norm(hand_vector)
dot_product = np.dot(hand_vector, vertical_vector)
cross_product = np.cross(vertical_vector, hand_vector)
angle_rad = np.arccos(np.clip(dot_product, -1.0, 1.0))
angle_deg = np.degrees(angle_rad)
if cross_product < 0:
angle_deg = -angle_deg
return angle_deg
def preprocess_image(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Apply GaussianBlur to reduce noise
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# Apply CLAHE (Contrast Limited Adaptive Histogram Equalization)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
equalized = clahe.apply(blurred)
# Normalize the image
normalized = cv2.normalize(equalized, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX)
# Sharpen the image
kernel = np.array([[0, -1, 0],
[-1, 5, -1],
[0, -1, 0]])
sharpened = cv2.filter2D(normalized, -1, kernel)
return cv2.cvtColor(sharpened, cv2.COLOR_GRAY2BGR)
def process_image(image_path):
image_name = os.path.basename(image_path)
print(f"Processing image: {image_name}")
image = cv2.imread(image_path)
if image is None:
print(f"Không thể đọc ảnh từ đường dẫn: {image_path}")
return None, None, None, None
image = preprocess_image(image)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
results = hands.process(image_rgb)
angles = []
image_with_landmarks = np.copy(image_rgb)
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
mp_drawing.draw_landmarks(image_with_landmarks, hand_landmarks, mp_hands.HAND_CONNECTIONS)
wrist = [hand_landmarks.landmark[mp_hands.HandLandmark.WRIST].x * image.shape[1],
hand_landmarks.landmark[mp_hands.HandLandmark.WRIST].y * image.shape[0]]
middle_finger_tip = [hand_landmarks.landmark[mp_hands.HandLandmark.MIDDLE_FINGER_TIP].x * image.shape[1],
hand_landmarks.landmark[mp_hands.HandLandmark.MIDDLE_FINGER_TIP].y * image.shape[0]]
angle = calculate_angle_with_vertical(wrist, middle_finger_tip)
angles.append(angle)
if angles:
return image_with_landmarks, angles, image_name
else:
print('Không nhận diện được bàn tay hoặc không đủ điểm đặc trưng.')
return image_with_landmarks, None, image_name
def display_image(image, angles, image_name):
image = Image.fromarray(image)
image.thumbnail((400, 400))
imgtk = ImageTk.PhotoImage(image=image)
canvas.delete("all")
canvas_width = canvas.winfo_width()
canvas_height = canvas.winfo_height()
x_pos = (canvas_width - image.width) / 2
y_pos = (canvas_height - image.height) / 2
canvas.create_image(x_pos, y_pos, anchor=tk.NW, image=imgtk)
canvas.image = imgtk
info_text.config(state=tk.NORMAL)
info_text.delete(1.0, tk.END)
info_text.insert(tk.END, f"Image name: {image_name}\n\n")
if angles:
for i, angle in enumerate(angles):
info_text.insert(tk.END, f'Hand {i + 1}:\n')
info_text.insert(tk.END, f'Góc giữa cổ tay và ngón tay giữa: {angle:.2f} độ\n\n')
info_text.config(state=tk.DISABLED)
def save_to_excel(data):
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "Hand Angles"
headers = ["Image Name", "Hand", "Wrist to Middle Finger Angle"]
ws.append(headers)
for row in data:
ws.append(row)
excel_file = filedialog.asksaveasfilename(defaultextension=".xlsx", filetypes=[("Excel files", "*.xlsx")])
if excel_file:
wb.save(excel_file)
print(f"Dữ liệu đã được lưu vào file Excel: {excel_file}")
def open_file_dialog():
file_paths = filedialog.askopenfilenames(filetypes=[("Image files", "*.jpg *.jpeg *.png")])
data_to_save = []
for file_path in file_paths:
image, angles, image_name = process_image(file_path)
if image is not None:
display_image(image, angles, image_name)
if angles:
for i, angle in enumerate(angles):
data_to_save.append([image_name, f"Hand {i + 1}", angle])
if data_to_save:
save_to_excel(data_to_save)
root = tk.Tk()
root.title("Hand Angle Measurement")
root.geometry("800x600")
frame = tk.Frame(root)
frame.pack(fill=tk.BOTH, expand=True)
canvas = tk.Canvas(frame, width=600, height=400)
canvas.pack(pady=20)
info_text = tk.Text(frame, wrap=tk.WORD, height=10, width=100)
info_text.pack()
scrollbar = Scrollbar(frame, command=info_text.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
info_text.config(yscrollcommand=scrollbar.set)
open_button = ttk.Button(root, text="Open Images", command=open_file_dialog)
open_button.pack()
root.mainloop()