ImagePRO-Python 1.3.0__py3-none-any.whl → 1.4.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 CHANGED
@@ -12,10 +12,11 @@ Features:
12
12
  - Pre-processing: resize, crop, rotate, blur, sharpen, contrast enhancement
13
13
  - Human analysis: face mesh, pose estimation, hand tracking
14
14
  - Object detection with YOLO models
15
+ - Reusable pipelines for chaining operations
15
16
  - Real-time processing capabilities
16
17
  """
17
18
 
18
- __version__ = "1.3.0"
19
+ __version__ = "1.4.0"
19
20
  __author__ = "Parsa Safaie"
20
21
  __email__ = "parsasafaie.2568@proton.me"
21
22
 
@@ -24,10 +25,12 @@ from . import utils
24
25
  from . import pre_processing
25
26
  from . import human_analysis
26
27
  from . import object_analysis
28
+ from . import pipeline
27
29
 
28
30
  __all__ = [
29
31
  "utils",
30
32
  "pre_processing",
31
33
  "human_analysis",
32
- "object_analysis"
34
+ "object_analysis",
35
+ "pipeline"
33
36
  ]
@@ -1,17 +1,11 @@
1
1
  # Body Analysis Module
2
2
  # Provides body pose estimation and hand tracking capabilities
3
3
  #
4
- # Both modules need the optional mediapipe dependency; they are imported
5
- # guardedly so the package stays importable without it.
4
+ # The mediapipe dependency is optional and imported lazily inside the
5
+ # functions that need it, so both submodules are safe to import without
6
+ # any AI extras installed.
6
7
 
7
- try: # requires mediapipe
8
- from . import body_pose_estimation
9
- except ImportError:
10
- body_pose_estimation = None
11
-
12
- try: # requires mediapipe
13
- from . import hand_tracking
14
- except ImportError:
15
- hand_tracking = None
8
+ from . import body_pose_estimation
9
+ from . import hand_tracking
16
10
 
17
11
  __all__ = ["body_pose_estimation", "hand_tracking"]
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import sys
4
4
  from pathlib import Path
5
+ from typing import TYPE_CHECKING
5
6
 
6
7
  # Add src directory to path for absolute imports
7
8
  _file_path = Path(__file__).resolve()
@@ -13,10 +14,11 @@ from ImagePRO.utils.image import Image
13
14
  from ImagePRO.utils.result import Result
14
15
 
15
16
  import cv2
16
- import mediapipe as mp
17
+
18
+ if TYPE_CHECKING: # mediapipe is imported lazily inside the functions
19
+ import mediapipe as mp
17
20
 
18
21
  # Constants
19
- mp_pose = mp.solutions.pose
20
22
  TOTAL_LANDMARKS = 33
21
23
  DEFAULT_CONFIDENCE = 0.7
22
24
  LANDMARK_RADIUS = 3
@@ -69,6 +71,16 @@ def detect_body_pose(
69
71
  ):
70
72
  raise TypeError("'landmarks_idx' must be a list of integers")
71
73
 
74
+ try:
75
+ import mediapipe as mp
76
+ except ImportError as err:
77
+ raise ImportError(
78
+ "The optional 'mediapipe' dependency is required for body pose "
79
+ 'detection. Install it with: pip install "ImagePRO-Python[mediapipe]"'
80
+ ) from err
81
+
82
+ mp_pose = mp.solutions.pose
83
+
72
84
  # Initialize detector if needed
73
85
  if pose_obj is None:
74
86
  pose_obj = mp_pose.Pose(
@@ -133,13 +145,21 @@ def detect_body_pose_live() -> None:
133
145
  Raises:
134
146
  RuntimeError: If camera cannot be accessed
135
147
  """
148
+ try:
149
+ import mediapipe as mp
150
+ except ImportError as err:
151
+ raise ImportError(
152
+ "The optional 'mediapipe' dependency is required for body pose "
153
+ 'detection. Install it with: pip install "ImagePRO-Python[mediapipe]"'
154
+ ) from err
155
+
136
156
  # Initialize camera
137
157
  cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
138
158
  if not cap.isOpened():
139
159
  raise RuntimeError("Cannot access webcam")
140
160
 
141
161
  # Initialize pose detector in tracking mode
