ImagePRO-Python 0.5.1__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.
Files changed (33) hide show
  1. ImagePRO/__init__.py +33 -0
  2. ImagePRO/human_analysis/__init__.py +7 -0
  3. ImagePRO/human_analysis/body_analysis/__init__.py +7 -0
  4. ImagePRO/human_analysis/body_analysis/body_pose_estimation.py +111 -74
  5. ImagePRO/human_analysis/body_analysis/hand_tracking.py +126 -76
  6. ImagePRO/human_analysis/face_analysis/__init__.py +16 -0
  7. ImagePRO/human_analysis/face_analysis/eye_status_analysis.py +154 -110
  8. ImagePRO/human_analysis/face_analysis/face_comparison.py +107 -38
  9. ImagePRO/human_analysis/face_analysis/face_detection.py +94 -82
  10. ImagePRO/human_analysis/face_analysis/face_mesh_analysis.py +160 -148
  11. ImagePRO/human_analysis/face_analysis/head_pose_estimation.py +159 -115
  12. ImagePRO/object_analysis/__init__.py +6 -0
  13. ImagePRO/object_analysis/object_detection.py +74 -77
  14. ImagePRO/pre_processing/__init__.py +22 -0
  15. ImagePRO/pre_processing/blur.py +180 -148
  16. ImagePRO/pre_processing/contrast.py +131 -123
  17. ImagePRO/pre_processing/crop.py +49 -53
  18. ImagePRO/pre_processing/dataset_generator.py +109 -89
  19. ImagePRO/pre_processing/grayscale.py +44 -43
  20. ImagePRO/pre_processing/resize.py +43 -53
  21. ImagePRO/pre_processing/rotate.py +134 -101
  22. ImagePRO/pre_processing/sharpen.py +97 -72
  23. ImagePRO/utils/__init__.py +6 -0
  24. ImagePRO/utils/image.py +118 -0
  25. ImagePRO/utils/result.py +146 -0
  26. imagepro_python-1.0.0.dist-info/METADATA +30 -0
  27. imagepro_python-1.0.0.dist-info/RECORD +30 -0
  28. ImagePRO/utils/io_handler.py +0 -180
  29. imagepro_python-0.5.1.dist-info/METADATA +0 -20
  30. imagepro_python-0.5.1.dist-info/RECORD +0 -28
  31. {imagepro_python-0.5.1.dist-info → imagepro_python-1.0.0.dist-info}/WHEEL +0 -0
  32. {imagepro_python-0.5.1.dist-info → imagepro_python-1.0.0.dist-info}/licenses/LICENSE +0 -0
  33. {imagepro_python-0.5.1.dist-info → imagepro_python-1.0.0.dist-info}/top_level.txt +0 -0
ImagePRO/__init__.py CHANGED
@@ -0,0 +1,33 @@
1
+ """
2
+ ImagePRO - Professional & Modular Image Processing Library in Python
3
+
4
+ A clean, modular, and easy-to-use Python library for image processing tasks,
5
+ built with OpenCV, MediaPipe, YOLO and designed to be extensible for developers.
6
+
7
+ Whether you're working on computer vision pipelines, preprocessing images for AI models,
8
+ or simply automating batch image edits — ImagePRO gives you powerful tools with minimal effort.
9
+
10
+ Features:
11
+ - Image I/O management and batch processing
12
+ - Pre-processing: resize, crop, rotate, blur, sharpen, contrast enhancement
13
+ - Human analysis: face mesh, pose estimation, hand tracking
14
+ - Object detection with YOLO models
15
+ - Real-time processing capabilities
16
+ """
17
+
18
+ __version__ = "1.0.0"
19
+ __author__ = "Parsa Safaie"
20
+ __email__ = "parsasafaie.2568@proton.me"
21
+
22
+ # Core modules
23
+ from . import utils
24
+ from . import pre_processing
25
+ from . import human_analysis
26
+ from . import object_analysis
27
+
28
+ __all__ = [
29
+ "utils",
30
+ "pre_processing",
31
+ "human_analysis",
32
+ "object_analysis"
33
+ ]
@@ -0,0 +1,7 @@
1
+ # Human Analysis Module
2
+ # Provides face and body analysis capabilities using MediaPipe
3
+
4
+ from . import face_analysis
5
+ from . import body_analysis
6
+
7
+ __all__ = ["face_analysis", "body_analysis"]
@@ -0,0 +1,7 @@
1
+ # Body Analysis Module
2
+ # Provides body pose estimation and hand tracking capabilities
3
+
4
+ from . import body_pose_estimation
5
+ from . import hand_tracking
6
+
7
+ __all__ = ["body_pose_estimation", "hand_tracking"]
@@ -1,130 +1,167 @@
1
- import sys
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
- # Add parent directory to import custom modules
8
- parent_dir = Path(__file__).resolve().parent.parent.parent
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
 
