diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..a8c2003
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "python-envs.defaultEnvManager": "ms-python.python:conda",
+ "python-envs.defaultPackageManager": "ms-python.python:conda",
+ "python-envs.pythonProjects": []
+}
\ No newline at end of file
diff --git a/image/cropped_Right_1753179393.jpg b/image/cropped_Right_1753179393.jpg
new file mode 100644
index 0000000..97448f4
Binary files /dev/null and b/image/cropped_Right_1753179393.jpg differ
diff --git a/image/cropped_Right_1753179532.jpg b/image/cropped_Right_1753179532.jpg
new file mode 100644
index 0000000..7c1eadc
Binary files /dev/null and b/image/cropped_Right_1753179532.jpg differ
diff --git a/image/cropped_Right_1753179605.jpg b/image/cropped_Right_1753179605.jpg
new file mode 100644
index 0000000..ce5559a
Binary files /dev/null and b/image/cropped_Right_1753179605.jpg differ
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..e69de29
diff --git a/utils/GUI.py b/utils/GUI.py
index 1445fde..6dc875b 100644
--- a/utils/GUI.py
+++ b/utils/GUI.py
@@ -9,33 +9,44 @@ current_mode = None
current_cap = None
# 用于追踪当前模式和摄像头资源
+# 初始化图形界面主要的逻辑
def create_gui():
- root = tk.Tk()
- root.title("Gesture Recognition")
- root.geometry("800x600")
-
- canvas = tk.Canvas(root, width=640, height=480)
- canvas.pack()
- # 创建显示视频内容的画布
-
- camera_button = tk.Button(
- root,
- text="Use Camera for Real-time Recognition",
- command=lambda: switch_to_camera(canvas)
- )
- camera_button.pack(pady=10)
- # 启动摄像头实时识别的按钮
-
- video_button = tk.Button(
- root,
- text="Upload Video File for Processing",
- command=lambda: select_and_process_video(canvas, root)
- )
- video_button.pack(pady=10)
- # 上传并处理视频文件的按钮
-
- root.mainloop()
-
+ try:
+ print("开始创建GUI界面")
+ root = tk.Tk()
+ root.title("Gesture Recognition")
+ root.geometry("800x600")
+ print("GUI窗口创建成功")
+
+ canvas = tk.Canvas(root, width=640, height=480)
+ canvas.pack()
+ print("画布创建成功")
+
+ camera_button = tk.Button(
+ root,
+ text="Use Camera for Real-time Recognition",
+ command=lambda: switch_to_camera(canvas)
+ )
+ camera_button.pack(pady=10)
+ print("摄像头按钮创建成功")
+
+ video_button = tk.Button(
+ root,
+ text="Upload Video File for Processing",
+ command=lambda: select_and_process_video(canvas, root)
+ )
+ video_button.pack(pady=10)
+ print("视频上传按钮创建成功")
+
+ print("GUI界面创建完成,进入主循环")
+ root.mainloop()
+
+ except Exception as e:
+ print(f"[ERROR] 创建GUI时发生异常: {str(e)}")
+ import traceback
+ print(traceback.format_exc())
+
+# 切换到摄像头实时识别模式
def switch_to_camera(canvas):
global current_mode, current_cap
@@ -46,18 +57,18 @@ def switch_to_camera(canvas):
canvas.delete("all")
# 设置当前模式为摄像头并清空Canvas
-
- current_cap = cv2.VideoCapture(0)
+ current_cap = cv2.VideoCapture(1)
+ current_cap.open(0)
if not current_cap.isOpened():
messagebox.showerror("Error", "Cannot open camera")
current_mode = None
return
# 启动摄像头
-
start_camera(canvas, current_cap)
# 传入canvas和current_cap
+# 切换到视频流处理模式
def select_and_process_video(canvas, root):
global current_mode, current_cap
@@ -108,5 +119,9 @@ def start_camera(canvas, cap):
show_frame(canvas, cap, gesture_processor)
# 启动摄像头进行实时手势识别
+
+
+
+
if __name__ == "__main__":
create_gui()
\ No newline at end of file
diff --git a/utils/__pycache__/finger_drawer.cpython-312.pyc b/utils/__pycache__/finger_drawer.cpython-312.pyc
new file mode 100644
index 0000000..add88ae
Binary files /dev/null and b/utils/__pycache__/finger_drawer.cpython-312.pyc differ
diff --git a/utils/__pycache__/finger_drawer.cpython-38.pyc b/utils/__pycache__/finger_drawer.cpython-38.pyc
new file mode 100644
index 0000000..e7fb8b2
Binary files /dev/null and b/utils/__pycache__/finger_drawer.cpython-38.pyc differ
diff --git a/utils/__pycache__/gesture_data.cpython-312.pyc b/utils/__pycache__/gesture_data.cpython-312.pyc
new file mode 100644
index 0000000..6672389
Binary files /dev/null and b/utils/__pycache__/gesture_data.cpython-312.pyc differ
diff --git a/utils/__pycache__/gesture_data.cpython-38.pyc b/utils/__pycache__/gesture_data.cpython-38.pyc
new file mode 100644
index 0000000..9172fc1
Binary files /dev/null and b/utils/__pycache__/gesture_data.cpython-38.pyc differ
diff --git a/utils/__pycache__/hand_gesture.cpython-312.pyc b/utils/__pycache__/hand_gesture.cpython-312.pyc
new file mode 100644
index 0000000..aee7640
Binary files /dev/null and b/utils/__pycache__/hand_gesture.cpython-312.pyc differ
diff --git a/utils/__pycache__/hand_gesture.cpython-38.pyc b/utils/__pycache__/hand_gesture.cpython-38.pyc
new file mode 100644
index 0000000..31616d2
Binary files /dev/null and b/utils/__pycache__/hand_gesture.cpython-38.pyc differ
diff --git a/utils/__pycache__/index_finger.cpython-312.pyc b/utils/__pycache__/index_finger.cpython-312.pyc
new file mode 100644
index 0000000..a09d50e
Binary files /dev/null and b/utils/__pycache__/index_finger.cpython-312.pyc differ
diff --git a/utils/__pycache__/index_finger.cpython-38.pyc b/utils/__pycache__/index_finger.cpython-38.pyc
new file mode 100644
index 0000000..16e5445
Binary files /dev/null and b/utils/__pycache__/index_finger.cpython-38.pyc differ
diff --git a/utils/__pycache__/kalman_filter.cpython-312.pyc b/utils/__pycache__/kalman_filter.cpython-312.pyc
new file mode 100644
index 0000000..d4d5909
Binary files /dev/null and b/utils/__pycache__/kalman_filter.cpython-312.pyc differ
diff --git a/utils/__pycache__/kalman_filter.cpython-38.pyc b/utils/__pycache__/kalman_filter.cpython-38.pyc
new file mode 100644
index 0000000..0e861b3
Binary files /dev/null and b/utils/__pycache__/kalman_filter.cpython-38.pyc differ
diff --git a/utils/__pycache__/model.cpython-312.pyc b/utils/__pycache__/model.cpython-312.pyc
new file mode 100644
index 0000000..7b25e92
Binary files /dev/null and b/utils/__pycache__/model.cpython-312.pyc differ
diff --git a/utils/__pycache__/model.cpython-38.pyc b/utils/__pycache__/model.cpython-38.pyc
new file mode 100644
index 0000000..8752477
Binary files /dev/null and b/utils/__pycache__/model.cpython-38.pyc differ
diff --git a/utils/__pycache__/process_images.cpython-312.pyc b/utils/__pycache__/process_images.cpython-312.pyc
new file mode 100644
index 0000000..0e65967
Binary files /dev/null and b/utils/__pycache__/process_images.cpython-312.pyc differ
diff --git a/utils/__pycache__/process_images.cpython-38.pyc b/utils/__pycache__/process_images.cpython-38.pyc
new file mode 100644
index 0000000..8616095
Binary files /dev/null and b/utils/__pycache__/process_images.cpython-38.pyc differ
diff --git a/utils/__pycache__/video_recognition.cpython-312.pyc b/utils/__pycache__/video_recognition.cpython-312.pyc
new file mode 100644
index 0000000..8b2c033
Binary files /dev/null and b/utils/__pycache__/video_recognition.cpython-312.pyc differ
diff --git a/utils/__pycache__/video_recognition.cpython-38.pyc b/utils/__pycache__/video_recognition.cpython-38.pyc
new file mode 100644
index 0000000..f7e40e5
Binary files /dev/null and b/utils/__pycache__/video_recognition.cpython-38.pyc differ
diff --git a/utils/gesture_recognition.ipynb b/utils/gesture_recognition.ipynb
index 9140a89..453b574 100644
--- a/utils/gesture_recognition.ipynb
+++ b/utils/gesture_recognition.ipynb
@@ -2,14 +2,16 @@
"cells": [
{
"cell_type": "code",
+ "execution_count": 1,
"id": "initial_id",
"metadata": {
- "collapsed": true,
"ExecuteTime": {
"end_time": "2024-09-07T05:11:28.761076Z",
"start_time": "2024-09-07T05:11:22.404354Z"
- }
+ },
+ "collapsed": true
},
+ "outputs": [],
"source": [
"import cv2\n",
"import time\n",
@@ -17,18 +19,19 @@
"import numpy as np\n",
"from collections import deque\n",
"from filterpy.kalman import KalmanFilter"
- ],
- "outputs": [],
- "execution_count": 1
+ ]
},
{
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "40aada17ccd31fe",
"metadata": {
"ExecuteTime": {
"end_time": "2024-09-07T05:11:28.777139Z",
"start_time": "2024-09-07T05:11:28.761076Z"
}
},
- "cell_type": "code",
+ "outputs": [],
"source": [
"gesture_locked = {'Left':False,'Right':False}\n",
"gesture_start_time = {'Left':0,'Right':0}\n",
@@ -48,19 +51,19 @@
"rect_draw_time = {'Left':0,'Right':0}\n",
"last_drawn_box = {'Left':None,'Right':None}\n",
"elapsed_time = {'Left':0,'Right':0}"
- ],
- "id": "40aada17ccd31fe",
- "outputs": [],
- "execution_count": 2
+ ]
},
{
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "2ee9323bb1c25cc0",
"metadata": {
"ExecuteTime": {
"end_time": "2024-09-07T05:11:28.824573Z",
"start_time": "2024-09-07T05:11:28.777139Z"
}
},
- "cell_type": "code",
+ "outputs": [],
"source": [
"def clear_hand_states(detected_hand ='Both'):\n",
" global gesture_locked, gesture_start_time, buffer_start_time, dragging, drag_point, buffer_duration,is_index_finger_up, trajectory,wait_time,kalman_wait_time, start_drag_time, rect_draw_time, last_drawn_box, wait_box, elapsed_time\n",
@@ -86,19 +89,19 @@
" last_drawn_box[h] = None\n",
" elapsed_time[h] = 0\n",
" # 清空没被检测的手"
- ],
- "id": "2ee9323bb1c25cc0",
- "outputs": [],
- "execution_count": 3
+ ]
},
{
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "96cf431d2562e7d",
"metadata": {
"ExecuteTime": {
"end_time": "2024-09-07T05:11:28.855831Z",
"start_time": "2024-09-07T05:11:28.824573Z"
}
},
- "cell_type": "code",
+ "outputs": [],
"source": [
"kalman_filters = {\n",
" 'Left': KalmanFilter(dim_x=4, dim_z=2),\n",
@@ -127,19 +130,19 @@
" kf.x = np.array([x, y, 0., 0.])\n",
" kf.P *= 1000.\n",
" # 重置"
- ],
- "id": "96cf431d2562e7d",
- "outputs": [],
- "execution_count": 4
+ ]
},
{
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "edc274b7ed495122",
"metadata": {
"ExecuteTime": {
"end_time": "2024-09-07T05:11:28.887346Z",
"start_time": "2024-09-07T05:11:28.855831Z"
}
},
- "cell_type": "code",
+ "outputs": [],
"source": [
"\n",
"mp_hands = mediapipe.solutions.hands\n",
@@ -154,19 +157,19 @@
"\n",
"mp_drawing = mediapipe.solutions.drawing_utils\n",
"clear_hand_states()"
- ],
- "id": "edc274b7ed495122",
- "outputs": [],
- "execution_count": 5
+ ]
},
{
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "51ff809ecaf1f899",
"metadata": {
"ExecuteTime": {
"end_time": "2024-09-07T05:11:28.934274Z",
"start_time": "2024-09-07T05:11:28.887346Z"
}
},
- "cell_type": "code",
+ "outputs": [],
"source": [
"def process_image(image):\n",
"\n",
@@ -256,7 +259,7 @@
" contour = np.array(trajectory[temp_handness], dtype=np.int32)\n",
" rect = cv2.minAreaRect(contour)\n",
" box = cv2.boxPoints(rect)\n",
- " box = np.int0(box)\n",
+ " box = np.int64(box)\n",
" rect_draw_time[temp_handness] = time.time()\n",
" last_drawn_box[temp_handness] = box\n",
" # 如果指向操作结束 轨迹列表有至少四个点的时候\n",
@@ -334,19 +337,53 @@
" # 如果没检测到手就清空全部信息\n",
" \n",
" return image"
- ],
- "id": "51ff809ecaf1f899",
- "outputs": [],
- "execution_count": 6
+ ]
},
{
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b7ce23e80ed36041",
"metadata": {
"ExecuteTime": {
"end_time": "2024-09-07T05:19:32.248575Z",
"start_time": "2024-09-07T05:11:28.934663Z"
}
},
- "cell_type": "code",
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "C:\\Users\\25055\\AppData\\Local\\Temp\\ipykernel_4200\\752492595.py:89: DeprecationWarning: `np.int0` is a deprecated alias for `np.intp`. (Deprecated NumPy 1.24)\n",
+ " box = np.int0(box)\n"
+ ]
+ },
+ {
+ "ename": "KeyboardInterrupt",
+ "evalue": "",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[1;32mIn[7], line 10\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCamera Error\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 8\u001b[0m \u001b[38;5;28;01mbreak\u001b[39;00m\n\u001b[1;32m---> 10\u001b[0m frame \u001b[38;5;241m=\u001b[39m \u001b[43mprocess_image\u001b[49m\u001b[43m(\u001b[49m\u001b[43mframe\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 11\u001b[0m cv2\u001b[38;5;241m.\u001b[39mimshow(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mVideo\u001b[39m\u001b[38;5;124m'\u001b[39m, frame)\n\u001b[0;32m 13\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m cv2\u001b[38;5;241m.\u001b[39mwaitKey(\u001b[38;5;241m1\u001b[39m) \u001b[38;5;241m&\u001b[39m \u001b[38;5;241m0xFF\u001b[39m \u001b[38;5;241m==\u001b[39m \u001b[38;5;28mord\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mq\u001b[39m\u001b[38;5;124m'\u001b[39m):\n",
+ "Cell \u001b[1;32mIn[6], line 9\u001b[0m, in \u001b[0;36mprocess_image\u001b[1;34m(image)\u001b[0m\n\u001b[0;32m 6\u001b[0m image \u001b[38;5;241m=\u001b[39m cv2\u001b[38;5;241m.\u001b[39mcvtColor(image, cv2\u001b[38;5;241m.\u001b[39mCOLOR_BGR2RGB)\n\u001b[0;32m 7\u001b[0m \u001b[38;5;66;03m# 预处理帧\u001b[39;00m\n\u001b[1;32m----> 9\u001b[0m results \u001b[38;5;241m=\u001b[39m \u001b[43mhands\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprocess\u001b[49m\u001b[43m(\u001b[49m\u001b[43mimage\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 11\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m results\u001b[38;5;241m.\u001b[39mmulti_hand_landmarks:\n\u001b[0;32m 12\u001b[0m \u001b[38;5;66;03m# 如果检测到手\u001b[39;00m\n\u001b[0;32m 14\u001b[0m handness_str \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m'\u001b[39m\n",
+ "File \u001b[1;32md:\\app-install-dict\\Anaconda3\\envs\\software_engineering\\lib\\site-packages\\mediapipe\\python\\solutions\\hands.py:153\u001b[0m, in \u001b[0;36mHands.process\u001b[1;34m(self, image)\u001b[0m\n\u001b[0;32m 132\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mprocess\u001b[39m(\u001b[38;5;28mself\u001b[39m, image: np\u001b[38;5;241m.\u001b[39mndarray) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m NamedTuple:\n\u001b[0;32m 133\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Processes an RGB image and returns the hand landmarks and handedness of each detected hand.\u001b[39;00m\n\u001b[0;32m 134\u001b[0m \n\u001b[0;32m 135\u001b[0m \u001b[38;5;124;03m Args:\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 150\u001b[0m \u001b[38;5;124;03m right hand) of the detected hand.\u001b[39;00m\n\u001b[0;32m 151\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[1;32m--> 153\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprocess\u001b[49m\u001b[43m(\u001b[49m\u001b[43minput_data\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mimage\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mimage\u001b[49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\n",
+ "File \u001b[1;32md:\\app-install-dict\\Anaconda3\\envs\\software_engineering\\lib\\site-packages\\mediapipe\\python\\solution_base.py:335\u001b[0m, in \u001b[0;36mSolutionBase.process\u001b[1;34m(self, input_data)\u001b[0m\n\u001b[0;32m 329\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 330\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_graph\u001b[38;5;241m.\u001b[39madd_packet_to_input_stream(\n\u001b[0;32m 331\u001b[0m stream\u001b[38;5;241m=\u001b[39mstream_name,\n\u001b[0;32m 332\u001b[0m packet\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_make_packet(input_stream_type,\n\u001b[0;32m 333\u001b[0m data)\u001b[38;5;241m.\u001b[39mat(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_simulated_timestamp))\n\u001b[1;32m--> 335\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_graph\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mwait_until_idle\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 336\u001b[0m \u001b[38;5;66;03m# Create a NamedTuple object where the field names are mapping to the graph\u001b[39;00m\n\u001b[0;32m 337\u001b[0m \u001b[38;5;66;03m# output stream names.\u001b[39;00m\n\u001b[0;32m 338\u001b[0m solution_outputs \u001b[38;5;241m=\u001b[39m collections\u001b[38;5;241m.\u001b[39mnamedtuple(\n\u001b[0;32m 339\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mSolutionOutputs\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_output_stream_type_info\u001b[38;5;241m.\u001b[39mkeys())\n",
+ "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
+ ]
+ },
+ {
+ "ename": "",
+ "evalue": "",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m在当前单元格或上一个单元格中执行代码时 Kernel 崩溃。\n",
+ "\u001b[1;31m请查看单元格中的代码,以确定故障的可能原因。\n",
+ "\u001b[1;31m单击此处了解详细信息。\n",
+ "\u001b[1;31m有关更多详细信息,请查看 Jupyter log。"
+ ]
+ }
+ ],
"source": [
"cap = cv2.VideoCapture(1)\n",
"cap.open(0)\n",
@@ -365,37 +402,34 @@
" \n",
"cap.release()\n",
"cv2.destroyAllWindows() "
- ],
- "id": "b7ce23e80ed36041",
- "outputs": [],
- "execution_count": 7
+ ]
},
{
- "metadata": {},
"cell_type": "code",
- "outputs": [],
"execution_count": null,
- "source": "",
- "id": "10fca4bc34a944ea"
+ "id": "10fca4bc34a944ea",
+ "metadata": {},
+ "outputs": [],
+ "source": []
}
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3",
+ "display_name": "software_engineering",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
- "version": 2
+ "version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
- "pygments_lexer": "ipython2",
- "version": "2.7.6"
+ "pygments_lexer": "ipython3",
+ "version": "3.8.20"
}
},
"nbformat": 4,
diff --git a/utils/hand_gesture.py b/utils/hand_gesture.py
index 69e6bc2..454c93a 100644
--- a/utils/hand_gesture.py
+++ b/utils/hand_gesture.py
@@ -3,7 +3,7 @@ from model import HandTracker
from index_finger import IndexFingerHandler
from gesture_data import HandState
from kalman_filter import KalmanHandler
-from utils.finger_drawer import FingerDrawer
+from finger_drawer import FingerDrawer
class HandGestureHandler:
def __init__(self):
diff --git a/utils/index_finger.py b/utils/index_finger.py
index 0c6bfed..281d50c 100644
--- a/utils/index_finger.py
+++ b/utils/index_finger.py
@@ -78,7 +78,7 @@ class IndexFingerHandler:
contour = np.array(self.hand_state.trajectory[temp_handness], dtype=np.int32)
rect = cv2.minAreaRect(contour)
box = cv2.boxPoints(rect)
- box = np.int0(box)
+ box = np.int64(box)
# 当拖拽点数大于4时则计算最小外接矩形
self.hand_state.rect_draw_time[temp_handness] = time.time()
self.hand_state.last_drawn_box[temp_handness] = box
diff --git a/utils/main.py b/utils/main.py
deleted file mode 100644
index 48b719e..0000000
--- a/utils/main.py
+++ /dev/null
@@ -1,278 +0,0 @@
-import cv2
-import time
-import mediapipe
-import numpy as np
-from collections import deque
-from filterpy.kalman import KalmanFilter
-
-gesture_locked = {'Left':False,'Right':False}
-gesture_start_time = {'Left':0,'Right':0}
-buffer_start_time = {'Left':0,'Right':0}
-start_drag_time = {'Left':0,'Right':0}
-dragging = {'Left':False,'Right':False}
-drag_point = {'Left':(0, 0),'Right':(0, 0)}
-buffer_duration = {'Left':0.25,'Right':0.25}
-is_index_finger_up = {'Left':False,'Right':False}
-index_finger_second = {'Left':0,'Right':0}
-index_finger_tip = {'Left':0,'Right':0}
-trajectory = {'Left':[],'Right':[]}
-square_queue = deque()
-wait_time = 1.5
-kalman_wait_time = 0.5
-wait_box = 2
-rect_draw_time = {'Left':0,'Right':0}
-last_drawn_box = {'Left':None,'Right':None}
-elapsed_time = {'Left':0,'Right':0}
-
-def clear_hand_states(detected_hand ='Both'):
- global gesture_locked, gesture_start_time, buffer_start_time, dragging, drag_point, buffer_duration,is_index_finger_up, trajectory,wait_time,kalman_wait_time, start_drag_time, rect_draw_time, last_drawn_box, wait_box, elapsed_time
-
- hands_to_clear = {'Left', 'Right'}
- if detected_hand == 'Both':
- hands_to_clear = hands_to_clear
- else:
- hands_to_clear -= {detected_hand}
- # 反向判断左右手
-
- for h in hands_to_clear:
- gesture_locked[h] = False
- gesture_start_time[h] = 0
- buffer_start_time[h] = 0
- dragging[h] = False
- drag_point[h] = (0, 0)
- buffer_duration[h] = 0.25
- is_index_finger_up[h] = False
- trajectory[h].clear()
- start_drag_time[h] = 0
- rect_draw_time[h] = 0
- last_drawn_box[h] = None
- elapsed_time[h] = 0
- # 清空没被检测的手
-
-kalman_filters = {
- 'Left': KalmanFilter(dim_x=4, dim_z=2),
- 'Right': KalmanFilter(dim_x=4, dim_z=2)
-}
-
-for key in kalman_filters:
- kalman_filters[key].x = np.array([0., 0., 0., 0.])
- kalman_filters[key].F = np.array([[1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]])
- # 状态转移矩阵
- kalman_filters[key].H = np.array([[1, 0, 0, 0], [0, 1, 0, 0]])
- # 观测矩阵
- kalman_filters[key].P *= 1000.
- kalman_filters[key].R = 3
- kalman_filters[key].Q = np.eye(4) * 0.01
-
-def kalman_filter_point(hand_label, x, y):
- kf = kalman_filters[hand_label]
- kf.predict()
- kf.update([x, y])
- # 更新状态
- return (kf.x[0], kf.x[1])
-
-def reset_kalman_filter(hand_label, x, y):
- kf = kalman_filters[hand_label]
- kf.x = np.array([x, y, 0., 0.])
- kf.P *= 1000.
- # 重置
-
-mp_hands = mediapipe.solutions.hands
-
-hands = mp_hands.Hands(
- static_image_mode=False,
- max_num_hands=2,
- # 一只更稳定
- min_detection_confidence=0.5,
- min_tracking_confidence=0.5
-)
-
-mp_drawing = mediapipe.solutions.drawing_utils
-clear_hand_states()
-
-def process_image(image):
-
- start_time = time.time()
- height, width = image.shape[:2]
- image = cv2.flip(image, 1)
- image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
- # 预处理帧
-
- results = hands.process(image)
-
- if results.multi_hand_landmarks:
- # 如果检测到手
-
- handness_str = ''
- index_finger_tip_str = ''
-
- if len(results.multi_hand_landmarks) == 1:
- clear_hand_states(detected_hand = results.multi_handedness[0].classification[0].label)
- # 如果只有一只手 则清空另一只手的数据 避免后续冲突导致不稳定
-
- for hand_idx in range(len(results.multi_hand_landmarks)):
-
- hand_21 = results.multi_hand_landmarks[hand_idx]
- mp_drawing.draw_landmarks(image, hand_21, mp_hands.HAND_CONNECTIONS)
-
- temp_handness = results.multi_handedness[hand_idx].classification[0].label
- handness_str += '{}:{}, '.format(hand_idx, temp_handness)
- is_index_finger_up[temp_handness] = False
- # 先设置为false 防止放下被错误更新为竖起
-
- cz0 = hand_21.landmark[0].z
- index_finger_second[temp_handness] = hand_21.landmark[7]
- index_finger_tip[temp_handness] = hand_21.landmark[8]
- # 食指指尖和第一个关节
-
- index_x, index_y = int(index_finger_tip[temp_handness].x * width), int(index_finger_tip[temp_handness].y * height)
-
- if all(index_finger_second[temp_handness].y < hand_21.landmark[i].y for i in range(21) if i not in [7, 8]) and index_finger_tip[temp_handness].y < index_finger_second[temp_handness].y:
- is_index_finger_up[temp_handness] = True
- # 如果指尖和第二个关节高度大于整只手所有关节点 则视为执行“指向”操作
-
- if is_index_finger_up[temp_handness]:
- if not gesture_locked[temp_handness]:
- if gesture_start_time[temp_handness] == 0:
- gesture_start_time[temp_handness] = time.time()
- # 记录食指抬起的时间
- elif time.time() - gesture_start_time[temp_handness] > wait_time:
- dragging[temp_handness] = True
- gesture_locked[temp_handness] = True
- drag_point[temp_handness] = (index_x, index_y)
- # 如果食指抬起的时间大于预设的等待时间则视为执行“指向”操作
- buffer_start_time[temp_handness] = 0
- # 检测到食指竖起就刷新缓冲时间
- else:
- if buffer_start_time[temp_handness] == 0:
- buffer_start_time[temp_handness] = time.time()
- elif time.time() - buffer_start_time[temp_handness] > buffer_duration[temp_handness]:
- gesture_start_time[temp_handness] = 0
- gesture_locked[temp_handness] = False
- dragging[temp_handness] = False
- # 如果缓冲时间大于设定 就证明已经结束指向操作
- # 这样可以防止某一帧识别有误导致指向操作被错误清除
-
- if dragging[temp_handness]:
-
- if start_drag_time[temp_handness] == 0:
- start_drag_time[temp_handness] = time.time()
- reset_kalman_filter(temp_handness, index_x, index_y)
- # 每次画线的时候初始化滤波器
-
- smooth_x, smooth_y = kalman_filter_point(temp_handness, index_x, index_y)
- drag_point[temp_handness] = (index_x, index_y)
- index_finger_radius = max(int(10 * (1 + (cz0 - index_finger_tip[temp_handness].z) * 5)), 0)
- cv2.circle(image, drag_point[temp_handness], index_finger_radius, (0, 0, 255), -1)
- # 根据离掌根的深度距离来构建一个圆
- # 用来显示已经开始指向操作
- # 和下方构建的深度点位对应 直接用倍数
- drag_point_smooth = (smooth_x, smooth_y)
-
- if time.time() - start_drag_time[temp_handness] > kalman_wait_time:
- trajectory[temp_handness].append(drag_point_smooth)
- # 因为kalman滤波器初始化的时候会很不稳定 前几帧通常会有较为严重的噪声
- # 所以直接等待前几帧运行完成之后再将点位加到轨迹列表中
- else:
- if len(trajectory[temp_handness]) > 4:
- contour = np.array(trajectory[temp_handness], dtype=np.int32)
- rect = cv2.minAreaRect(contour)
- box = cv2.boxPoints(rect)
- box = np.int0(box)
- rect_draw_time[temp_handness] = time.time()
- last_drawn_box[temp_handness] = box
- # 如果指向操作结束 轨迹列表有至少四个点的时候
- # 使用最小包围图形将画的不规则图案调整为一个矩形
-
- start_drag_time[temp_handness] = 0
- trajectory[temp_handness].clear()
-
- for i in range(1, len(trajectory[temp_handness])):
-
- pt1 = (int(trajectory[temp_handness][i-1][0]), int(trajectory[temp_handness][i-1][1]))
- pt2 = (int(trajectory[temp_handness][i][0]), int(trajectory[temp_handness][i][1]))
- cv2.line(image, pt1, pt2, (0, 0, 255), 2)
- # 绘制连接轨迹点的线
-
- if last_drawn_box[temp_handness] is not None:
- elapsed_time[temp_handness] = time.time() - rect_draw_time[temp_handness]
-
- if elapsed_time[temp_handness] < wait_box:
- cv2.drawContours(image, [last_drawn_box[temp_handness]], 0, (0, 255, 0), 2)
- # 将矩形框保留一段时间 否则一帧太快 无法看清效果
-
- elif elapsed_time[temp_handness] >= wait_box - 0.1:
-
- box = last_drawn_box[temp_handness]
- x_min = max(0, min(box[:, 0]))
- y_min = max(0, min(box[:, 1]))
- x_max = min(image.shape[1], max(box[:, 0]))
- y_max = min(image.shape[0], max(box[:, 1]))
- cropped_image = image[y_min:y_max, x_min:x_max]
- filename = f"../image/cropped_{temp_handness}_{int(time.time())}.jpg"
- cv2.imwrite(filename, cropped_image)
- last_drawn_box[temp_handness] = None
- # 不能直接剪裁画完的图像 可能会错误的将手剪裁进去
- # 等待一段时间 有一个给手缓冲移动走的时间再将这一帧里的矩形提取出来
-
- for i in range(21):
-
- cx = int(hand_21.landmark[i].x * width)
- cy = int(hand_21.landmark[i].y * height)
- cz = hand_21.landmark[i].z
- depth_z = cz0 - cz
- radius = max(int(6 * (1 + depth_z*5)), 0)
-
- if i == 0:
- image = cv2.circle(image, (cx, cy), radius, (255, 255, 0), thickness=-1)
- if i == 8:
- image = cv2.circle(image, (cx, cy), radius, (255, 165, 0), thickness=-1)
- index_finger_tip_str += '{}:{:.2f}, '.format(hand_idx, depth_z)
- if i in [1,5,9,13,17]:
- image = cv2.circle(image, (cx, cy), radius, (0, 0, 255), thickness=-1)
- if i in [2,6,10,14,18]:
- image = cv2.circle(image, (cx, cy), radius, (75, 0, 130), thickness=-1)
- if i in [3,7,11,15,19]:
- image = cv2.circle(image, (cx, cy), radius, (238, 130, 238), thickness=-1)
- if i in [4,12,16,20]:
- image = cv2.circle(image, (cx, cy), radius, (0, 255, 255), thickness=-1)
- # 提取出每一个关节点 赋予对应的颜色和根据掌根的深度
-
- scaler= 1
- image = cv2.putText(image,handness_str, (25*scaler, 100*scaler), cv2.FONT_HERSHEY_SIMPLEX, 1.25*scaler, (0,0,255), 2,)
- image = cv2.putText(image,index_finger_tip_str, (25*scaler, 150*scaler), cv2.FONT_HERSHEY_SIMPLEX, 1.25*scaler, (0,0,255), 2,)
-
- spend_time = time.time() - start_time
- if spend_time > 0:
- FPS = 1.0 / spend_time
- else:
- FPS = 0
-
- image = cv2.putText(image,'FPS '+str(int(FPS)),(25*scaler,50*scaler),cv2.FONT_HERSHEY_SIMPLEX,1.25*scaler,(0,0,255),2,)
- # 显示FPS 检测到的手和食指指尖对于掌根的深度值
-
- else:
- clear_hand_states()
- # 如果没检测到手就清空全部信息
-
- return image
-
-########################################
-
-cap = cv2.VideoCapture(1)
-cap.open(0)
-
-while cap.isOpened():
- success, frame = cap.read()
- if not success:
- print("Camera Error")
- break
-
- frame = process_image(frame)
- cv2.imshow('Video', frame)
-
- if cv2.waitKey(1) & 0xFF == ord('q'):
- break
-
-cap.release()
-cv2.destroyAllWindows()
\ No newline at end of file