ryhara commited on
Commit
dfbf77d
·
1 Parent(s): 6b88b7e
Files changed (4) hide show
  1. README.md +5 -2
  2. app.py +127 -0
  3. packages.txt +2 -0
  4. requirements.txt +1 -0
README.md CHANGED
@@ -1,14 +1,17 @@
1
  ---
2
  title: Hand Visibility Detector
3
- emoji: 😻
4
- colorFrom: red
5
  colorTo: indigo
6
  sdk: gradio
7
  sdk_version: 6.12.0
 
8
  app_file: app.py
9
  pinned: false
10
  license: cc-by-nc-4.0
11
  short_description: Per-keypoint Hand Visibility Detector
 
 
12
  ---
13
 
14
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
  title: Hand Visibility Detector
3
+ emoji: 🤚
4
+ colorFrom: green
5
  colorTo: indigo
6
  sdk: gradio
7
  sdk_version: 6.12.0
8
+ python_version: 3.12
9
  app_file: app.py
10
  pinned: false
11
  license: cc-by-nc-4.0
12
  short_description: Per-keypoint Hand Visibility Detector
13
+ models:
14
+ - ryhara/hand_visibility_detector
15
  ---
16
 
17
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Gradio demo: interactive hand visibility detection on images and videos."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import tempfile
6
+
7
+ import cv2
8
+ import gradio as gr
9
+ import numpy as np
10
+ import torch
11
+
12
+ from hand_visibility_detector import HandVisibilityPipeline, draw_detections
13
+
14
+ device = "cuda" if torch.cuda.is_available() else "cpu"
15
+
16
+ pipe = HandVisibilityPipeline(
17
+ device=device,
18
+ dtype=torch.float32,
19
+ )
20
+
21
+
22
+ def process_image(
23
+ image_rgb: np.ndarray,
24
+ hand_conf: float,
25
+ show_bones: bool,
26
+ ) -> tuple[np.ndarray, str]:
27
+ if image_rgb is None:
28
+ return np.zeros((256, 256, 3), dtype=np.uint8), "No image provided"
29
+ pipe.hand_conf = hand_conf
30
+ results = pipe.predict(image_rgb)
31
+ annotated = draw_detections(image_rgb, results, show_bones=show_bones)
32
+ info_lines = [f"Detected {len(results)} hand(s)"]
33
+ for i, r in enumerate(results):
34
+ side = "R" if r.is_right else "L"
35
+ avg_vis = r.visibility.mean()
36
+ info_lines.append(
37
+ f" [{i}] {side} conf={r.bbox_conf:.2f} avg_vis={avg_vis:.2f}"
38
+ )
39
+ return annotated, "\n".join(info_lines)
40
+
41
+
42
+ def process_video(
43
+ video_path: str,
44
+ hand_conf: float,
45
+ show_bones: bool,
46
+ progress: gr.Progress = gr.Progress(),
47
+ ) -> str | None:
48
+ if video_path is None:
49
+ return None
50
+ import imageio
51
+
52
+ cap = cv2.VideoCapture(video_path)
53
+ if not cap.isOpened():
54
+ return None
55
+ fps = cap.get(cv2.CAP_PROP_FPS) or 30.0
56
+ total = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) or 0
57
+
58
+ out_path = tempfile.mktemp(suffix=".mp4")
59
+ pipe.hand_conf = hand_conf
60
+
61
+ progress(0.0, desc="Starting...")
62
+ with imageio.get_writer(
63
+ out_path,
64
+ fps=fps,
65
+ codec="libx264",
66
+ pixelformat="yuv420p",
67
+ macro_block_size=1,
68
+ ffmpeg_params=["-movflags", "+faststart"],
69
+ ) as writer:
70
+ frame_idx = 0
71
+ while True:
72
+ ret, frame = cap.read()
73
+ if not ret:
74
+ break
75
+ frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
76
+ results = pipe.predict(frame_rgb)
77
+ annotated = draw_detections(frame_rgb, results, show_bones=show_bones)
78
+ writer.append_data(annotated)
79
+ frame_idx += 1
80
+ if total > 0:
81
+ progress(frame_idx / total, desc=f"Frame {frame_idx}/{total}")
82
+ else:
83
+ progress(0.5, desc=f"Frame {frame_idx}")
84
+
85
+ cap.release()
86
+ progress(1.0, desc="Done")
87
+ return out_path
88
+
89
+
90
+ with gr.Blocks(title="Hand Visibility Detector") as demo:
91
+ gr.Markdown("## Hand Visibility Detector")
92
+ gr.Markdown(
93
+ "Detect hands, estimate 3D pose (WiLoR-mini), and predict "
94
+ "per-keypoint visibility. Green = visible, Red = occluded."
95
+ )
96
+
97
+ with gr.Row():
98
+ hand_conf_slider = gr.Slider(
99
+ minimum=0.1, maximum=0.9, value=0.5, step=0.05,
100
+ label="Hand detection confidence",
101
+ )
102
+ show_bones_cb = gr.Checkbox(value=True, label="Show bones")
103
+
104
+ with gr.Tabs():
105
+ with gr.Tab("Single Image"):
106
+ with gr.Row():
107
+ img_input = gr.Image(label="Input", type="numpy")
108
+ img_output = gr.Image(label="Result", type="numpy")
109
+ img_info = gr.Textbox(label="Info", interactive=False)
110
+ img_btn = gr.Button("Detect")
111
+ img_btn.click(
112
+ fn=process_image,
113
+ inputs=[img_input, hand_conf_slider, show_bones_cb],
114
+ outputs=[img_output, img_info],
115
+ )
116
+
117
+ with gr.Tab("Video"):
118
+ vid_input = gr.Video(label="Input video")
119
+ vid_output = gr.Video(label="Result video")
120
+ vid_btn = gr.Button("Process Video")
121
+ vid_btn.click(
122
+ fn=process_video,
123
+ inputs=[vid_input, hand_conf_slider, show_bones_cb],
124
+ outputs=[vid_output],
125
+ )
126
+
127
+ demo.launch()
packages.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ libgl1
2
+ libglib2.0-0
requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ hand-visibility-detector[demo] @ git+https://github.com/ryhara/hand_visibility_detector.git