9
+ # Constants
13
10
  mp_pose = mp.solutions.pose
11
+ TOTAL_LANDMARKS = 33
12
+ DEFAULT_CONFIDENCE = 0.7
13
+ LANDMARK_RADIUS = 3
14
+ LANDMARK_COLOR = (0, 0, 255) # Red color for landmarks
14
15
 
15
16
  def detect_body_pose(
16
- model_accuracy: float = 0.7,
17
- landmarks_idx: list | None = None,
18
- src_image_path: str | None = None,
19
- src_np_image=None,
20
- output_image_path: str | None = None,
21
- output_csv_path: str | None = None,
22
- pose_obj=None
23
- ):
24
- """
25
- Detect body landmarks from an image using MediaPipe Pose.
26
-
27
- Parameters
28
- ----------
29
- model_accuracy : float, default=0.7
30
- Minimum detection confidence [0, 1].
31
- landmarks_idx : list[int] | None, optional
32
- Indices of landmarks to extract. Default: all 33.
33
- src_image_path : str | None, optional
34
- Path to image file.
35
- src_np_image : np.ndarray | None, optional
36
- Preloaded BGR image array.
37
- output_image_path : str | None, optional
38
- If provided, saves annotated image.
39
- output_csv_path : str | None, optional
40
- If provided, saves landmarks CSV.
41
- pose_obj : mp.solutions.pose.Pose | None, optional
42
- Optional pre-initialized pose model.
43
-
44
- Returns
45
- -------
46
- tuple[np.ndarray, list]
47
- Annotated image and landmarks list.
48
-
49
- Raises
50
- ------
51
- 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]
52
50
  """
53
- if landmarks_idx is not None and (not isinstance(landmarks_idx, list) or not all(isinstance(i, int) for i in landmarks_idx)):
54
- raise TypeError("'landmarks_idx' must be a list of ints or None.")
51
+ if not isinstance(image, Image):
52
+ raise TypeError("'image' must be an Image instance")
55
53
 
56
- np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
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")
57
56
 
58
- if landmarks_idx is None:
59
- landmarks_idx = list(range(33))
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")
60
62
 
63
+ # Initialize detector if needed
61
64
  if pose_obj is None:
62
65
  pose_obj = mp_pose.Pose(
63
- min_detection_confidence=model_accuracy,
66
+ min_detection_confidence=min_confidence,
64
67
  static_image_mode=True
65
68
  )
66
69
 
67
- image_rgb = cv2.cvtColor(np_image, cv2.COLOR_BGR2RGB)
68
- result = pose_obj.process(image_rgb)
70
+ # Use all landmarks if none specified
71
+ if landmarks_idx is None:
72
+ landmarks_idx = list(range(TOTAL_LANDMARKS))
73
+
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)
69
78
 
70
- annotated_image = np_image.copy()
71
- all_landmarks = []
79
+ # Detect pose
80
+ result = pose_obj.process(img_rgb)
81
+ landmarks = []
72
82
 
73
83
  if result.pose_landmarks:
74
- if len(landmarks_idx) == 33:
84
+ # Visualize landmarks
85
+ if len(landmarks_idx) == TOTAL_LANDMARKS:
86
+ # Draw full skeleton
75
87
  mp.solutions.drawing_utils.draw_landmarks(
76
- annotated_image,
88
+ img_copy,
77
89
  result.pose_landmarks,
78
90
  mp_pose.POSE_CONNECTIONS,
79
91
  landmark_drawing_spec=mp.solutions.drawing_styles.get_default_pose_landmarks_style()
80
92
  )
