ImagePRO-Python 0.5.2__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ImagePRO/__init__.py +1 -1
- ImagePRO/human_analysis/body_analysis/body_pose_estimation.py +104 -72
- ImagePRO/human_analysis/body_analysis/hand_tracking.py +118 -74
- ImagePRO/human_analysis/face_analysis/eye_status_analysis.py +149 -109
- ImagePRO/human_analysis/face_analysis/face_comparison.py +100 -37
- ImagePRO/human_analysis/face_analysis/face_detection.py +83 -76
- ImagePRO/human_analysis/face_analysis/face_mesh_analysis.py +153 -145
- ImagePRO/human_analysis/face_analysis/head_pose_estimation.py +153 -113
- ImagePRO/object_analysis/object_detection.py +59 -64
- ImagePRO/pre_processing/blur.py +173 -155
- ImagePRO/pre_processing/contrast.py +129 -127
- ImagePRO/pre_processing/crop.py +45 -53
- ImagePRO/pre_processing/dataset_generator.py +97 -85
- ImagePRO/pre_processing/grayscale.py +42 -42
- ImagePRO/pre_processing/resize.py +41 -49
- ImagePRO/pre_processing/rotate.py +131 -102
- ImagePRO/pre_processing/sharpen.py +94 -73
- ImagePRO/utils/image.py +118 -0
- ImagePRO/utils/result.py +146 -0
- {imagepro_python-0.5.2.dist-info → imagepro_python-1.0.0.dist-info}/METADATA +1 -1
- imagepro_python-1.0.0.dist-info/RECORD +30 -0
- ImagePRO/utils/io_handler.py +0 -180
- imagepro_python-0.5.2.dist-info/RECORD +0 -29
- {imagepro_python-0.5.2.dist-info → imagepro_python-1.0.0.dist-info}/WHEEL +0 -0
- {imagepro_python-0.5.2.dist-info → imagepro_python-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {imagepro_python-0.5.2.dist-info → imagepro_python-1.0.0.dist-info}/top_level.txt +0 -0
ImagePRO/__init__.py
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
from pathlib import Path
|
|
1
|
+
from __future__ import annotations
|
|
3
2
|
|
|
4
3
|
import cv2
|
|
5
4
|
import mediapipe as mp
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
sys.path.append(str(parent_dir))
|
|
10
|
-
|
|
11
|
-
from utils.io_handler import IOHandler
|
|
6
|
+
from ImagePRO.utils.image import Image
|
|
7
|
+
from ImagePRO.utils.result import Result
|
|
12
8
|
|
|
13
9
|
# Constants
|
|
14
10
|
mp_pose = mp.solutions.pose
|
|
@@ -18,96 +14,121 @@ LANDMARK_RADIUS = 3
|
|
|
18
14
|
LANDMARK_COLOR = (0, 0, 255) # Red color for landmarks
|
|
19
15
|
|
|
20
16
|
def detect_body_pose(
|
|
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
|
-
Raises
|
|
55
|
-
------
|
|
56
|
-
ValueError, TypeError, FileNotFoundError, IOError
|
|
17
|
+
image: Image,
|
|
18
|
+
*,
|
|
19
|
+
min_confidence: float = DEFAULT_CONFIDENCE,
|
|
20
|
+
landmarks_idx: list[int] | None = None,
|
|
21
|
+
pose_obj: mp.solutions.pose.Pose | None = None
|
|
22
|
+
) -> Result:
|
|
23
|
+
"""Detect body landmarks in an image using MediaPipe Pose.
|
|
24
|
+
|
|
25
|
+
Extracts 3D body landmark coordinates and optionally draws them.
|
|
26
|
+
Can focus on specific landmarks or detect all 33 points.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
image: Input image to process.
|
|
30
|
+
min_confidence: Detection confidence threshold.
|
|
31
|
+
Must be between 0 and 1.
|
|
32
|
+
Default: 0.7
|
|
33
|
+
landmarks_idx: Specific landmark indices to detect.
|
|
34
|
+
If None, detects all 33 landmarks.
|
|
35
|
+
Default: None
|
|
36
|
+
pose_obj: Pre-initialized pose detector.
|
|
37
|
+
If None, creates new instance.
|
|
38
|
+
Default: None
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Result object with detections and visualization:
|
|
42
|
+
- image: Input image with landmarks drawn
|
|
43
|
+
- data: List of [idx, x, y, z] coordinates
|
|
44
|
+
- meta: Operation info and parameters
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
TypeError: If image is not an Image instance
|
|
48
|
+
ValueError: If min_confidence not in [0,1]
|
|
49
|
+
TypeError: If landmarks_idx is not list[int]
|
|
57
50
|
"""
|
|
58
|
-
if
|
|
59
|
-
raise TypeError("'
|
|
51
|
+
if not isinstance(image, Image):
|
|
52
|
+
raise TypeError("'image' must be an Image instance")
|
|
60
53
|
|
|
61
|
-
|
|
54
|
+
if not isinstance(min_confidence, (int, float)) or not (0.0 <= min_confidence <= 1.0):
|
|
55
|
+
raise ValueError("'min_confidence' must be between 0.0 and 1.0")
|
|
62
56
|
|
|
63
|
-
if landmarks_idx is None
|
|
64
|
-
landmarks_idx
|
|
57
|
+
if landmarks_idx is not None and (
|
|
58
|
+
not isinstance(landmarks_idx, list)
|
|
59
|
+
or not all(isinstance(i, int) for i in landmarks_idx)
|
|
60
|
+
):
|
|
61
|
+
raise TypeError("'landmarks_idx' must be a list of integers")
|
|
65
62
|
|
|
63
|
+
# Initialize detector if needed
|
|
66
64
|
if pose_obj is None:
|
|
67
65
|
pose_obj = mp_pose.Pose(
|
|
68
|
-
min_detection_confidence=
|
|
66
|
+
min_detection_confidence=min_confidence,
|
|
69
67
|
static_image_mode=True
|
|
70
68
|
)
|
|
71
69
|
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
# Use all landmarks if none specified
|
|
71
|
+
if landmarks_idx is None:
|
|
72
|
+
landmarks_idx = list(range(TOTAL_LANDMARKS))
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
# Prepare image
|
|
75
|
+
h, w = image.shape[:2]
|
|
76
|
+
img_copy = image._data.copy()
|
|
77
|
+
img_rgb = cv2.cvtColor(img_copy, cv2.COLOR_BGR2RGB)
|
|
78
|
+
|
|
79
|
+
# Detect pose
|
|
80
|
+
result = pose_obj.process(img_rgb)
|
|
81
|
+
landmarks = []
|
|
77
82
|
|
|
78
83
|
if result.pose_landmarks:
|
|
84
|
+
# Visualize landmarks
|
|
79
85
|
if len(landmarks_idx) == TOTAL_LANDMARKS:
|
|
86
|
+
# Draw full skeleton
|
|
80
87
|
mp.solutions.drawing_utils.draw_landmarks(
|
|
81
|
-
|
|
88
|
+
img_copy,
|
|
82
89
|
result.pose_landmarks,
|
|
83
90
|
mp_pose.POSE_CONNECTIONS,
|
|
84
91
|
landmark_drawing_spec=mp.solutions.drawing_styles.get_default_pose_landmarks_style()
|
|
85
92
|
)
|
|
86
93
|
else:
|
|
87
|
-
|
|
94
|
+
# Draw only selected points
|
|
88
95
|
for idx in landmarks_idx:
|
|
89
96
|
lm = result.pose_landmarks.landmark[idx]
|
|
90
97
|
x, y = int(w * lm.x), int(h * lm.y)
|
|
91
|
-
cv2.circle(
|
|
98
|
+
cv2.circle(img_copy, (x, y), LANDMARK_RADIUS, LANDMARK_COLOR, -1)
|
|
92
99
|
|
|
100
|
+
# Extract coordinates
|
|
93
101
|
for idx in landmarks_idx:
|
|
94
102
|
lm = result.pose_landmarks.landmark[idx]
|
|
95
|
-
|
|
103
|
+
landmarks.append([idx, lm.x, lm.y, lm.z])
|
|
104
|
+
|
|
105
|
+
return Result(
|
|
106
|
+
image=img_copy,
|
|
107
|
+
data=landmarks,
|
|
108
|
+
meta={
|
|
109
|
+
"source": image,
|
|
110
|
+
"operation": "detect_body_pose",
|
|
111
|
+
"min_confidence": min_confidence,
|
|
112
|
+
"landmarks_idx": landmarks_idx
|
|
113
|
+
}
|
|
114
|
+
)
|
|
96
115
|
|
|
97
|
-
if output_image_path:
|
|
98
|
-
print(IOHandler.save_image(annotated_image, output_image_path))
|
|
99
|
-
if output_csv_path:
|
|
100
|
-
print(IOHandler.save_csv(all_landmarks, output_csv_path))
|
|
101
116
|
|
|
102
|
-
|
|
117
|
+
def detect_body_pose_live() -> None:
|
|
118
|
+
"""Start live webcam feed with real-time body pose detection.
|
|
103
119
|
|
|
120
|
+
Opens the default camera and shows pose landmarks in real-time.
|
|
121
|
+
Press ESC to exit the application.
|
|
104
122
|
|
|
105
|
-
|
|
106
|
-
|
|
123
|
+
Raises:
|
|
124
|
+
RuntimeError: If camera cannot be accessed
|
|
125
|
+
"""
|
|
126
|
+
# Initialize camera
|
|
107
127
|
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
|
|
108
128
|
if not cap.isOpened():
|
|
109
|
-
raise RuntimeError("
|
|
129
|
+
raise RuntimeError("Cannot access webcam")
|
|
110
130
|
|
|
131
|
+
# Initialize pose detector in tracking mode
|
|
111
132
|
pose_obj = mp_pose.Pose(
|
|
112
133
|
min_detection_confidence=DEFAULT_CONFIDENCE,
|
|
113
134
|
static_image_mode=False
|
|
@@ -115,21 +136,32 @@ def detect_body_pose_live():
|
|
|
115
136
|
|
|
116
137
|
try:
|
|
117
138
|
while True:
|
|
139
|
+
# Get frame
|
|
118
140
|
success, frame = cap.read()
|
|
119
141
|
if not success:
|
|
120
|
-
print("
|
|
142
|
+
print("Failed to capture frame, skipping...")
|
|
121
143
|
continue
|
|
122
144
|
|
|
145
|
+
# Process frame
|
|
123
146
|
try:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
147
|
+
result = detect_body_pose(
|
|
148
|
+
image=Image.from_array(frame),
|
|
149
|
+
min_confidence=DEFAULT_CONFIDENCE,
|
|
150
|
+
pose_obj=pose_obj
|
|
151
|
+
)
|
|
152
|
+
display_frame = result.image
|
|
153
|
+
except (TypeError, ValueError):
|
|
154
|
+
# Fall back to raw frame if detection fails
|
|
155
|
+
display_frame = frame
|
|
156
|
+
|
|
157
|
+
# Show result
|
|
158
|
+
cv2.imshow('ImagePRO - Live Body Pose Detection', display_frame)
|
|
159
|
+
|
|
160
|
+
# Check for ESC key
|
|
130
161
|
if cv2.waitKey(5) & 0xFF == 27:
|
|
131
162
|
break
|
|
132
163
|
finally:
|
|
164
|
+
# Clean up resources
|
|
133
165
|
cap.release()
|
|
134
166
|
cv2.destroyAllWindows()
|
|
135
167
|
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
from pathlib import Path
|
|
1
|
+
from __future__ import annotations
|
|
3
2
|
|
|
4
3
|
import cv2
|
|
5
4
|
import mediapipe as mp
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
sys.path.append(str(parent_dir))
|
|
10
|
-
|
|
11
|
-
from utils.io_handler import IOHandler
|
|
6
|
+
from ImagePRO.utils.image import Image
|
|
7
|
+
from ImagePRO.utils.result import Result
|
|
12
8
|
|
|
13
9
|
# Constants
|
|
14
10
|
mp_hands = mp.solutions.hands
|
|
@@ -20,55 +16,61 @@ LANDMARK_COLOR = (0, 0, 255) # Red color for landmarks
|
|
|
20
16
|
|
|
21
17
|
|
|
22
18
|
def detect_hands(
|
|
19
|
+
image: Image,
|
|
20
|
+
*,
|
|
23
21
|
max_hands: int = DEFAULT_MAX_HANDS,
|
|
24
22
|
min_confidence: float = DEFAULT_MIN_CONFIDENCE,
|
|
25
|
-
landmarks_idx: list | None = None,
|
|
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
|
-
Raises
|
|
60
|
-
------
|
|
61
|
-
ValueError, TypeError, FileNotFoundError, IOError
|
|
23
|
+
landmarks_idx: list[int] | None = None,
|
|
24
|
+
hands_obj: mp.solutions.hands.Hands | None = None
|
|
25
|
+
) -> Result:
|
|
26
|
+
"""Detect hand landmarks in an image using MediaPipe Hands.
|
|
27
|
+
|
|
28
|
+
Identifies hand positions and extracts 3D coordinates of
|
|
29
|
+
key points (joints, fingertips, etc.).
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
image: Input image to process.
|
|
33
|
+
max_hands: Maximum number of hands to detect.
|
|
34
|
+
Must be positive.
|
|
35
|
+
Default: 2
|
|
36
|
+
min_confidence: Detection confidence threshold.
|
|
37
|
+
Must be between 0 and 1.
|
|
38
|
+
Default: 0.7
|
|
39
|
+
landmarks_idx: Specific landmark indices to detect.
|
|
40
|
+
If None, detects all 21 points per hand.
|
|
41
|
+
Default: None
|
|
42
|
+
hands_obj: Pre-initialized hand detector.
|
|
43
|
+
If None, creates new instance.
|
|
44
|
+
Default: None
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Result object with detections and visualization:
|
|
48
|
+
- image: Input image with landmarks drawn
|
|
49
|
+
- data: List of [hand_id, point_id, x, y, z]
|
|
50
|
+
- meta: Operation info and parameters
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
TypeError: If image is not an Image instance
|
|
54
|
+
ValueError: If max_hands is not positive
|
|
55
|
+
ValueError: If min_confidence not in [0,1]
|
|
56
|
+
TypeError: If landmarks_idx is not list[int]
|
|
62
57
|
"""
|
|
58
|
+
if not isinstance(image, Image):
|
|
59
|
+
raise TypeError("'image' must be an Image instance")
|
|
60
|
+
|
|
63
61
|
if not isinstance(max_hands, int) or max_hands <= 0:
|
|
64
|
-
raise ValueError("'max_hands' must be
|
|
62
|
+
raise ValueError("'max_hands' must be positive")
|
|
63
|
+
|
|
65
64
|
if not isinstance(min_confidence, (int, float)) or not (0.0 <= min_confidence <= 1.0):
|
|
66
|
-
raise ValueError("'min_confidence' must be
|
|
67
|
-
if landmarks_idx is not None and (not isinstance(landmarks_idx, list) or not all(isinstance(i, int) for i in landmarks_idx)):
|
|
68
|
-
raise TypeError("'landmarks_idx' must be a list of ints or None.")
|
|
65
|
+
raise ValueError("'min_confidence' must be between 0.0 and 1.0")
|
|
69
66
|
|
|
70
|
-
|
|
67
|
+
if landmarks_idx is not None and (
|
|
68
|
+
not isinstance(landmarks_idx, list)
|
|
69
|
+
or not all(isinstance(i, int) for i in landmarks_idx)
|
|
70
|
+
):
|
|
71
|
+
raise TypeError("'landmarks_idx' must be a list of integers")
|
|
71
72
|
|
|
73
|
+
# Initialize detector if needed
|
|
72
74
|
if hands_obj is None:
|
|
73
75
|
hands_obj = mp_hands.Hands(
|
|
74
76
|
min_detection_confidence=min_confidence,
|
|
@@ -76,55 +78,91 @@ def detect_hands(
|
|
|
76
78
|
static_image_mode=True
|
|
77
79
|
)
|
|
78
80
|
|
|
81
|
+
# Use all landmarks if none specified
|
|
79
82
|
if landmarks_idx is None:
|
|
80
83
|
landmarks_idx = list(range(TOTAL_HAND_LANDMARKS))
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
# Prepare image
|
|
86
|
+
img_copy = image._data.copy()
|
|
87
|
+
img_rgb = cv2.cvtColor(img_copy, cv2.COLOR_BGR2RGB)
|
|
84
88
|
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
# Detect hands
|
|
90
|
+
results = hands_obj.process(img_rgb)
|
|
91
|
+
landmarks = []
|
|
87
92
|
|
|
93
|
+
# Process detections
|
|
88
94
|
if results.multi_hand_landmarks:
|
|
89
95
|
for hand_id, hand_landmarks in enumerate(results.multi_hand_landmarks):
|
|
96
|
+
# Visualize landmarks
|
|
90
97
|
if len(landmarks_idx) == TOTAL_HAND_LANDMARKS:
|
|
98
|
+
# Draw full hand skeleton
|
|
91
99
|
mp.solutions.drawing_utils.draw_landmarks(
|
|
92
|
-
image=
|
|
100
|
+
image=img_copy,
|
|
93
101
|
landmark_list=hand_landmarks,
|
|
94
102
|
connections=mp_hands.HAND_CONNECTIONS,
|
|
95
103
|
landmark_drawing_spec=mp.solutions.drawing_styles.get_default_hand_landmarks_style(),
|
|
96
104
|
connection_drawing_spec=mp.solutions.drawing_styles.get_default_hand_connections_style()
|
|
97
105
|
)
|
|
98
106
|
else:
|
|
99
|
-
|
|
107
|
+
# Draw only selected points
|
|
108
|
+
h, w, _ = img_copy.shape
|
|
100
109
|
for idx in landmarks_idx:
|
|
101
110
|
lm = hand_landmarks.landmark[idx]
|
|
102
111
|
x, y = int(w * lm.x), int(h * lm.y)
|
|
103
|
-
cv2.circle(
|
|
112
|
+
cv2.circle(img_copy, (x, y), LANDMARK_RADIUS, LANDMARK_COLOR, -1)
|
|
104
113
|
|
|
114
|
+
# Extract coordinates
|
|
105
115
|
for idx in landmarks_idx:
|
|
106
116
|
lm = hand_landmarks.landmark[idx]
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
landmarks.append([hand_id, idx, lm.x, lm.y, lm.z])
|
|
118
|
+
|
|
119
|
+
return Result(
|
|
120
|
+
image=img_copy,
|
|
121
|
+
data=landmarks,
|
|
122
|
+
meta={
|
|
123
|
+
"source": image,
|
|
124
|
+
"operation": "detect_hands",
|
|
125
|
+
"max_hands": max_hands,
|
|
126
|
+
"min_confidence": min_confidence,
|
|
127
|
+
"landmarks_idx": landmarks_idx
|
|
128
|
+
}
|
|
129
|
+
)
|
|
115
130
|
|
|
116
131
|
|
|
117
|
-
def detect_hands_live(
|
|
118
|
-
|
|
132
|
+
def detect_hands_live(
|
|
133
|
+
max_hands: int = DEFAULT_MAX_HANDS,
|
|
134
|
+
min_confidence: float = DEFAULT_MIN_CONFIDENCE
|
|
135
|
+
) -> None:
|
|
136
|
+
"""Start live webcam feed with real-time hand detection.
|
|
137
|
+
|
|
138
|
+
Opens the default camera and shows hand landmarks in real-time.
|
|
139
|
+
Press ESC to exit.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
max_hands: Maximum number of hands to track.
|
|
143
|
+
Must be positive.
|
|
144
|
+
Default: 2
|
|
145
|
+
min_confidence: Detection confidence threshold.
|
|
146
|
+
Must be between 0 and 1.
|
|
147
|
+
Default: 0.7
|
|
148
|
+
|
|
149
|
+
Raises:
|
|
150
|
+
ValueError: If parameters are invalid
|
|
151
|
+
RuntimeError: If camera cannot be accessed
|
|
152
|
+
"""
|
|
153
|
+
# Validate parameters
|
|
119
154
|
if not isinstance(max_hands, int) or max_hands <= 0:
|
|
120
|
-
raise ValueError("'max_hands' must be
|
|
155
|
+
raise ValueError("'max_hands' must be positive")
|
|
156
|
+
|
|
121
157
|
if not isinstance(min_confidence, (int, float)) or not (0.0 <= min_confidence <= 1.0):
|
|
122
|
-
raise ValueError("'min_confidence' must be
|
|
158
|
+
raise ValueError("'min_confidence' must be between 0.0 and 1.0")
|
|
123
159
|
|
|
160
|
+
# Initialize camera
|
|
124
161
|
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
|
|
125
162
|
if not cap.isOpened():
|
|
126
|
-
raise RuntimeError("
|
|
163
|
+
raise RuntimeError("Cannot access webcam")
|
|
127
164
|
|
|
165
|
+
# Initialize hand detector in tracking mode
|
|
128
166
|
hands_obj = mp_hands.Hands(
|
|
129
167
|
min_detection_confidence=min_confidence,
|
|
130
168
|
max_num_hands=max_hands,
|
|
@@ -133,26 +171,32 @@ def detect_hands_live(max_hands: int = DEFAULT_MAX_HANDS, min_confidence: float
|
|
|
133
171
|
|
|
134
172
|
try:
|
|
135
173
|
while True:
|
|
174
|
+
# Get frame
|
|
136
175
|
success, frame = cap.read()
|
|
137
176
|
if not success:
|
|
138
|
-
print("
|
|
177
|
+
print("Failed to capture frame, skipping...")
|
|
139
178
|
continue
|
|
140
179
|
|
|
141
|
-
|
|
180
|
+
# Process frame
|
|
181
|
+
result = detect_hands(
|
|
182
|
+
image=Image.from_array(frame),
|
|
142
183
|
max_hands=max_hands,
|
|
143
184
|
min_confidence=min_confidence,
|
|
144
|
-
src_np_image=frame,
|
|
145
185
|
hands_obj=hands_obj
|
|
146
186
|
)
|
|
187
|
+
display_frame = result.image if result.image is not None else frame
|
|
147
188
|
|
|
148
|
-
|
|
189
|
+
# Show result
|
|
190
|
+
cv2.imshow('ImagePRO - Live Hand Detection', display_frame)
|
|
149
191
|
|
|
192
|
+
# Check for ESC key
|
|
150
193
|
if cv2.waitKey(5) & 0xFF == 27:
|
|
151
194
|
break
|
|
152
195
|
finally:
|
|
196
|
+
# Clean up resources
|
|
153
197
|
cap.release()
|
|
154
198
|
cv2.destroyAllWindows()
|
|
155
199
|
|
|
156
200
|
|
|
157
201
|
if __name__ == "__main__":
|
|
158
|
-
detect_hands_live(
|
|
202
|
+
detect_hands_live()
|