142
- pose_obj = mp_pose.Pose(
162
+ pose_obj = mp.solutions.pose.Pose(
143
163
  min_detection_confidence=DEFAULT_CONFIDENCE,
144
164
  static_image_mode=False
145
165
  )
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import sys
4
4
  from pathlib import Path
5
+ from typing import TYPE_CHECKING
5
6
 
6
7
  # Add src directory to path for absolute imports
7
8
  _file_path = Path(__file__).resolve()
@@ -13,10 +14,11 @@ from ImagePRO.utils.image import Image
13
14
  from ImagePRO.utils.result import Result
14
15
 
15
16
  import cv2
16
- import mediapipe as mp
17
+
18
+ if TYPE_CHECKING: # mediapipe is imported lazily inside the functions
19
+ import mediapipe as mp
17
20
 
18
21
  # Constants
19
- mp_hands = mp.solutions.hands
20
22
  DEFAULT_MAX_HANDS = 2
21
23
  DEFAULT_MIN_CONFIDENCE = 0.7
22
24
  TOTAL_HAND_LANDMARKS = 21
@@ -79,6 +81,16 @@ def detect_hands(
79
81
  ):
80
82
  raise TypeError("'landmarks_idx' must be a list of integers")
81
83
 
84
+ try:
85
+ import mediapipe as mp
86
+ except ImportError as err:
87
+ raise ImportError(
88
+ "The optional 'mediapipe' dependency is required for hand "
89
+ 'tracking. Install it with: pip install "ImagePRO-Python[mediapipe]"'
90
+ ) from err
91
+
92
+ mp_hands = mp.solutions.hands
93
+
82
94
  # Initialize detector if needed
83
95
  if hands_obj is None:
84
96
  hands_obj = mp_hands.Hands(
@@ -168,13 +180,21 @@ def detect_hands_live(
168
180
  if not isinstance(min_confidence, (int, float)) or not (0.0 <= min_confidence <= 1.0):
169
181
  raise ValueError("'min_confidence' must be between 0.0 and 1.0")
170
182
 
183
+ try:
184
+ import mediapipe as mp
185
+ except ImportError as err:
186
+ raise ImportError(
187
+ "The optional 'mediapipe' dependency is required for hand "
188
+ 'tracking. Install it with: pip install "ImagePRO-Python[mediapipe]"'
189
+ ) from err
190
+
171
191
  # Initialize camera
172
192
  cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
173
193
  if not cap.isOpened():
174
194
  raise RuntimeError("Cannot access webcam")
175
195
 
176
196
  # Initialize hand detector in tracking mode
177
- hands_obj = mp_hands.Hands(
197
+ hands_obj = mp.solutions.hands.Hands(
178
198
  min_detection_confidence=min_confidence,
179
199
  max_num_hands=max_hands,
180
200
  static_image_mode=False
@@ -1,34 +1,15 @@
1
1
  # Face Analysis Module
2
2
  # Provides facial landmark detection, pose estimation, and eye status analysis
3
3
  #
4
- # The mediapipe-based modules and the insightface-based module are imported
5
- # guardedly so that importing the package works with only the dependencies
6
- # a caller actually needs; unavailable modules are set to None.
4
+ # The mediapipe and insightface dependencies are optional and imported
5
+ # lazily inside the functions that need them, so every submodule is safe
6
+ # to import regardless of which extras are installed.
7
7
 
8
- try: # requires mediapipe
9
- from . import eye_status_analysis
10
- except ImportError:
11
- eye_status_analysis = None
12
-
13
- try: # requires insightface
14
- from . import face_comparison
15
- except ImportError:
16
- face_comparison = None
17
-
18
- try: # requires mediapipe
19
- from . import face_detection
20
- except ImportError:
21
- face_detection = None
22
-
23
- try: # requires mediapipe
24
- from . import face_mesh_analysis
25
- except ImportError:
26
- face_mesh_analysis = None
27
-
28
- try: # requires mediapipe
29
- from . import head_pose_estimation
30
- except ImportError:
31
- head_pose_estimation = None
8
+ from . import eye_status_analysis
9
+ from . import face_comparison
10
+ from . import face_detection
11
+ from . import face_mesh_analysis
12
+ from . import head_pose_estimation
32
13
 
33
14
  __all__ = [
34
15
  "eye_status_analysis",
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import sys
4
4
  from pathlib import Path
5
+ from typing import TYPE_CHECKING
5
6
 
6
7
  # Add src directory to path for absolute imports
7
8
  _file_path = Path(__file__).resolve()
@@ -14,10 +15,11 @@ from ImagePRO.utils.image import Image
14
15
  from ImagePRO.utils.result import Result
15
16
 
16
17
  import cv2
17
- import mediapipe as mp
18
+
19
+ if TYPE_CHECKING: # mediapipe is imported lazily inside the functions
20
+ import mediapipe as mp
18
21
 
19
22
  # Constants
20
- mp_face_mesh = mp.solutions.face_mesh
21
23
  DEFAULT_MIN_CONFIDENCE = 0.7
22
24
  DEFAULT_THRESHOLD = 0.2
23
25
  RIGHT_EYE_INDICES = [386, 374, 263, 362] # MediaPipe right eye landmarks
@@ -65,12 +67,20 @@ def analyze_eye_status(
65
67
  if not 0 <= min_confidence <= 1:
66
68
  raise ValueError("'min_confidence' must be between 0 and 1")
67
69
 
70
+ try:
71
+ import mediapipe as mp
72
+ except ImportError as err:
73
+ raise ImportError(
74
+ "The optional 'mediapipe' dependency is required for eye status "
75
+ 'analysis. Install it with: pip install "ImagePRO-Python[mediapipe]"'
76
+ ) from err
77
+
68
78
  # Get image dimensions
69
79
  h, w = image.shape[:2]
70
80
 
71
81
  # Initialize detector if needed
72
82
  if face_mesh_obj is None:
73
- face_mesh_obj = mp_face_mesh.FaceMesh(
83
+ face_mesh_obj = mp.solutions.face_mesh.FaceMesh(
74
84
  min_detection_confidence=min_confidence,
75
85
  refine_landmarks=True,
76
86
  static_image_mode=True
@@ -173,13 +183,21 @@ def analyze_eye_status_live(
173
183
  if not 0 <= min_confidence <= 1:
174
184
  raise ValueError("'min_confidence' must be between 0 and 1")
175
185
 
186
+ try:
187
+ import mediapipe as mp
188
+ except ImportError as err:
189
+ raise ImportError(
190
+ "The optional 'mediapipe' dependency is required for eye status "
191
+ 'analysis. Install it with: pip install "ImagePRO-Python[mediapipe]"'
192
+ ) from err
193
+
176
194
  # Initialize webcam
177
195
  cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
178
196
  if not cap.isOpened():
179
197
  raise RuntimeError("Failed to access webcam")
180
198
 
181
199
  # Initialize face mesh detector for video
182
- face_mesh = mp_face_mesh.FaceMesh(
200
+ face_mesh = mp.solutions.face_mesh.FaceMesh(
183
201
  max_num_faces=1,
184
202
  min_detection_confidence=min_confidence,
185
203
  refine_landmarks=True,
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import sys
4
4
  from pathlib import Path
5
+ from typing import TYPE_CHECKING
5
6
 
6
7
  # Add src directory to path for absolute imports
7
8
  _file_path = Path(__file__).resolve()
@@ -13,11 +14,13 @@ import os
13
14
 
14
15
  import cv2
15
16
  import numpy as np
16
- from insightface.app import FaceAnalysis
17
17
 
18
18
  from ImagePRO.utils.image import Image
19
19
  from ImagePRO.utils.result import Result
20
20
 
21
+ if TYPE_CHECKING: # insightface is imported lazily inside the function
22
+ from insightface.app import FaceAnalysis
23
+
21
24
  # Constants
22
25
  DEFAULT_SIMILARITY_THRESHOLD = 0.5
23
26
  DEFAULT_MODEL_NAME = "buffalo_l"
@@ -62,6 +65,15 @@ def compare_faces(
62
65
  if not isinstance(image_2, Image):
63
66
  raise TypeError("'image_2' must be an Image instance")
64
67
 
68
+ try:
69
+ from insightface.app import FaceAnalysis
70
+ except ImportError as err:
71
+ raise ImportError(
72
+ "The optional 'insightface' dependency is required for face "
73
+ 'comparison. Install it with: pip install '
74
+ '"ImagePRO-Python[insightface]"'
75
+ ) from err
76
+
65
77
  # Initialize model if needed
66
78
  if app is None:
67
79
  app = FaceAnalysis(
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import sys
4
4
  from pathlib import Path
5
+ from typing import TYPE_CHECKING
5
6
 
6
7
  # Add src directory to path for absolute imports
7
8
  _file_path = Path(__file__).resolve()
@@ -10,13 +11,15 @@ if str(_src_path) not in sys.path:
10
11
  sys.path.insert(0, str(_src_path))
11
12
 
12
13
  import cv2
13
- import mediapipe as mp
14
14
  import numpy as np
15
15
 
16
16
  from ImagePRO.human_analysis.face_analysis.face_mesh_analysis import analyze_face_mesh
17
17
  from ImagePRO.utils.image import Image
18
18
  from ImagePRO.utils.result import Result
19
19
 
20
+ if TYPE_CHECKING: # mediapipe is imported lazily inside analyze_face_mesh
21
+ import mediapipe as mp
22
+
20
23
 
21
24
  # Constants
22
25
  DEFAULT_MAX_FACES = 1
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import sys
4
4
  from pathlib import Path
5
+ from typing import TYPE_CHECKING
5
6
 
6
7
  # Add src directory to path for absolute imports
7
8
  _file_path = Path(__file__).resolve()
@@ -13,12 +14,11 @@ from ImagePRO.utils.image import Image
13
14
  from ImagePRO.utils.result import Result
14
15
 
15
16
  import cv2
16
- import mediapipe as mp
17
+
18
+ if TYPE_CHECKING: # mediapipe is imported lazily inside the functions
19
+ import mediapipe as mp
17
20
 
18
21
  # Constants
19
- mp_face_mesh = mp.solutions.face_mesh
20
- mp_drawing_utils = mp.solutions.drawing_utils
21
- mp_drawing_styles = mp.solutions.drawing_styles
22
22
  DEFAULT_MAX_FACES = 1
23
23
  DEFAULT_MIN_CONFIDENCE = 0.7
24
24
  TOTAL_FACE_LANDMARKS = 468
@@ -71,7 +71,6 @@ def analyze_face_mesh(
71
71
  - Coordinates are normalized [0,1]. Multiply by width/height for pixels
72
72
  - Full mesh (468 points) shows tessellation, specific points show dots
73
73
  """
74
-
75
74
  # Validate inputs
76
75
  if not isinstance(image, Image):
77
76
  raise TypeError("'image' must be an Image instance")
@@ -88,6 +87,18 @@ def analyze_face_mesh(
88
87
  ):
89
88
  raise TypeError("'landmarks_idx' must be a list of integers")
90
89
 
90
+ try:
91
+ import mediapipe as mp
92
+ except ImportError as err:
93
+ raise ImportError(
94
+ "The optional 'mediapipe' dependency is required for face mesh "
95
+ 'analysis. Install it with: pip install "ImagePRO-Python[mediapipe]"'
96
+ ) from err
97
+
98
+ mp_face_mesh = mp.solutions.face_mesh
99
+ mp_drawing_utils = mp.solutions.drawing_utils
100
+ mp_drawing_styles = mp.solutions.drawing_styles
101
+
91
102
  # Initialize detector if needed
92
103
  if face_mesh_obj is None:
93
104
  face_mesh = mp_face_mesh.FaceMesh(
@@ -195,13 +206,21 @@ def analyze_face_mesh_live(
195
206
  if not isinstance(min_confidence, (int, float)) or not (0 <= min_confidence <= 1):
196
207
  raise ValueError("'min_confidence' must be between 0 and 1")
197
208
 
209
+ try:
210
+ import mediapipe as mp
211
+ except ImportError as err:
212
+ raise ImportError(
213
+ "The optional 'mediapipe' dependency is required for face mesh "
214
+ 'analysis. Install it with: pip install "ImagePRO-Python[mediapipe]"'
215
+ ) from err
216
+
198
217
  # Initialize camera
199
218
  cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
200
219
  if not cap.isOpened():
201
220
  raise RuntimeError("Cannot access webcam")
202
221
 
203
222
  # Initialize detector in tracking mode for better performance
204
- face_mesh = mp_face_mesh.FaceMesh(
223
+ face_mesh = mp.solutions.face_mesh.FaceMesh(
205
224
  max_num_faces=max_faces,
206
225
  min_detection_confidence=min_confidence,
207
226
  refine_landmarks=True,
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import sys
4
4
  from pathlib import Path
5
+ from typing import TYPE_CHECKING
5
6
 
6
7
  # Add src directory to path for absolute imports
7
8
  _file_path = Path(__file__).resolve()
@@ -14,10 +15,11 @@ from ImagePRO.utils.image import Image
14
15
  from ImagePRO.utils.result import Result
15
16
 
16
17
  import cv2
17
- import mediapipe as mp
18
+
19
+ if TYPE_CHECKING: # mediapipe is imported lazily inside the functions
20
+ import mediapipe as mp
18
21
 
19
22
  # Constants
20
- mp_face_mesh = mp.solutions.face_mesh
21
23
  DEFAULT_MAX_FACES = 1
22
24
  DEFAULT_MIN_CONFIDENCE = 0.7
23
25
  HEAD_POSE_INDICES = [1, 152, 33, 263, 168] # nose_tip, chin, left_eye, right_eye, nasion
@@ -169,13 +171,21 @@ def estimate_head_pose_live(
169
171
  if not 0 <= min_confidence <= 1:
170
172
  raise ValueError("'min_confidence' must be between 0 and 1")
171
173
 
174
+ try:
175
+ import mediapipe as mp
176
+ except ImportError as err:
177
+ raise ImportError(
178
+ "The optional 'mediapipe' dependency is required for head pose "
179
+ 'estimation. Install it with: pip install "ImagePRO-Python[mediapipe]"'
180
+ ) from err
181
+
172
182
  # Initialize webcam
173
183
  cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
174
184
  if not cap.isOpened():
175
185
  raise RuntimeError("Failed to access webcam")
176
186
 
177
187
  # Initialize face mesh detector for video
178
- face_mesh = mp_face_mesh.FaceMesh(
188
+ face_mesh = mp.solutions.face_mesh.FaceMesh(
179
189
  max_num_faces=max_faces,
180
190
  min_detection_confidence=min_confidence,
181
191
  refine_landmarks=True,
@@ -1,9 +1,9 @@
1
1
  # Object Analysis Module
2
2
  # Provides object detection capabilities using YOLO models
3
+ #
4
+ # The ultralytics dependency is optional and imported lazily inside the
5
+ # functions that need it, so this package imports cleanly without it.
3
6
 
4
- try: # object_detection needs the optional ultralytics dependency
5
- from . import object_detection
6
- except ImportError:
7
- object_detection = None
7
+ from . import object_detection
8
8
 
9
9
  __all__ = ["object_detection"]
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import sys
4
4
  from pathlib import Path
5
+ from typing import TYPE_CHECKING
5
6
 
6
7
  # Add src directory to path for absolute imports
7
8
  _file_path = Path(__file__).resolve()
@@ -9,11 +10,12 @@ _src_path = _file_path.parents[2] # Go up to src directory
9
10
  if str(_src_path) not in sys.path:
10
11
  sys.path.insert(0, str(_src_path))
11
12
 
12
- from ultralytics import YOLO
13
-
14
13
  from ImagePRO.utils.image import Image
15
14
  from ImagePRO.utils.result import Result
16
15
 
16
+ if TYPE_CHECKING: # ultralytics is imported lazily inside the function
17
+ from ultralytics import YOLO
18
+
17
19
  # Constants
18
20
  DEFAULT_ACCURACY_LEVEL = 1
19
21
  MODEL_MAPPING = {
@@ -65,15 +67,24 @@ def detect_objects(
65
67
  if not isinstance(image, Image):
66
68
  raise TypeError("'image' must be an Image instance")
67
69
 
70
+ # accuracy_level only applies when no model is given
71
+ if model is None and accuracy_level not in MODEL_MAPPING:
72
+ raise ValueError(
73
+ f"'accuracy_level' must be in {list(MODEL_MAPPING.keys())}, "
74
+ f"got {accuracy_level}"
75
+ )
76
+
77
+ try:
78
+ from ultralytics import YOLO
79
+ except ImportError as err:
80
+ raise ImportError(
81
+ "The optional 'ultralytics' dependency is required for object "
82
+ 'detection. Install it with: pip install "ImagePRO-Python[yolo]"'
83
+ ) from err
84
+
68
85
  # Initialize model
69
86
  model_name = None
70
87
  if model is None:
71
- if accuracy_level not in MODEL_MAPPING:
72
- raise ValueError(
73
- f"'accuracy_level' must be in {list(MODEL_MAPPING.keys())}, "
74
- f"got {accuracy_level}"
75
- )
76
-
77
88
  model_name = MODEL_MAPPING[accuracy_level]
78
89
  model = YOLO(model=model_name)
79
90
 
@@ -0,0 +1,9 @@
1
+ # Pipeline Module
2
+ # Provides a reusable, ordered chain of image processing operations
3
+ #
4
+ # Uses only base dependencies (numpy); all operations handed to a Pipeline
5
+ # may come from any module, including those with optional backends.
6
+
7
+ from .pipeline import Pipeline, Step
8
+
9
+ __all__ = ["Pipeline", "Step"]
@@ -0,0 +1,362 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ from pathlib import Path
5
+ from typing import Any, Callable, Iterator
6
+
7
+ # Add src directory to path for absolute imports
8
+ _file_path = Path(__file__).resolve()
9
+ _src_path = _file_path.parents[2] # Go up to src directory
10
+ if str(_src_path) not in sys.path:
11
+ sys.path.insert(0, str(_src_path))
12
+
13
+ import numpy as np
14
+
15
+ from ImagePRO.utils.image import Image
16
+ from ImagePRO.utils.result import Result
17
+
18
+
19
+ class Step:
20
+ """
21
+ A single operation in a Pipeline, with optional keyword arguments.
22
+
23
+ Wraps any callable that accepts an Image as its first positional argument
24
+ and returns a Result (or a numpy.ndarray, treated as the output image).
25
+ Keyword arguments given to the constructor are forwarded to the wrapped
26
+ function on every call, so a Step fully describes one stage of a pipeline.
27
+
28
+ Example:
29
+ >>> from ImagePRO.pre_processing.blur import apply_gaussian_blur
30
+ >>> step = Step(apply_gaussian_blur, kernel_size=(7, 7))
31
+ >>> result = step(image) # Same as apply_gaussian_blur(image, kernel_size=(7, 7))
32
+
33
+ Attributes:
34
+ function (Callable):
35
+ The wrapped function to execute.
36
+ kwargs (dict[str, Any]):
37
+ Keyword-only arguments forwarded to the function on each call.
38
+ """
39
+
40
+ def __init__(self, function: Callable[..., Result], **kwargs: Any) -> None:
41
+ """
42
+ Create a Step from a function and its keyword arguments.
43
+
44
+ Args:
45
+ function (Callable):
46
+ Function to wrap. Must be callable and accept an Image as its
47
+ first positional argument.
48
+ **kwargs (Any):
49
+ Keyword-only arguments forwarded to the function on every call.
50
+
51
+ Raises:
52
+ TypeError: If function is not callable.
53
+ """
54
+ if not callable(function):
55
+ raise TypeError("'function' must be a callable.")
56
+ self.function = function
57
+ self.kwargs: dict[str, Any] = dict(kwargs)
58
+
59
+ @property
60
+ def name(self) -> str:
61
+ """
62
+ Human-readable name of the wrapped function, used in pipeline metadata.
63
+
64
+ Returns:
65
+ str: The function's __name__ when available, otherwise the name
66
+ of its type (e.g. 'partial' for functools.partial objects).
67
+ """
68
+ return getattr(self.function, "__name__", type(self.function).__name__)
69
+
70
+ def __call__(self, image: Image) -> Result:
71
+ """
72
+ Execute the wrapped function on an image.
73
+
74
+ Args:
75
+ image (Image):
76
+ Input image passed to the wrapped function.
77
+
78
+ Returns:
79
+ Result: Whatever the wrapped function returns.
80
+
81
+ Raises:
82
+ TypeError: If image is not an Image instance (raised by the
83
+ wrapped function's own validation).
84
+ ValueError: If wrapped function arguments are invalid (raised by
85
+ the wrapped function's own validation).
86
+ """
87
+ return self.function(image, **self.kwargs)
88
+
89
+ def __repr__(self) -> str:
90
+ """
91
+ Return a readable representation of the step.
92
+
93
+ Returns:
94
+ str: Representation including the function name and arguments.
95
+ """
96
+ args = ", ".join(f"{key}={value!r}" for key, value in self.kwargs.items())
97
+ return f"Step({self.name}{', ' + args if args else ''})"
98
+
99
+
100
+ class Pipeline:
101
+ """
102
+ A reusable, ordered chain of image processing operations.
103
+
104
+ A Pipeline is defined once from a sequence of functions and can then be
105
+ run on any input as many times as needed. Each operation receives an
106
+ Image and its output image is automatically wrapped and fed to the next
107
+ operation; the final Result is returned with pipeline metadata attached.
108
+
109
+ Operations are the standard ImagePRO functions (which take an Image and
110
+ return a Result) or any custom callable following the same convention.
111
+ A custom function may also return a plain numpy.ndarray, which is treated
112
+ as the output image. Per-operation keyword arguments are configured with
113
+ Step, or fluently via apply().
114
+
115
+ Pipelines are immutable: apply() returns a new Pipeline and leaves the
116
+ original untouched, and run() never mutates the pipeline, so a single
117
+ Pipeline instance is safe to reuse across many inputs.
118
+
119
+ Example:
120
+ >>> from ImagePRO.pre_processing.blur import apply_gaussian_blur
121
+ >>> from ImagePRO.pre_processing.grayscale import convert_to_grayscale
122
+ >>> from ImagePRO.pre_processing.resize import resize_image
123
+ >>>
124
+ >>> pipeline = Pipeline([
125
+ ... Step(apply_gaussian_blur, kernel_size=(7, 7)),
126
+ ... convert_to_grayscale,
127
+ ... Step(resize_image, new_size=(800, 600)),
128
+ ... ])
129
+ >>> result = pipeline.run("photo.jpg") # Any Image, ndarray or path
130
+ >>> result.save_as_img("processed.jpg")
131
+ """
132
+
133
+ def __init__(self, *operations: Any) -> None:
134
+ """
135
+ Create a Pipeline from one or more operations.
136
+
137
+ Operations can be passed as separate arguments or as a single
138
+ list/tuple. Passing another Pipeline as an operation nests it: the
139
+ inner pipeline runs as a single step.
140
+
141
+ Args:
142
+ *operations (Callable | Step | list | tuple):
143
+ Functions to execute in order. Each element must be callable;
144
+ Step instances carry their keyword arguments. A single
145
+ list/tuple of operations is also accepted.
146
+
147
+ Raises:
148
+ TypeError: If any operation is not callable.
149
+ """
150
+ if len(operations) == 1 and isinstance(operations[0], (list, tuple)):
151
+ operations = tuple(operations[0])
152
+
153
+ steps: list[Step] = []
154
+ for operation in operations:
155
+ if not callable(operation):
156
+ raise TypeError(
157
+ "All pipeline operations must be callable; got "
158
+ f"{type(operation).__name__}. Wrap keyword arguments with "
159
+ "Step, e.g. Step(resize_image, new_size=(800, 600))."
160
+ )
161
+ steps.append(operation if isinstance(operation, Step) else Step(operation))
162
+ self._operations = steps
163
+
164
+ @property
165
+ def operations(self) -> tuple[Step, ...]:
166
+ """
167
+ The ordered steps of this pipeline.
168
+
169
+ Returns:
170
+ tuple[Step, ...]: Step objects in execution order.
171
+ """
172
+ return tuple(self._operations)
173
+
174
+ def apply(self, function: Callable[..., Result], **kwargs: Any) -> Pipeline:
175
+ """
176
+ Return a new Pipeline with one more operation appended.
177
+
178
+ The current pipeline is not modified, following ImagePRO's
179
+ non-destructive design principle.
180
+
181
+ Args:
182
+ function (Callable):
183
+ Function to append. Must be callable and accept an Image as
184
+ its first positional argument.
185
+ **kwargs (Any):
186
+ Keyword-only arguments forwarded to the function on every run.
187
+
188
+ Returns:
189
+ Pipeline: New pipeline containing all existing steps plus this one.
190
+
191
+ Raises:
192
+ TypeError: If function is not callable.
193
+
194
+ Example:
195
+ >>> pipeline = Pipeline(apply_gaussian_blur).apply(
196
+ ... resize_image, new_size=(800, 600)
197
+ ... )
198
+ """
199
+ return Pipeline(*self._operations, Step(function, **kwargs))
200
+
201
+ def run(self, image: Image | np.ndarray | str | Path) -> Result:
202
+ """
203
+ Execute all pipeline operations in order on the given input.
204
+
205
+ The input is first normalized to an Image (file paths are loaded and
206
+ NumPy arrays are wrapped, assuming BGR for 3-channel and GRAY for 2D
207
+ arrays). Each operation then receives an Image built from the previous
208
+ operation's output; 2D intermediates are tagged as GRAY and
209
+ multi-channel ones keep the incoming colorspace.
210
+
211
+ The returned Result carries the final operation's image and data. Its
212
+ metadata contains the pipeline information (operation, steps,
213
+ step_meta, source) merged over the final operation's own metadata.
214
+
215
+ Args:
216
+ image (Image | np.ndarray | str | Path):
217
+ Input to process. Can be an Image instance, a NumPy array
218
+ (BGR for 3-channel, GRAY for 2D), or a path to an image file.
219
+
220
+ Returns:
221
+ Result: Result object of the final operation.
222
+ - image (np.ndarray | list[np.ndarray] | None): Final output image(s)
223
+ - data (Any): Structured data of the final operation
224
+ - meta (dict): Final operation metadata plus pipeline info:
225
+ 'operation' ("pipeline"), 'steps' (list of step names),
226
+ 'step_meta' (per-step metadata list), 'source' (input Image)
227
+
228
+ Raises:
229
+ TypeError: If image is not an Image, ndarray, or path.
230
+ TypeError: If an operation returns an unsupported type.
231
+ ValueError: If the pipeline has no operations.
232
+ ValueError: If a non-final operation returns no image, so the
233
+ chain cannot continue.
234
+ TypeError/ValueError: As raised by the operations themselves for
235
+ invalid inputs or arguments.
236
+ """
237
+ # Normalize input to an Image (cheap validation before any step runs)
238
+ if isinstance(image, Image):
239
+ current = image
240
+ elif isinstance(image, np.ndarray):
241
+ colorspace = "GRAY" if image.ndim == 2 else "BGR"
242
+ current = Image.from_array(image, colorspace=colorspace)
243
+ elif isinstance(image, (str, Path)):
244
+ current = Image.from_path(image)
245
+ else:
246
+ raise TypeError(
247
+ "'image' must be an Image instance, a numpy.ndarray, or a "
248
+ "file path (str or pathlib.Path)."
249
+ )
250
+
251
+ if not self._operations:
252
+ raise ValueError(
253
+ "Cannot run an empty pipeline. Add operations at construction "
254
+ "or with apply()."
255
+ )
256
+
257
+ source = current
258
+ step_names: list[str] = []
259
+ step_metas: list[dict[str, Any]] = []
260
+ final_image: Any = None
261
+ final_data: Any = None
262
+ final_meta: dict[str, Any] = {}
263
+
264
+ for index, step in enumerate(self._operations):
265
+ is_last = index == len(self._operations) - 1
266
+ output = step(current)
267
+
268
+ # Normalize the step output (Result is the convention; a plain
269
+ # ndarray from custom functions is accepted as the output image)
270
+ if isinstance(output, Result):
271
+ final_image = output.image
272
+ final_data = output.data
273
+ final_meta = dict(output.meta)
274
+ elif isinstance(output, np.ndarray):
275
+ final_image = output
276
+ final_data = None
277
+ final_meta = {}
278
+ else:
279
+ raise TypeError(
280
+ f"Step {index} ('{step.name}') returned "
281
+ f"{type(output).__name__}; pipeline operations must "
282
+ "return a Result object or a numpy.ndarray."
283
+ )
284
+
285
+ step_names.append(step.name)
286
+ step_metas.append(final_meta)
287
+
288
+ if is_last:
289
+ break
290
+
291
+ # Prepare the input of the next operation
292
+ if final_image is None:
293
+ raise ValueError(
294
+ f"Step {index} ('{step.name}') returned no image, so the "
295
+ "pipeline cannot continue. Only the final step of a "
296
+ "pipeline may return a result without an image."
297
+ )
298
+ if not isinstance(final_image, np.ndarray):
299
+ raise ValueError(
300
+ f"Step {index} ('{step.name}') did not return a single "
301
+ "image array, so the pipeline cannot continue. Only the "
302
+ "final step of a pipeline may return multi-image results."
303
+ )
304
+
305
+ colorspace = "GRAY" if final_image.ndim == 2 else current.colorspace
306
+ current = Image.from_array(final_image, colorspace=colorspace)
307
+
308
+ meta = dict(final_meta)
309
+ meta.update({
310
+ "source": source,
311
+ "operation": "pipeline",
312
+ "steps": step_names,
313
+ "step_meta": step_metas,
314
+ })
315
+ return Result(image=final_image, data=final_data, meta=meta)
316
+
317
+ def __call__(self, image: Image | np.ndarray | str | Path) -> Result:
318
+ """
319
+ Run the pipeline on an input; shorthand for run().
320
+
321
+ Args:
322
+ image (Image | np.ndarray | str | Path):
323
+ Input to process, as accepted by run().
324
+
325
+ Returns:
326
+ Result: Result object of the final operation.
327
+
328
+ Raises:
329
+ TypeError: If image is not an Image, ndarray, or path.
330
+ ValueError: If the pipeline has no operations or a non-final
331
+ operation returns no image.
332
+ """
333
+ return self.run(image)
334
+
335
+ def __len__(self) -> int:
336
+ """
337
+ Return the number of operations in the pipeline.
338
+
339
+ Returns:
340
+ int: Number of steps.
341
+ """
342
+ return len(self._operations)
343
+
344
+ def __iter__(self) -> Iterator[Step]:
345
+ """
346
+ Iterate over the pipeline's steps in execution order.
347
+
348
+ Returns:
349
+ Iterator[Step]: Iterator of Step objects.
350
+ """
351
+ return iter(self._operations)
352
+
353
+ def __repr__(self) -> str:
354
+ """
355
+ Return a readable representation of the pipeline.
356
+
357
+ Returns:
358
+ str: Representation listing the step names in order.
359
+ """
360
+ if not self._operations:
361
+ return "Pipeline(<empty>)"
362
+ return f"Pipeline({' -> '.join(step.name for step in self._operations)})"
@@ -1,19 +1,18 @@
1
1
  # Pre-processing Module
2
2
  # Provides image manipulation, filtering, and enhancement capabilities
3
+ #
4
+ # dataset_generator uses the optional mediapipe dependency, imported
5
+ # lazily inside its functions, so it is safe to import here regardless.
3
6
 
4
7
  from . import blur
5
8
  from . import contrast
6
9
  from . import crop
10
+ from . import dataset_generator
7
11
  from . import grayscale
8
12
  from . import resize
9
13
  from . import rotate
10
14
  from . import sharpen
11
15
 
12
- try: # dataset_generator needs the optional mediapipe dependency
13
- from . import dataset_generator
14
- except ImportError:
15
- dataset_generator = None
16
-
17
16
  __all__ = [
18
17
  "blur",
19
18
  "contrast",
@@ -12,7 +12,6 @@ if str(_src_path) not in sys.path:
12
12
  sys.path.insert(0, str(_src_path))
13
13
 
14
14
  import cv2
15
- import mediapipe as mp
16
15
 
17
16
  from ImagePRO.human_analysis.face_analysis.face_detection import detect_faces
18
17
  from ImagePRO.pre_processing import blur, grayscale, resize, rotate, sharpen
@@ -95,6 +94,14 @@ def capture_bulk_pictures(
95
94
  if not isinstance(delay, (int, float)) or delay < 0:
96
95
  raise ValueError("'delay' must be a non-negative number")
97
96
 
97
+ try:
98
+ import mediapipe as mp
99
+ except ImportError as err:
100
+ raise ImportError(
101
+ "The optional 'mediapipe' dependency is required for dataset "
102
+ 'generation. Install it with: pip install "ImagePRO-Python[mediapipe]"'
103
+ ) from err
104
+
98
105
  # Setup output directory structure
99
106
  base_dir = Path(folder_path)
100
107
  face_folder = base_dir / str(face_id)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ImagePRO-Python
3
- Version: 1.3.0
3
+ Version: 1.4.0
4
4
  Summary: Professional & modular image processing library with OpenCV, MediaPipe, and YOLO integration.
5
5
  Author-email: Parsa Safaie <parsasafaie.2568@proton.me>
6
6
  License: MIT
@@ -76,6 +76,11 @@ Whether you're working on computer vision pipelines, preprocessing images for AI
76
76
  - **YOLO Integration**: Multiple accuracy levels (nano to extra-large)
77
77
  - **Flexible Models**: Pre-trained or custom model support
78
78
 
79
+ ### **Pipelines**
80
+ - **Reusable Operation Chains**: Define a sequence of functions once, then run it on any input (Image, NumPy array, or file path)
81
+ - **Flexible Steps**: Any ImagePRO function or custom callable; per-step keyword arguments via `Step`
82
+ - **Pipeline Metadata**: Every result lists the executed steps and each step's parameters
83
+
79
84
  ## Installation
80
85
 
81
86
  ### From PyPI
@@ -90,6 +95,8 @@ pip install "ImagePRO-Python[full]" # Everything
90
95
  pip install "ImagePRO-Python[dev]" # Test tooling (pytest)
91
96
  ```
92
97
 
98
+ > **Note**: The base install is lightweight — AI backends (MediaPipe, Ultralytics, InsightFace) are optional and imported lazily, only when you call a function that actually needs them. `import ImagePRO` never loads these dependencies. If a backend is missing, the function you call raises an `ImportError` telling you exactly which extra to install.
99
+
93
100
  ### From Source
94
101
  ```bash
95
102
  git clone https://github.com/parsasafaie/ImagePRO.git
@@ -152,6 +159,22 @@ object_detection_result = detect_objects(
152
159
  )
153
160
  print(f"Detected {len(object_detection_result.data)} objects")
154
161
  object_detection_result.save_as_img("detections.jpg")
162
+
163
+ # Chain operations into a reusable pipeline
164
+ from ImagePRO.pipeline import Pipeline, Step
165
+ from ImagePRO.pre_processing.grayscale import convert_to_grayscale
166
+ from ImagePRO.pre_processing.resize import resize_image
167
+
168
+ pipeline = Pipeline([
169
+ Step(apply_gaussian_blur, kernel_size=(7, 7)),
170
+ convert_to_grayscale,
171
+ Step(resize_image, new_size=(800, 600)),
172
+ ])
173
+
174
+ # Run it on any input: an Image, a NumPy array, or a file path
175
+ pipeline_result = pipeline.run("person_and_objects.jpg")
176
+ pipeline_result.save_as_img("processed_output.jpg")
177
+ print(pipeline_result.meta["steps"]) # Executed step names
155
178
  ```
156
179
 
157
180
  > **Note**: These are basic examples. Each module contains many more functions with extensive customization options. Explore the module-specific README files for detailed documentation.
@@ -165,6 +188,7 @@ Each module includes comprehensive documentation with detailed examples:
165
188
  - [Face Analysis](src/ImagePRO/human_analysis/face_analysis/README.md): Face mesh, pose estimation, eye status, comparison
166
189
  - [Body Analysis](src/ImagePRO/human_analysis/body_analysis/README.md): Body pose and hand tracking
167
190
  - **[Object Analysis](src/ImagePRO/object_analysis/README.md)**: YOLO-based object detection
191
+ - **[Pipeline](src/ImagePRO/pipeline/README.md)**: Reusable chains of image processing operations
168
192
  - **[Utils](src/ImagePRO/utils/README.md)**: Shared utilities and I/O handling
169
193
 
170
194
  For detailed project structure and development guidelines, see [PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md).
@@ -176,6 +200,8 @@ ImagePRO is built with a modular architecture designed for extensibility and mai
176
200
  - **Clean Separation of Concerns**: Each module handles a specific domain
177
201
  - **Consistent API Patterns**: All functions follow the same input/output conventions
178
202
  - **Shared Utilities**: Common `Image` and `Result` classes for unified I/O
203
+ - **Reusable Pipelines**: Chain any operations into a `Pipeline` and run it on any input
204
+ - **Lazy Optional Imports**: Heavy AI dependencies (MediaPipe, Ultralytics, InsightFace) are only imported inside the functions that use them, keeping `import ImagePRO` fast and independent of installed extras
179
205
  - **Professional Error Handling**: Comprehensive validation with clear error messages
180
206
  - **Type Safety**: Full type hints throughout the codebase
181
207
  - **Documentation**: Google-style docstrings for all functions
@@ -0,0 +1,33 @@
1
+ ImagePRO/__init__.py,sha256=3B8cQH4zhV6EEAvVMKYMsJHok_hpGLTgu4QfP33DV08,1081
2
+ ImagePRO/human_analysis/__init__.py,sha256=uSU0lM1p1HM6TNGv6u0nPHWy9QY505v43lqTkhClddM,190
3
+ ImagePRO/human_analysis/body_analysis/__init__.py,sha256=uUWG5eOxLQjZoYddmNkRlF66l6vSVyJpUFz1wDddXkk,374
4
+ ImagePRO/human_analysis/body_analysis/body_pose_estimation.py,sha256=yqEV18ZEZwV__Oqt1Hi72EGmbTNes-mrY068SBT9RbU,6245
5
+ ImagePRO/human_analysis/body_analysis/hand_tracking.py,sha256=SpdIZNgvaHzINpWu7rgNawSHvuuawzFtQ7JiHHQ0fqA,7578
6
+ ImagePRO/human_analysis/face_analysis/__init__.py,sha256=297IQuoO2Wb_PyigS_2NOuVnM7FpNPceu5jhJp6YdG0,604
7
+ ImagePRO/human_analysis/face_analysis/eye_status_analysis.py,sha256=Q_EUNPpXoF7Vi-Kd0gURNxs9X3U5J4Yi3coL_6lkeb8,7773
8
+ ImagePRO/human_analysis/face_analysis/face_comparison.py,sha256=lIr490PAf8R6C_Zhv-zBN1Un1EPiwxi4W7ahgkqXAVc,4724
9
+ ImagePRO/human_analysis/face_analysis/face_detection.py,sha256=F3Bq_0rAcQklmNAu-JvxGBIxUnWmyM-SHuZawHXJeac,4009
10
+ ImagePRO/human_analysis/face_analysis/face_mesh_analysis.py,sha256=rv08Mx_IBB-hjTh09bFaaPjaOm0tFbBs0brc4mE66mg,8723
11
+ ImagePRO/human_analysis/face_analysis/head_pose_estimation.py,sha256=2_ZVpwavyIzCIH4x3d2bvCPvv-X5gpmSYxtk5jlgCYw,7688
12
+ ImagePRO/object_analysis/__init__.py,sha256=eVQpYlHO89RYKT0CHjPfJjjif5X_Jx3AtAUpR5m0Yms,292
13
+ ImagePRO/object_analysis/object_detection.py,sha256=1qPd3Xfo2Vi4JnBs5wD8-k3WR6ZkYNdT9tco2Ze1ICQ,3385
14
+ ImagePRO/pipeline/__init__.py,sha256=-32hbR492qwxutXau7EfnysXbhW8fKKMywkV0ejIMFE,301
15
+ ImagePRO/pipeline/pipeline.py,sha256=-CRWfWXB_lFdjrqg3gdyYFFvq0vZAednrJnod6b4WYA,13802
16
+ ImagePRO/pre_processing/__init__.py,sha256=pw6-J5sdbkdBG4RlTxOzQKaspGnlPIGo3m_NXH2bVCE,559
17
+ ImagePRO/pre_processing/blur.py,sha256=3zNTNpvLZPdrtRtBziB6X8ys8M7cIvyPDhojTqR63jo,7950
18
+ ImagePRO/pre_processing/contrast.py,sha256=4UT78ggW1rh_iaEI8FObDB4kpEmRRFWjdJES60SnHDM,5064
19
+ ImagePRO/pre_processing/crop.py,sha256=3Nwerzo57kx1sZPr9m355P-qf1NuZSZEA5iUn2Q1704,2406
20
+ ImagePRO/pre_processing/dataset_generator.py,sha256=i7UM4o8hznFUfUgbYI6H01EkQJOqt4IsI9IrjzzN8gQ,7921
21
+ ImagePRO/pre_processing/grayscale.py,sha256=MRCsFRIaL45sYVHzhuNyZBXsP7PF-yorn0Wt7xONvpY,1781
22
+ ImagePRO/pre_processing/histogram.py,sha256=sNTWWZXr5VLpOrF_PTTJ6TD8yv1zR1l9cMyXHe7JFIM,2596
23
+ ImagePRO/pre_processing/resize.py,sha256=Rnde8l_PXck5OWQBEMOHgLeW2YkTz9Xfr6fGmz0sdm8,1760
24
+ ImagePRO/pre_processing/rotate.py,sha256=wQj3nQpN-ilM0HHwovN--UdGEJkPCY0BJ0zAdyBxv-o,4174
25
+ ImagePRO/pre_processing/sharpen.py,sha256=hOkY7QhzgMp9LXQwt56AP4enn24ntXlmFLe57Bxssvw,3682
26
+ ImagePRO/utils/__init__.py,sha256=McVd-o9KtKOpAVYbLi19KxsatPPFFF-Qbt0gdgY3Ln8,170
27
+ ImagePRO/utils/image.py,sha256=Y64mD97rTiJb8_uNYlyG227VZodeb4U1aGezMkj7MnM,4025
28
+ ImagePRO/utils/result.py,sha256=ToQaOmUlTtobJkC65BG0YO_6BkBleMBn-0Qydko7cZc,6138
29
+ imagepro_python-1.4.0.dist-info/licenses/LICENSE,sha256=sehkHN7dbe5umrINZJyJjIf9VTemZSgTfJlq6iIsbJQ,1069
30
+ imagepro_python-1.4.0.dist-info/METADATA,sha256=POgVUYD-3fKBCKxkjSgKTZqCt5BWjvtfDBqlrn7Qg9I,11121
31
+ imagepro_python-1.4.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
32
+ imagepro_python-1.4.0.dist-info/top_level.txt,sha256=UOuPzsoWrVKXgUupOSI96shJ6wE8Fhz-8bm8oMlLC3s,9
33
+ imagepro_python-1.4.0.dist-info/RECORD,,
@@ -1,31 +0,0 @@
1
- ImagePRO/__init__.py,sha256=yY-6-5p9OyeNlmPnYMeht-2yJJun8DJvH7yi0b-tMOE,997
2
- ImagePRO/human_analysis/__init__.py,sha256=uSU0lM1p1HM6TNGv6u0nPHWy9QY505v43lqTkhClddM,190
3
- ImagePRO/human_analysis/body_analysis/__init__.py,sha256=ezFnUJNwQXW47n9Bfxcmk4BNgvt_Bqs3Y5VESxgz2Sg,494
4
- ImagePRO/human_analysis/body_analysis/body_pose_estimation.py,sha256=QkqF27YOHYoOVq5KMz0AaU455CQcRVfTbFStPZGYUA8,5565
5
- ImagePRO/human_analysis/body_analysis/hand_tracking.py,sha256=fYOQGu5mcrYgqtWu5wW0xApx76fOXGDxz3hZRUhvW9k,6910
6
- ImagePRO/human_analysis/face_analysis/__init__.py,sha256=nABUIg9Z-yL6JfAxMb2fqwfxmSfJmvSxfwnQuKSIOGg,1028
7
- ImagePRO/human_analysis/face_analysis/eye_status_analysis.py,sha256=9ydxEj4EhVCNf954gdFBQemS1uRNA-XGCMzyliI2AsQ,7126
8
- ImagePRO/human_analysis/face_analysis/face_comparison.py,sha256=vHYqWTuXEadoeZn-z81ZazXlpBri702Gz37XdWPJirw,4303
9
- ImagePRO/human_analysis/face_analysis/face_detection.py,sha256=9LFMotGJ0KlAUb5yTfrXaAH_Ztr3OO3vbXLhXTN8M9M,3896
10
- ImagePRO/human_analysis/face_analysis/face_mesh_analysis.py,sha256=TBSZELe_CdXcXDRRiaAYkDqHHpktRhi_koC-2iwk2Gk,8038
11
- ImagePRO/human_analysis/face_analysis/head_pose_estimation.py,sha256=CovQITnmLNiLlEWffuL0idAJNBOC_nnZlC-4G9pFXxs,7328
12
- ImagePRO/object_analysis/__init__.py,sha256=KcFRxVKnC0qU82zS31P4CriZIKqZdyGqQwdrMy9N4pc,267
13
- ImagePRO/object_analysis/object_detection.py,sha256=REfu73vNSvUIbIzel24jygyCumZKvYr7_d6YyLDhdwY,2943
14
- ImagePRO/pre_processing/__init__.py,sha256=d10ZfQzWM0JRJrFrMHOr-mxF4XYnObj6GYPTLaqzqDA,536
15
- ImagePRO/pre_processing/blur.py,sha256=3zNTNpvLZPdrtRtBziB6X8ys8M7cIvyPDhojTqR63jo,7950
16
- ImagePRO/pre_processing/contrast.py,sha256=4UT78ggW1rh_iaEI8FObDB4kpEmRRFWjdJES60SnHDM,5064
17
- ImagePRO/pre_processing/crop.py,sha256=3Nwerzo57kx1sZPr9m355P-qf1NuZSZEA5iUn2Q1704,2406
18
- ImagePRO/pre_processing/dataset_generator.py,sha256=7sL9uI_i272eOO1U_XFAaAoo7pfnU5ryuRuLERilzgo,7667
19
- ImagePRO/pre_processing/grayscale.py,sha256=MRCsFRIaL45sYVHzhuNyZBXsP7PF-yorn0Wt7xONvpY,1781
20
- ImagePRO/pre_processing/histogram.py,sha256=sNTWWZXr5VLpOrF_PTTJ6TD8yv1zR1l9cMyXHe7JFIM,2596
21
- ImagePRO/pre_processing/resize.py,sha256=Rnde8l_PXck5OWQBEMOHgLeW2YkTz9Xfr6fGmz0sdm8,1760
22
- ImagePRO/pre_processing/rotate.py,sha256=wQj3nQpN-ilM0HHwovN--UdGEJkPCY0BJ0zAdyBxv-o,4174
23
- ImagePRO/pre_processing/sharpen.py,sha256=hOkY7QhzgMp9LXQwt56AP4enn24ntXlmFLe57Bxssvw,3682
24
- ImagePRO/utils/__init__.py,sha256=McVd-o9KtKOpAVYbLi19KxsatPPFFF-Qbt0gdgY3Ln8,170
25
- ImagePRO/utils/image.py,sha256=Y64mD97rTiJb8_uNYlyG227VZodeb4U1aGezMkj7MnM,4025
26
- ImagePRO/utils/result.py,sha256=ToQaOmUlTtobJkC65BG0YO_6BkBleMBn-0Qydko7cZc,6138
27
- imagepro_python-1.3.0.dist-info/licenses/LICENSE,sha256=sehkHN7dbe5umrINZJyJjIf9VTemZSgTfJlq6iIsbJQ,1069
28
- imagepro_python-1.3.0.dist-info/METADATA,sha256=8Rl5PyW1UcO7Zc_nZuzHCYtU7u-lUbhY8d-J2qR6B1A,9435
29
- imagepro_python-1.3.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
30
- imagepro_python-1.3.0.dist-info/top_level.txt,sha256=UOuPzsoWrVKXgUupOSI96shJ6wE8Fhz-8bm8oMlLC3s,9
31
- imagepro_python-1.3.0.dist-info/RECORD,,