81
93
  else:
82
- h, w, _ = annotated_image.shape
94
+ # Draw only selected points
83
95
  for idx in landmarks_idx:
84
96
  lm = result.pose_landmarks.landmark[idx]
85
97
  x, y = int(w * lm.x), int(h * lm.y)
86
- cv2.circle(annotated_image, (x, y), 3, (0, 0, 255), -1)
98
+ cv2.circle(img_copy, (x, y), LANDMARK_RADIUS, LANDMARK_COLOR, -1)
87
99
 
100
+ # Extract coordinates
88
101
  for idx in landmarks_idx:
89
102
  lm = result.pose_landmarks.landmark[idx]
90
- all_landmarks.append([idx, lm.x, lm.y, lm.z])
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
+ )
91
115
 
92
- if output_image_path:
93
- print(IOHandler.save_image(annotated_image, output_image_path))
94
- if output_csv_path:
95
- print(IOHandler.save_csv(all_landmarks, output_csv_path))
96
116
 
97
- return annotated_image, all_landmarks
117
+ def detect_body_pose_live() -> None:
118
+ """Start live webcam feed with real-time body pose detection.
98
119
 
120
+ Opens the default camera and shows pose landmarks in real-time.
121
+ Press ESC to exit the application.
99
122
 
100
- def detect_body_pose_live():
101
- """Starts webcam and shows real-time body pose detection. Press ESC to exit."""
123
+ Raises:
124
+ RuntimeError: If camera cannot be accessed
125
+ """
126
+ # Initialize camera
102
127
  cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
103
128
  if not cap.isOpened():
104
- raise RuntimeError("Failed to open webcam.")
129
+ raise RuntimeError("Cannot access webcam")
105
130
 
131
+ # Initialize pose detector in tracking mode
106
132
  pose_obj = mp_pose.Pose(
107
- min_detection_confidence=0.7,
133
+ min_detection_confidence=DEFAULT_CONFIDENCE,
108
134
  static_image_mode=False
109
135
  )
110
136
 
111
137
  try:
112
138
  while True:
139
+ # Get frame
113
140
  success, frame = cap.read()
114
141
  if not success:
115
- print("Ignoring empty camera frame.")
142
+ print("Failed to capture frame, skipping...")
116
143
  continue
117
144
 
145
+ # Process frame
118
146
  try:
119
- annotated_img, _ = detect_body_pose(src_np_image=frame, pose_obj=pose_obj)
120
- except ValueError:
121
- annotated_img = frame
122
-
123
- cv2.imshow('ImagePRO - Live Body Pose Detection', annotated_img)
124
-
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
125
161
  if cv2.waitKey(5) & 0xFF == 27:
126
162
  break
127
163
  finally:
164
+ # Clean up resources
128
165
  cap.release()
129
166
  cv2.destroyAllWindows()
130
167
 
@@ -1,68 +1,76 @@
1
- import sys
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
- # Add parent directory to import custom modules
8
- parent_dir = Path(__file__).resolve().parent.parent.parent
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
 
9
+ # Constants
13
10
  mp_hands = mp.solutions.hands
11
+ DEFAULT_MAX_HANDS = 2
12
+ DEFAULT_MIN_CONFIDENCE = 0.7
13
+ TOTAL_HAND_LANDMARKS = 21
14
+ LANDMARK_RADIUS = 3
15
+ LANDMARK_COLOR = (0, 0, 255) # Red color for landmarks
14
16
 
15
17
 
16
18
  def detect_hands(
17
- max_hands: int = 2,
18
- min_confidence: float = 0.7,
19
- landmarks_idx: list | None = None,
20
- src_image_path: str | None = None,
21
- src_np_image=None,
22
- output_image_path: str | None = None,
23
- output_csv_path: str | None = None,
24
- hands_obj=None
25
- ):
26
- """
27
- Detect hand landmarks in an image using MediaPipe Hands.
28
-
29
- Parameters
30
- ----------
31
- max_hands : int, default=2
32
- Max number of hands to detect.
33
- min_confidence : float, default=0.7
34
- Minimum detection confidence [0, 1].
35
- landmarks_idx : list[int] | None, optional
36
- Landmark indices to extract (default: all 21).
37
- src_image_path : str | None, optional
38
- Path to image file.
39
- src_np_image : np.ndarray | None, optional
40
- Preloaded BGR image array.
41
- output_image_path : str | None, optional
42
- If provided, saves annotated image.
43
- output_csv_path : str | None, optional
44
- If provided, saves landmarks CSV.
45
- hands_obj : mp.solutions.hands.Hands | None, optional
46
- Optional pre-initialized model.
47
-
48
- Returns
49
- -------
50
- tuple[np.ndarray, list]
51
- Annotated image and landmarks list.
52
-
53
- Raises
54
- ------
55
- ValueError, TypeError, FileNotFoundError, IOError
19
+ image: Image,
20
+ *,
21
+ max_hands: int = DEFAULT_MAX_HANDS,
22
+ min_confidence: float = DEFAULT_MIN_CONFIDENCE,
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]
56
57
  """
58
+ if not isinstance(image, Image):
59
+ raise TypeError("'image' must be an Image instance")
60
+
57
61
  if not isinstance(max_hands, int) or max_hands <= 0:
58
- raise ValueError("'max_hands' must be a positive integer.")
62
+ raise ValueError("'max_hands' must be positive")
63
+
59
64
  if not isinstance(min_confidence, (int, float)) or not (0.0 <= min_confidence <= 1.0):
60
- raise ValueError("'min_confidence' must be a float between 0.0 and 1.0.")
61
- if landmarks_idx is not None and (not isinstance(landmarks_idx, list) or not all(isinstance(i, int) for i in landmarks_idx)):
62
- 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")
63
66
 
64
- np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
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")
65
72
 
73
+ # Initialize detector if needed
66
74
  if hands_obj is None:
67
75
  hands_obj = mp_hands.Hands(
68
76
  min_detection_confidence=min_confidence,
@@ -70,55 +78,91 @@ def detect_hands(
70
78
  static_image_mode=True
71
79
  )
72
80
 
81
+ # Use all landmarks if none specified
73
82
  if landmarks_idx is None:
74
- landmarks_idx = list(range(21))
83
+ landmarks_idx = list(range(TOTAL_HAND_LANDMARKS))
75
84
 
76
- rgb_image = cv2.cvtColor(np_image, cv2.COLOR_BGR2RGB)
77
- results = hands_obj.process(rgb_image)
85
+ # Prepare image
86
+ img_copy = image._data.copy()
87
+ img_rgb = cv2.cvtColor(img_copy, cv2.COLOR_BGR2RGB)
78
88
 
79
- annotated_image = np_image.copy()
80
- all_landmarks = []
89
+ # Detect hands
90
+ results = hands_obj.process(img_rgb)
91
+ landmarks = []
81
92
 
93
+ # Process detections
82
94
  if results.multi_hand_landmarks:
83
95
  for hand_id, hand_landmarks in enumerate(results.multi_hand_landmarks):
84
- if len(landmarks_idx) == 21:
96
+ # Visualize landmarks
97
+ if len(landmarks_idx) == TOTAL_HAND_LANDMARKS:
98
+ # Draw full hand skeleton
85
99
  mp.solutions.drawing_utils.draw_landmarks(
86
- image=annotated_image,
100
+ image=img_copy,
87
101
  landmark_list=hand_landmarks,
88
102
  connections=mp_hands.HAND_CONNECTIONS,
89
103
  landmark_drawing_spec=mp.solutions.drawing_styles.get_default_hand_landmarks_style(),
90
104
  connection_drawing_spec=mp.solutions.drawing_styles.get_default_hand_connections_style()
91
105
  )
92
106
  else:
93
- h, w, _ = annotated_image.shape
107
+ # Draw only selected points
108
+ h, w, _ = img_copy.shape
94
109
  for idx in landmarks_idx:
95
110
  lm = hand_landmarks.landmark[idx]
96
111
  x, y = int(w * lm.x), int(h * lm.y)
97
- cv2.circle(annotated_image, (x, y), 3, (0, 0, 255), -1)
112
+ cv2.circle(img_copy, (x, y), LANDMARK_RADIUS, LANDMARK_COLOR, -1)
98
113
 
114
+ # Extract coordinates
99
115
  for idx in landmarks_idx:
100
116
  lm = hand_landmarks.landmark[idx]
101
- all_landmarks.append([hand_id, idx, lm.x, lm.y, lm.z])
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
+ )
130
+
102
131
 
103
- if output_image_path:
104
- print(IOHandler.save_image(annotated_image, output_image_path))
105
- if output_csv_path:
106
- print(IOHandler.save_csv(all_landmarks, output_csv_path))
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.
107
137
 
108
- return annotated_image, all_landmarks
138
+ Opens the default camera and shows hand landmarks in real-time.
139
+ Press ESC to exit.
109
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
110
148
 
111
- def detect_hands_live(max_hands: int = 2, min_confidence: float = 0.7):
112
- """Real-time hand detection via webcam. Press ESC to exit."""
149
+ Raises:
150
+ ValueError: If parameters are invalid
151
+ RuntimeError: If camera cannot be accessed
152
+ """
153
+ # Validate parameters
113
154
  if not isinstance(max_hands, int) or max_hands <= 0:
114
- raise ValueError("'max_hands' must be a positive integer.")
155
+ raise ValueError("'max_hands' must be positive")
156
+
115
157
  if not isinstance(min_confidence, (int, float)) or not (0.0 <= min_confidence <= 1.0):
116
- raise ValueError("'min_confidence' must be a float between 0.0 and 1.0.")
158
+ raise ValueError("'min_confidence' must be between 0.0 and 1.0")
117
159
 
160
+ # Initialize camera
118
161
  cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
119
162
  if not cap.isOpened():
120
- raise RuntimeError("Failed to open webcam.")
163
+ raise RuntimeError("Cannot access webcam")
121
164
 
165
+ # Initialize hand detector in tracking mode
122
166
  hands_obj = mp_hands.Hands(
123
167
  min_detection_confidence=min_confidence,
124
168
  max_num_hands=max_hands,
@@ -127,26 +171,32 @@ def detect_hands_live(max_hands: int = 2, min_confidence: float = 0.7):
127
171
 
128
172
  try:
129
173
  while True:
174
+ # Get frame
130
175
  success, frame = cap.read()
131
176
  if not success:
132
- print("Ignoring empty camera frame.")
177
+ print("Failed to capture frame, skipping...")
133
178
  continue
134
179
 
135
- annotated_img, _ = detect_hands(
180
+ # Process frame
181
+ result = detect_hands(
182
+ image=Image.from_array(frame),
136
183
  max_hands=max_hands,
137
184
  min_confidence=min_confidence,
138
- src_np_image=frame,
139
185
  hands_obj=hands_obj
140
186
  )
187
+ display_frame = result.image if result.image is not None else frame
141
188
 
142
- cv2.imshow('Live hand detector - ImagePRO', annotated_img)
189
+ # Show result
190
+ cv2.imshow('ImagePRO - Live Hand Detection', display_frame)
143
191
 
192
+ # Check for ESC key
144
193
  if cv2.waitKey(5) & 0xFF == 27:
145
194
  break
146
195
  finally:
196
+ # Clean up resources
147
197
  cap.release()
148
198
  cv2.destroyAllWindows()
149
199
 
150
200
 
151
201
  if __name__ == "__main__":
152
- detect_hands_live(max_hands=2)
202
+ detect_hands_live()
@@ -0,0 +1,16 @@
1
+ # Face Analysis Module
2
+ # Provides facial landmark detection, pose estimation, and eye status analysis
3
+
4
+ from . import eye_status_analysis
5
+ from . import face_comparison
6
+ from . import face_detection
7
+ from . import face_mesh_analysis
8
+ from . import head_pose_estimation
9
+
10
+ __all__ = [
11
+ "eye_status_analysis",
12
+ "face_comparison",
13
+ "face_detection",
14
+ "face_mesh_analysis",
15
+ "head_pose_estimation"
16
+ ]