ImagePRO-Python 1.2.1__py3-none-any.whl → 1.3.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 (28) hide show
  1. ImagePRO/__init__.py +2 -2
  2. ImagePRO/human_analysis/body_analysis/__init__.py +12 -2
  3. ImagePRO/human_analysis/body_analysis/body_pose_estimation.py +3 -2
  4. ImagePRO/human_analysis/body_analysis/hand_tracking.py +5 -3
  5. ImagePRO/human_analysis/face_analysis/__init__.py +29 -6
  6. ImagePRO/human_analysis/face_analysis/face_comparison.py +2 -2
  7. ImagePRO/human_analysis/face_analysis/face_detection.py +1 -1
  8. ImagePRO/human_analysis/face_analysis/face_mesh_analysis.py +11 -12
  9. ImagePRO/human_analysis/face_analysis/head_pose_estimation.py +1 -1
  10. ImagePRO/object_analysis/__init__.py +4 -1
  11. ImagePRO/object_analysis/object_detection.py +6 -6
  12. ImagePRO/pre_processing/__init__.py +6 -2
  13. ImagePRO/pre_processing/blur.py +10 -10
  14. ImagePRO/pre_processing/contrast.py +4 -7
  15. ImagePRO/pre_processing/crop.py +4 -5
  16. ImagePRO/pre_processing/dataset_generator.py +9 -10
  17. ImagePRO/pre_processing/histogram.py +36 -48
  18. ImagePRO/pre_processing/resize.py +2 -2
  19. ImagePRO/pre_processing/rotate.py +6 -7
  20. ImagePRO/pre_processing/sharpen.py +16 -13
  21. ImagePRO/utils/image.py +7 -6
  22. ImagePRO/utils/result.py +10 -7
  23. {imagepro_python-1.2.1.dist-info → imagepro_python-1.3.0.dist-info}/METADATA +43 -18
  24. imagepro_python-1.3.0.dist-info/RECORD +31 -0
  25. {imagepro_python-1.2.1.dist-info → imagepro_python-1.3.0.dist-info}/WHEEL +1 -1
  26. imagepro_python-1.2.1.dist-info/RECORD +0 -31
  27. {imagepro_python-1.2.1.dist-info → imagepro_python-1.3.0.dist-info}/licenses/LICENSE +0 -0
  28. {imagepro_python-1.2.1.dist-info → imagepro_python-1.3.0.dist-info}/top_level.txt +0 -0
ImagePRO/__init__.py CHANGED
@@ -15,7 +15,7 @@ Features:
15
15
  - Real-time processing capabilities
16
16
  """
17
17
 
18
- __version__ = "1.0.0"
18
+ __version__ = "1.3.0"
19
19
  __author__ = "Parsa Safaie"
20
20
  __email__ = "parsasafaie.2568@proton.me"
21
21
 
@@ -27,7 +27,7 @@ from . import object_analysis
27
27
 
28
28
  __all__ = [
29
29
  "utils",
30
- "pre_processing",
30
+ "pre_processing",
31
31
  "human_analysis",
32
32
  "object_analysis"
33
33
  ]
@@ -1,7 +1,17 @@
1
1
  # Body Analysis Module
2
2
  # Provides body pose estimation and hand tracking capabilities
3
+ #
4
+ # Both modules need the optional mediapipe dependency; they are imported
5
+ # guardedly so the package stays importable without it.
3
6
 
4
- from . import body_pose_estimation
5
- from . import hand_tracking
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
6
16
 
7
17
  __all__ = ["body_pose_estimation", "hand_tracking"]
@@ -64,7 +64,7 @@ def detect_body_pose(
64
64
  raise ValueError("'min_confidence' must be between 0.0 and 1.0")
65
65
 
66
66
  if landmarks_idx is not None and (
67
- not isinstance(landmarks_idx, list)
67
+ not isinstance(landmarks_idx, list)
68
68
  or not all(isinstance(i, int) for i in landmarks_idx)
69
69
  ):
70
70
  raise TypeError("'landmarks_idx' must be a list of integers")
@@ -97,7 +97,8 @@ def detect_body_pose(
97
97
  img_copy,
98
98
  result.pose_landmarks,
99
99
  mp_pose.POSE_CONNECTIONS,
100
- landmark_drawing_spec=mp.solutions.drawing_styles.get_default_pose_landmarks_style()
100
+ landmark_drawing_spec=mp.solutions.drawing_styles
101
+ .get_default_pose_landmarks_style()
101
102
  )
102
103
  else:
103
104
  # Draw only selected points
@@ -74,7 +74,7 @@ def detect_hands(
74
74
  raise ValueError("'min_confidence' must be between 0.0 and 1.0")
75
75
 
76
76
  if landmarks_idx is not None and (
77
- not isinstance(landmarks_idx, list)
77
+ not isinstance(landmarks_idx, list)
78
78
  or not all(isinstance(i, int) for i in landmarks_idx)
79
79
  ):
80
80
  raise TypeError("'landmarks_idx' must be a list of integers")
@@ -109,8 +109,10 @@ def detect_hands(
109
109
  image=img_copy,
110
110
  landmark_list=hand_landmarks,
111
111
  connections=mp_hands.HAND_CONNECTIONS,
112
- landmark_drawing_spec=mp.solutions.drawing_styles.get_default_hand_landmarks_style(),
113
- connection_drawing_spec=mp.solutions.drawing_styles.get_default_hand_connections_style()
112
+ landmark_drawing_spec=mp.solutions.drawing_styles
113
+ .get_default_hand_landmarks_style(),
114
+ connection_drawing_spec=mp.solutions.drawing_styles
115
+ .get_default_hand_connections_style()
114
116
  )
115
117
  else:
116
118
  # Draw only selected points
@@ -1,16 +1,39 @@
1
1
  # Face Analysis Module
2
2
  # Provides facial landmark detection, pose estimation, and eye status analysis
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.
3
7
 
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
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
9
32
 
10
33
  __all__ = [
11
34
  "eye_status_analysis",
12
35
  "face_comparison",
13
- "face_detection",
36
+ "face_detection",
14
37
  "face_mesh_analysis",
15
38
  "head_pose_estimation"
16
39
  ]
@@ -85,8 +85,8 @@ def compare_faces(
85
85
 
86
86
  try:
87
87
  # Save images to disk if needed
88
- path_1 = save_temp_image(image_1._data, 'tmp1.jpg')
89
- path_2 = save_temp_image(image_2._data, 'tmp2.jpg')
88
+ path_1 = save_temp_image(image_1, 'tmp1.jpg')
89
+ path_2 = save_temp_image(image_2, 'tmp2.jpg')
90
90
 
91
91
  # Load and preprocess images
92
92
  img1 = load_rgb_image(path_1)
@@ -29,7 +29,7 @@ FACE_OUTLINE_INDICES = [
29
29
 
30
30
 
31
31
  def detect_faces(
32
- image: Image,
32
+ image: Image,
33
33
  *,
34
34
  max_faces: int = DEFAULT_MAX_FACES,
35
35
  min_confidence: float = DEFAULT_MIN_CONFIDENCE,
@@ -83,7 +83,7 @@ def analyze_face_mesh(
83
83
  raise ValueError("'min_confidence' must be between 0 and 1")
84
84
 
85
85
  if landmarks_idx is not None and (
86
- not isinstance(landmarks_idx, list)
86
+ not isinstance(landmarks_idx, list)
87
87
  or not all(isinstance(i, int) for i in landmarks_idx)
88
88
  ):
89
89
  raise TypeError("'landmarks_idx' must be a list of integers")
@@ -99,11 +99,8 @@ def analyze_face_mesh(
99
99
  else:
100
100
  face_mesh = face_mesh_obj
101
101
 
102
- # Prepare image
103
- img_copy = image._data.copy()
104
- img_rgb = cv2.cvtColor(img_copy, cv2.COLOR_BGR2RGB)
105
-
106
- # Detect facial landmarks
102
+ # Detect facial landmarks (cvtColor allocates a new RGB array)
103
+ img_rgb = cv2.cvtColor(image._data, cv2.COLOR_BGR2RGB)
107
104
  results = face_mesh.process(img_rgb)
108
105
 
109
106
  # Handle no detections
@@ -121,11 +118,14 @@ def analyze_face_mesh(
121
118
  }
122
119
  )
123
120
 
121
+ # Allocate the annotation canvas only when a face was found
122
+ img_copy = image._data.copy()
123
+
124
124
  # Use all landmarks if none specified
125
125
  landmarks_idx = landmarks_idx or list(range(TOTAL_FACE_LANDMARKS))
126
126
  # Process each detected face
127
127
  landmarks = []
128
-
128
+
129
129
  for face_id, face_landmarks in enumerate(results.multi_face_landmarks):
130
130
  # Draw landmarks
131
131
  if len(landmarks_idx) == TOTAL_FACE_LANDMARKS:
@@ -146,11 +146,10 @@ def analyze_face_mesh(
146
146
  cv2.circle(img_copy, (cx, cy), 3, (0, 0, 255), -1)
147
147
 
148
148
  # Extract coordinates
149
- face_data = [
150
- [face_id, idx, lm.x, lm.y, lm.z]
151
- for idx in landmarks_idx
152
- for lm in [face_landmarks.landmark[idx]]
153
- ]
149
+ face_data = []
150
+ for idx in landmarks_idx:
151
+ lm = face_landmarks.landmark[idx]
152
+ face_data.append([face_id, idx, lm.x, lm.y, lm.z])
154
153
  landmarks.append(face_data)
155
154
 
156
155
  return Result(
@@ -97,7 +97,7 @@ def estimate_head_pose(
97
97
  for face in landmarks:
98
98
  # Map landmarks by index
99
99
  points = {lm[1]: lm for lm in face}
100
-
100
+
101
101
  try:
102
102
  # Extract key points
103
103
  nose_x, nose_y = points[1][2:4] # Nose tip
@@ -1,6 +1,9 @@
1
1
  # Object Analysis Module
2
2
  # Provides object detection capabilities using YOLO models
3
3
 
4
- from . import object_detection
4
+ try: # object_detection needs the optional ultralytics dependency
5
+ from . import object_detection
6
+ except ImportError:
7
+ object_detection = None
5
8
 
6
9
  __all__ = ["object_detection"]
@@ -16,10 +16,9 @@ from ImagePRO.utils.result import Result
16
16
 
17
17
  # Constants
18
18
  DEFAULT_ACCURACY_LEVEL = 1
19
- DEFAULT_CONFIDENCE = 0.5
20
19
  MODEL_MAPPING = {
21
20
  1: "yolo11n.pt",
22
- 2: "yolo11s.pt",
21
+ 2: "yolo11s.pt",
23
22
  3: "yolo11m.pt",
24
23
  4: "yolo11l.pt",
25
24
  5: "yolo11x.pt"
@@ -56,6 +55,7 @@ def detect_objects(
56
55
  Result object with detections and metadata:
57
56
  - image: Original with bounding boxes drawn
58
57
  - data: List of [class_id, [x1,y1,x2,y2], confidence]
58
+ with box coordinates normalized to [0, 1]
59
59
  - meta: Operation info and model used
60
60
 
61
61
  Raises:
@@ -73,12 +73,12 @@ def detect_objects(
73
73
  f"'accuracy_level' must be in {list(MODEL_MAPPING.keys())}, "
74
74
  f"got {accuracy_level}"
75
75
  )
76
-
76
+
77
77
  model_name = MODEL_MAPPING[accuracy_level]
78
78
  model = YOLO(model=model_name)
79
79
 
80
- # Run inference
81
- result = model(image._data.copy())[0]
80
+ # Run inference (ultralytics does not mutate the input array)
81
+ result = model(image._data)[0]
82
82
  boxes = result.boxes
83
83
 
84
84
  # Process detections
@@ -92,7 +92,7 @@ def detect_objects(
92
92
  # Show visualization if requested
93
93
  if show_result:
94
94
  result.show()
95
-
95
+
96
96
  return Result(
97
97
  image=result.plot(),
98
98
  data=detections,
@@ -4,15 +4,19 @@
4
4
  from . import blur
5
5
  from . import contrast
6
6
  from . import crop
7
- from . import dataset_generator
8
7
  from . import grayscale
9
8
  from . import resize
10
9
  from . import rotate
11
10
  from . import sharpen
12
11
 
12
+ try: # dataset_generator needs the optional mediapipe dependency
13
+ from . import dataset_generator
14
+ except ImportError:
15
+ dataset_generator = None
16
+
13
17
  __all__ = [
14
18
  "blur",
15
- "contrast",
19
+ "contrast",
16
20
  "crop",
17
21
  "dataset_generator",
18
22
  "grayscale",
@@ -60,9 +60,9 @@ def apply_average_blur(
60
60
  ):
61
61
  raise ValueError("'kernel_size' must be a tuple of two positive integers.")
62
62
 
63
- # Apply box filter blur
64
- blurred = cv2.blur(image._data.copy(), kernel_size)
65
-
63
+ # Apply box filter blur (cv2.blur never mutates its input)
64
+ blurred = cv2.blur(image._data, kernel_size)
65
+
66
66
  return Result(
67
67
  image=blurred,
68
68
  meta={
@@ -112,8 +112,8 @@ def apply_gaussian_blur(
112
112
  raise ValueError("'kernel_size' must be a tuple of two odd positive integers.")
113
113
 
114
114
  # Apply Gaussian blur with automatic sigma calculation
115
- blurred = cv2.GaussianBlur(image._data.copy(), kernel_size, 0)
116
-
115
+ blurred = cv2.GaussianBlur(image._data, kernel_size, 0)
116
+
117
117
  return Result(
118
118
  image=blurred,
119
119
  meta={
@@ -160,8 +160,8 @@ def apply_median_blur(
160
160
  raise ValueError("'filter_size' must be an odd integer greater than 1.")
161
161
 
162
162
  # Apply median filtering
163
- blurred = cv2.medianBlur(image._data.copy(), filter_size)
164
-
163
+ blurred = cv2.medianBlur(image._data, filter_size)
164
+
165
165
  return Result(
166
166
  image=blurred,
167
167
  meta={
@@ -203,7 +203,7 @@ def apply_bilateral_blur(
203
203
  Result: Result object with smoothed image.
204
204
  - image (np.ndarray): Edge-preserving smoothed output
205
205
  - data (None): No additional data
206
- - meta (dict): Contains filter *,parameters and operation info
206
+ - meta (dict): Contains filter parameters and operation info
207
207
 
208
208
  Raises:
209
209
  TypeError: If image is not an Image instance
@@ -221,12 +221,12 @@ def apply_bilateral_blur(
221
221
 
222
222
  # Apply bilateral filter
223
223
  blurred = cv2.bilateralFilter(
224
- image._data.copy(),
224
+ image._data,
225
225
  filter_size,
226
226
  sigma_color,
227
227
  sigma_space
228
228
  )
229
-
229
+
230
230
  return Result(
231
231
  image=blurred,
232
232
  meta={
@@ -13,14 +13,11 @@ import cv2
13
13
 
14
14
  from ImagePRO.utils.image import Image
15
15
  from ImagePRO.utils.result import Result
16
- from ImagePRO.pre_processing.grayscale import convert_to_grayscale
17
16
 
18
17
 
19
18
  # Constants for contrast enhancement
20
19
  DEFAULT_CLIP_LIMIT = 2.0 # For CLAHE
21
20
  DEFAULT_TILE_GRID_SIZE = (8, 8) # For CLAHE
22
- DEFAULT_ALPHA = 1.5 # For linear stretching
23
- DEFAULT_BETA = 10 # For linear stretching
24
21
 
25
22
 
26
23
  def apply_clahe_contrast(
@@ -65,8 +62,8 @@ def apply_clahe_contrast(
65
62
  ):
66
63
  raise TypeError("'tile_grid_size' must be a tuple of two positive integers")
67
64
 
68
- # Convert and apply CLAHE
69
- grayscale = convert_to_grayscale(image=Image.from_array(image._data.copy()))
65
+ # Convert and apply CLAHE (cvtColor returns a new array; input untouched)
66
+ grayscale = cv2.cvtColor(image._data, cv2.COLOR_BGR2GRAY)
70
67
  clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=tile_grid_size)
71
68
  enhanced = clahe.apply(grayscale)
72
69
 
@@ -105,7 +102,7 @@ def apply_histogram_equalization(
105
102
  raise TypeError("'image' must be an Image instance")
106
103
 
107
104
  # Convert and apply global histogram equalization
108
- grayscale = convert_to_grayscale(image=Image.from_array(image._data.copy()))
105
+ grayscale = cv2.cvtColor(image._data, cv2.COLOR_BGR2GRAY)
109
106
  enhanced = cv2.equalizeHist(grayscale)
110
107
 
111
108
  return Result(
@@ -156,7 +153,7 @@ def apply_contrast_stretching(
156
153
  raise ValueError("'beta' must be an integer between 0 and 255")
157
154
 
158
155
  # Convert and apply linear stretching
159
- grayscale = convert_to_grayscale(image=Image.from_array(image._data.copy()))
156
+ grayscale = cv2.cvtColor(image._data, cv2.COLOR_BGR2GRAY)
160
157
  enhanced = cv2.convertScaleAbs(grayscale, alpha=alpha, beta=beta)
161
158
 
162
159
  return Result(
@@ -12,10 +12,6 @@ if str(_src_path) not in sys.path:
12
12
  from ImagePRO.utils.image import Image
13
13
  from ImagePRO.utils.result import Result
14
14
 
15
- # Constants
16
- DEFAULT_START_POINT = (0, 0)
17
- DEFAULT_END_POINT = (100, 100)
18
-
19
15
 
20
16
  def crop_image(
21
17
  image: Image,
@@ -59,7 +55,10 @@ def crop_image(
59
55
  x2, y2 = end_point
60
56
 
61
57
  if x1 < 0 or y1 < 0 or x2 <= x1 or y2 <= y1:
62
- raise ValueError("Invalid crop coordinates: ensure (x1, y1) is top-left and (x2, y2) is bottom-right")
58
+ raise ValueError(
59
+ "Invalid crop coordinates: ensure (x1, y1) is top-left "
60
+ "and (x2, y2) is bottom-right"
61
+ )
63
62
 
64
63
  height, width = image.shape[:2]
65
64
 
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import random
3
4
  import sys
5
+ import time
4
6
  from pathlib import Path
5
7
 
6
8
  # Add src directory to path for absolute imports
@@ -9,16 +11,13 @@ _src_path = _file_path.parents[2] # Go up to src directory
9
11
  if str(_src_path) not in sys.path:
10
12
  sys.path.insert(0, str(_src_path))
11
13
 
12
- from ImagePRO.human_analysis.face_analysis.face_detection import detect_faces
13
- from ImagePRO.pre_processing import blur, grayscale, rotate, sharpen, resize
14
- from ImagePRO.utils.image import Image
15
-
16
- import random
17
- import time
18
-
19
14
  import cv2
20
15
  import mediapipe as mp
21
16
 
17
+ from ImagePRO.human_analysis.face_analysis.face_detection import detect_faces
18
+ from ImagePRO.pre_processing import blur, grayscale, resize, rotate, sharpen
19
+ from ImagePRO.utils.image import Image
20
+
22
21
  # Constants
23
22
  DEFAULT_NUM_IMAGES = 200
24
23
  DEFAULT_START_INDEX = 0
@@ -40,7 +39,7 @@ def capture_bulk_pictures(
40
39
  apply_grayscale: bool = False,
41
40
  apply_sharpen: bool = False,
42
41
  apply_rotate: bool = False,
43
- apply_resize: tuple = False,
42
+ apply_resize: tuple[int, int] | bool = False,
44
43
  delay: float = DEFAULT_DELAY
45
44
  ) -> None:
46
45
  """Generate a dataset by capturing faces from webcam.
@@ -50,7 +49,7 @@ def capture_bulk_pictures(
50
49
  face recognition datasets with data augmentation.
51
50
 
52
51
  Processing pipeline (if enabled):
53
- average blur → laplacian sharpen → grayscale → resize → random rotate
52
+ median blur → laplacian sharpen → grayscale → resize → random rotate
54
53
 
55
54
  Args:
56
55
  folder_path: Base directory for dataset.
@@ -135,7 +134,7 @@ def capture_bulk_pictures(
135
134
 
136
135
  if apply_blur:
137
136
  # Reduce noise while preserving facial features
138
- processed = blur.apply_average_blur(
137
+ processed = blur.apply_median_blur(
139
138
  image=Image.from_array(processed),
140
139
  filter_size=3
141
140
  ).image
@@ -15,73 +15,61 @@ import matplotlib.pyplot as plt
15
15
  from ImagePRO.utils.image import Image
16
16
  from ImagePRO.utils.result import Result
17
17
 
18
+
18
19
  def show_histogram(image: Image) -> Result:
19
20
  """
20
- Displays the histogram of an image with customizable options.
21
-
22
- This function visualizes the intensity distribution of an image. It handles both grayscale
23
- and color images, with automatic detection of image type. For color images, it displays
24
- histograms for each color channel (BGR or RGB) with appropriate colors.
21
+ Builds a matplotlib histogram figure for an image.
22
+
23
+ This function creates the histogram plot of the intensity distribution of
24
+ an image. It handles both grayscale and color images, with automatic
25
+ detection of image type. For color images, it plots a histogram for each
26
+ color channel (BGR or RGB) with appropriate colors. The pyplot module is
27
+ returned in ``data``; call ``matplotlib.pyplot.show()`` to display the
28
+ figure.
25
29
 
26
30
  Args:
27
31
  image (Image):
28
- Input image to convert. Must be BGR, RGB or Grayscale format.
32
+ Input image to analyze. Must be BGR, RGB or Grayscale format.
29
33
 
30
34
  Returns:
31
35
  Result: Result object with histogram plot.
32
- - image (np.ndarray): None
33
- - data (None): matplotlib.pyplot object
36
+ - image: None
37
+ - data: The matplotlib.pyplot module (figure is created, not shown)
34
38
  - meta (dict): Contains source object and operation info
35
39
 
36
40
  Raises:
37
41
  TypeError: If image is not an Image instance
38
- ValueError: If image colorspace is not defined.
42
+ ValueError: If image colorspace is not supported.
39
43
  """
40
44
  if not isinstance(image, Image):
41
45
  raise TypeError("'image' must be an Image instance.")
42
46
 
43
- if image.colorspace == "BGR":
44
- colors = ('blue', 'green', 'red')
45
- plt.figure(figsize=(10, 6))
47
+ if image.colorspace in ("BGR", "RGB"):
48
+ if image.colorspace == "BGR":
49
+ colors = ("blue", "green", "red")
50
+ labels = ("Blue Channel", "Green Channel", "Red Channel")
51
+ else:
52
+ colors = ("red", "green", "blue")
53
+ labels = ("Red Channel", "Green Channel", "Blue Channel")
54
+ channels = list(enumerate(colors))
55
+ elif image.colorspace == "GRAY":
56
+ channels = [(0, "black")]
57
+ labels = None
58
+ else:
59
+ raise ValueError(f"Unknown colorspace: {image.colorspace}")
46
60
 
47
- for i, color in enumerate(colors):
48
- hist = cv2.calcHist([image._data], [i], None, [256], [0, 256])
49
- plt.plot(hist, color=color)
50
- plt.xlim([0, 256])
51
-
52
-
53
- plt.title('Histogram of BGR Channels')
54
- plt.xlabel('Pixel Intensity')
55
- plt.ylabel('Frequency')
56
- plt.legend(['Blue Channel', 'Green Channel', 'Red Channel'])
57
-
58
-
59
- elif image.colorspace == "RGB":
60
- colors = ('red', 'green', 'blue')
61
- plt.figure(figsize=(10, 6))
61
+ plt.figure(figsize=(10, 6))
62
+ for channel, color in channels:
63
+ hist = cv2.calcHist([image._data], [channel], None, [256], [0, 256])
64
+ plt.plot(hist, color=color)
62
65
 
63
- for i, color in enumerate(colors):
64
- hist = cv2.calcHist([image._data], [i], None, [256], [0, 256])
65
- plt.plot(hist, color=color)
66
- plt.xlim([0, 256])
67
-
68
-
69
- plt.title('Histogram of RGB Channels')
70
- plt.xlabel('Pixel Intensity')
71
- plt.ylabel('Frequency')
72
- plt.legend(['Red Channel', 'Green Channel', 'Blue Channel'])
73
-
74
-
75
- elif image.colorspace == 'GRAY':
76
- plt.figure(figsize=(10, 6))
66
+ if labels is not None:
67
+ plt.title(f"Histogram of {image.colorspace} Channels")
68
+ plt.legend(labels)
69
+ plt.xlabel("Pixel Intensity")
70
+ plt.ylabel("Frequency")
77
71
 
78
- hist = cv2.calcHist([image._data], [0], None, [256], [0, 256])
79
- plt.plot(hist, color='black')
80
- plt.xlim([0, 256])
81
-
82
- else:
83
- return ValueError('Unknown colorspace')
84
-
72
+ plt.xlim([0, 256])
85
73
 
86
74
  return Result(
87
75
  image=None,
@@ -22,7 +22,7 @@ def resize_image(
22
22
  ) -> Result:
23
23
  """Resize an image to specified dimensions.
24
24
 
25
- Changes image size while maintaining aspect ratio.
25
+ Changes image size to the exact (width, height) given.
26
26
  Uses bilinear interpolation for smooth resizing.
27
27
 
28
28
  Args:
@@ -52,7 +52,7 @@ def resize_image(
52
52
 
53
53
  # Resize using bilinear interpolation
54
54
  resized = cv2.resize(image._data, new_size, interpolation=cv2.INTER_LINEAR)
55
-
55
+
56
56
  return Result(
57
57
  image=resized,
58
58
  meta={
@@ -10,7 +10,6 @@ if str(_src_path) not in sys.path:
10
10
  sys.path.insert(0, str(_src_path))
11
11
 
12
12
  import cv2
13
- import numpy as np
14
13
 
15
14
  from ImagePRO.utils.image import Image
16
15
  from ImagePRO.utils.result import Result
@@ -18,7 +17,6 @@ from ImagePRO.utils.result import Result
18
17
 
19
18
  # Constants for rotation operations
20
19
  DEFAULT_SCALE = 1.0
21
- DEFAULT_ANGLE = 45.0
22
20
 
23
21
 
24
22
  def rotate_image_90(image: Image) -> Result:
@@ -39,7 +37,7 @@ def rotate_image_90(image: Image) -> Result:
39
37
  if not isinstance(image, Image):
40
38
  raise TypeError("'image' must be an Image instance")
41
39
 
42
- rotated = cv2.rotate(image._data.copy(), cv2.ROTATE_90_CLOCKWISE)
40
+ rotated = cv2.rotate(image._data, cv2.ROTATE_90_CLOCKWISE)
43
41
  return Result(
44
42
  image=rotated,
45
43
  meta={
@@ -68,7 +66,7 @@ def rotate_image_180(image: Image) -> Result:
68
66
  if not isinstance(image, Image):
69
67
  raise TypeError("'image' must be an Image instance")
70
68
 
71
- rotated = cv2.rotate(image._data.copy(), cv2.ROTATE_180)
69
+ rotated = cv2.rotate(image._data, cv2.ROTATE_180)
72
70
  return Result(
73
71
  image=rotated,
74
72
  meta={
@@ -97,7 +95,7 @@ def rotate_image_270(image: Image) -> Result:
97
95
  if not isinstance(image, Image):
98
96
  raise TypeError("'image' must be an Image instance")
99
97
 
100
- rotated = cv2.rotate(image._data.copy(), cv2.ROTATE_90_COUNTERCLOCKWISE)
98
+ rotated = cv2.rotate(image._data, cv2.ROTATE_90_COUNTERCLOCKWISE)
101
99
  return Result(
102
100
  image=rotated,
103
101
  meta={
@@ -117,7 +115,8 @@ def rotate_image_custom(
117
115
  """Rotate image by custom angle with optional scaling.
118
116
 
119
117
  Rotates around image center. Positive angles are counter-clockwise.
120
- Image is resized to contain full rotated content.
118
+ The output canvas keeps the original image dimensions, so corners of
119
+ the rotated image may be clipped.
121
120
 
122
121
  Args:
123
122
  image: Input image to rotate.
@@ -144,7 +143,7 @@ def rotate_image_custom(
144
143
 
145
144
  h, w = image.shape[:2]
146
145
  matrix = cv2.getRotationMatrix2D((w/2, h/2), angle, scale)
147
- rotated = cv2.warpAffine(image._data.copy(), matrix, (w, h))
146
+ rotated = cv2.warpAffine(image._data, matrix, (w, h))
148
147
 
149
148
  return Result(
150
149
  image=rotated,
@@ -14,7 +14,7 @@ import numpy as np
14
14
 
15
15
  from ImagePRO.utils.image import Image
16
16
  from ImagePRO.utils.result import Result
17
- from ImagePRO.pre_processing.blur import apply_average_blur
17
+ from ImagePRO.pre_processing.blur import DEFAULT_KERNEL_SIZE
18
18
 
19
19
  # Constants
20
20
  DEFAULT_LAPLACIAN_COEFFICIENT = 3.0
@@ -52,13 +52,16 @@ def apply_laplacian_sharpening(
52
52
  if not isinstance(coefficient, (int, float)) or coefficient < 0:
53
53
  raise ValueError("'coefficient' must be a non-negative number")
54
54
 
55
- # Apply Laplacian edge detection
56
- laplacian = cv2.Laplacian(image._data.copy(), cv2.CV_64F)
57
- laplacian = np.uint8(np.absolute(laplacian))
55
+ # Apply Laplacian edge detection, then enhance edges while keeping
56
+ # float arithmetic identical to: image + coefficient * |laplacian|
57
+ laplacian = cv2.Laplacian(image._data, cv2.CV_64F)
58
+ np.absolute(laplacian, out=laplacian)
59
+ laplacian = laplacian.astype(np.uint8)
58
60
 
59
- # Enhance edges
60
- sharpened = image._data + coefficient * laplacian
61
- sharpened = np.uint8(np.clip(sharpened, 0, 255))
61
+ sharpened = laplacian * coefficient
62
+ sharpened += image._data
63
+ np.clip(sharpened, 0, 255, out=sharpened)
64
+ sharpened = sharpened.astype(np.uint8)
62
65
 
63
66
  return Result(
64
67
  image=sharpened,
@@ -102,15 +105,15 @@ def apply_unsharp_masking(
102
105
  raise ValueError("'coefficient' must be a non-negative number")
103
106
 
104
107
  # Create the mask from original vs blurred difference
105
- blurred = apply_average_blur(image=Image.from_array(image._data.copy()))
108
+ blurred = cv2.blur(image._data, DEFAULT_KERNEL_SIZE)
106
109
  mask = cv2.subtract(image._data, blurred)
107
-
110
+
108
111
  # Apply unsharp masking
109
112
  sharpened = cv2.addWeighted(
110
- image._data,
111
- 1 + coefficient,
112
- mask,
113
- -coefficient,
113
+ image._data,
114
+ 1 + coefficient,
115
+ mask,
116
+ -coefficient,
114
117
  0
115
118
  )
116
119
 
ImagePRO/utils/image.py CHANGED
@@ -18,8 +18,9 @@ class Image:
18
18
  """
19
19
  Lightweight, immutable image wrapper for ImagePRO.
20
20
 
21
- Use factory constructors to create instances. All methods return new Image objects.
22
- Images are handled in BGR format by default to match OpenCV conventions.
21
+ Use factory constructors to create instances; instances are lightweight
22
+ wrappers and are not modified by ImagePRO operations. Images are handled
23
+ in BGR format by default to match OpenCV conventions.
23
24
 
24
25
  Attributes:
25
26
  _data (np.ndarray):
@@ -35,7 +36,7 @@ class Image:
35
36
  >>> # Load from file (default BGR)
36
37
  >>> img = Image.from_path('input.jpg', colorspace="BGR")
37
38
  >>> print(img.shape) # (H, W, 3)
38
- >>>
39
+ >>>
39
40
  >>> # Or wrap a NumPy array
40
41
  >>> img = Image.from_array(np_array, colorspace="RGB")
41
42
  """
@@ -47,7 +48,7 @@ class Image:
47
48
 
48
49
  @classmethod
49
50
  def from_path(
50
- cls,
51
+ cls,
51
52
  path: str | Path,
52
53
  colorspace: Colorspace = "BGR"
53
54
  ) -> Image:
@@ -58,7 +59,8 @@ class Image:
58
59
  path (str | Path):
59
60
  Path to the image file.
60
61
  colorspace (Colorspace, optional):
61
- Colorspace of the image array in that path ("BGR", "RGB", or "GRAY"). Defaults to "BGR".
62
+ Colorspace of the image array in that path
63
+ ("BGR", "RGB", or "GRAY"). Defaults to "BGR".
62
64
 
63
65
  Returns:
64
66
  Image: New Image instance loaded from disk.
@@ -124,4 +126,3 @@ class Image:
124
126
  np.dtype: Data type of the image array.
125
127
  """
126
128
  return self._data.dtype
127
-
ImagePRO/utils/result.py CHANGED
@@ -143,22 +143,25 @@ class Result:
143
143
  raise IOError(f"Failed to write CSV to {out_path}: {exc}") from exc
144
144
  return self
145
145
 
146
- def flatten_rows(data):
146
+
147
+ def flatten_rows(data: Any) -> list[list[Any]]:
147
148
  """
148
149
  Flatten nested lists/tuples into rows suitable for CSV writing.
149
-
150
+
150
151
  Recursively processes nested data structures to create a flat list of rows
151
152
  that can be written to a CSV file. Handles mixed nesting levels gracefully.
152
-
153
+
153
154
  Args:
154
155
  data: Nested list/tuple structure containing data to flatten.
155
-
156
+
156
157
  Returns:
157
158
  list[list[Any]]: Flattened list of rows, where each row is a list of values.
158
-
159
+
159
160
  Example:
160
- >>> flatten_rows([[1, 2], [3, [4, 5]]])
161
- [[1, 2], [3, 4, 5]]
161
+ >>> flatten_rows([[1, 2], [3, 4]])
162
+ [[1, 2], [3, 4]]
163
+ >>> flatten_rows([[[1, 2], [3, 4]], [5]])
164
+ [[1, 2], [3, 4], [5]]
162
165
  """
163
166
  rows = []
164
167
  for item in data:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ImagePRO-Python
3
- Version: 1.2.1
3
+ Version: 1.3.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
@@ -32,14 +32,19 @@ Provides-Extra: yolo
32
32
  Requires-Dist: ultralytics<9.0,>=8.2; extra == "yolo"
33
33
  Provides-Extra: mediapipe
34
34
  Requires-Dist: mediapipe<=0.10.11,>=0.10.0; extra == "mediapipe"
35
+ Requires-Dist: numpy<2.0,>=1.24; extra == "mediapipe"
35
36
  Provides-Extra: insightface
36
37
  Requires-Dist: insightface<0.8,>=0.7; extra == "insightface"
37
38
  Requires-Dist: onnxruntime<2.0,>=1.16; extra == "insightface"
39
+ Requires-Dist: numpy<2.0,>=1.24; extra == "insightface"
38
40
  Provides-Extra: full
39
41
  Requires-Dist: mediapipe<=0.10.11,>=0.10.0; extra == "full"
40
42
  Requires-Dist: ultralytics<9.0,>=8.2; extra == "full"
41
43
  Requires-Dist: insightface<0.8,>=0.7; extra == "full"
42
44
  Requires-Dist: onnxruntime<2.0,>=1.16; extra == "full"
45
+ Requires-Dist: numpy<2.0,>=1.24; extra == "full"
46
+ Provides-Extra: dev
47
+ Requires-Dist: pytest<9.0,>=8.0; extra == "dev"
43
48
  Dynamic: license-file
44
49
 
45
50
  # ImagePRO
@@ -50,11 +55,10 @@ Dynamic: license-file
50
55
 
51
56
  Whether you're working on computer vision pipelines, preprocessing images for AI models, or simply automating batch image edits — **ImagePRO** gives you powerful tools with minimal effort.
52
57
 
53
- ## ✨ Features
58
+ ## Features
54
59
 
55
60
  ### **Image I/O & Management**
56
61
  - Flexible input/output handling (file paths or numpy arrays)
57
- - Batch processing capabilities
58
62
  - Multiple format support (JPEG, PNG, CSV, etc.)
59
63
 
60
64
  ### **Pre-processing & Enhancement**
@@ -71,13 +75,19 @@ Whether you're working on computer vision pipelines, preprocessing images for AI
71
75
  ### **Object Detection**
72
76
  - **YOLO Integration**: Multiple accuracy levels (nano to extra-large)
73
77
  - **Flexible Models**: Pre-trained or custom model support
74
- - **Batch Processing**: Efficient handling of multiple images
75
78
 
76
- ## 🚀 Installation
79
+ ## Installation
77
80
 
78
81
  ### From PyPI
79
82
  ```bash
80
83
  pip install ImagePRO-Python
84
+
85
+ # Or with optional extras:
86
+ pip install "ImagePRO-Python[yolo]" # YOLO object detection
87
+ pip install "ImagePRO-Python[mediapipe]" # MediaPipe human analysis
88
+ pip install "ImagePRO-Python[insightface]" # InsightFace face comparison
89
+ pip install "ImagePRO-Python[full]" # Everything
90
+ pip install "ImagePRO-Python[dev]" # Test tooling (pytest)
81
91
  ```
82
92
 
83
93
  ### From Source
@@ -109,7 +119,7 @@ pip install -r requirements/full.txt
109
119
 
110
120
  See the [Directory Structure](/PROJECT_STRUCTURE.md#directory-structure) section in [PROJECT_STRUCTURE.md](/PROJECT_STRUCTURE.md) for details on which modules need which requirements.
111
121
 
112
- ## 📖 Quick Start
122
+ ## Quick Start
113
123
 
114
124
  ```python
115
125
  from ImagePRO.pre_processing.blur import apply_average_blur
@@ -126,9 +136,9 @@ image = Image.from_path("person_and_objects.jpg")
126
136
  blur_result = apply_average_blur(image=image)
127
137
  blur_result.save_as_img("blurred_output.jpg")
128
138
 
129
- # Analyze face mesh (468 landmarks)
139
+ # Analyze face mesh (468 landmarks per detected face)
130
140
  face_mesh_result = analyze_face_mesh(image=image)
131
- print(f"Detected {len(face_mesh_result.data)} face landmarks")
141
+ print(f"Detected {len(face_mesh_result.data)} face(s)")
132
142
  face_mesh_result.save_as_csv("face_landmarks.csv")
133
143
 
134
144
  # Detect body pose (33 landmarks)
@@ -138,8 +148,7 @@ print(f"Body pose data: {body_pose_result.data}")
138
148
  # Detect objects with YOLO
139
149
  object_detection_result = detect_objects(
140
150
  image=image,
141
- accuracy_level=3, # 1=nano, 2=small, 3=medium, 4=large, 5=extra-large
142
- confidence=0.5
151
+ accuracy_level=3 # 1=nano, 2=small, 3=medium, 4=large, 5=extra-large
143
152
  )
144
153
  print(f"Detected {len(object_detection_result.data)} objects")
145
154
  object_detection_result.save_as_img("detections.jpg")
@@ -147,7 +156,7 @@ object_detection_result.save_as_img("detections.jpg")
147
156
 
148
157
  > **Note**: These are basic examples. Each module contains many more functions with extensive customization options. Explore the module-specific README files for detailed documentation.
149
158
 
150
- ## 📚 Documentation
159
+ ## Documentation
151
160
 
152
161
  Each module includes comprehensive documentation with detailed examples:
153
162
 
@@ -160,7 +169,7 @@ Each module includes comprehensive documentation with detailed examples:
160
169
 
161
170
  For detailed project structure and development guidelines, see [PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md).
162
171
 
163
- ## 🏗️ Architecture
172
+ ## Architecture
164
173
 
165
174
  ImagePRO is built with a modular architecture designed for extensibility and maintainability:
166
175
 
@@ -172,12 +181,27 @@ ImagePRO is built with a modular architecture designed for extensibility and mai
172
181
  - **Documentation**: Google-style docstrings for all functions
173
182
 
174
183
  ### Key Design Principles
175
- - **Immutable Design**: Image objects are immutable, operations return new instances
184
+ - **Non-Destructive Operations**: Operations never write into the input image; they return results in new `Result` objects (note: `crop_image` returns a view into the source array)
176
185
  - **Functional Style**: Stateless functions that can be easily composed
177
186
  - **Result Objects**: Unified return type containing image, data, and metadata
178
187
  - **Keyword Arguments**: All optional parameters use keyword-only syntax
179
188
 
180
- ## 🤝 Contributing
189
+ ## Testing
190
+
191
+ The test suite uses pytest:
192
+
193
+ ```bash
194
+ # Install with test tooling (editable install + dev extra)
195
+ pip install -e ".[dev]"
196
+
197
+ # Run the suite (optional heavy dependencies are mocked; base deps are enough)
198
+ pytest
199
+
200
+ # Include performance smoke guards
201
+ pytest --run-performance
202
+ ```
203
+
204
+ ## Contributing
181
205
 
182
206
  Contributions are welcome! Please feel free to submit a Pull Request.
183
207
 
@@ -185,9 +209,10 @@ Contributions are welcome! Please feel free to submit a Pull Request.
185
209
  1. Fork the repository
186
210
  2. Create a virtual environment: `python -m venv .venv`
187
211
  3. Install dependencies: `pip install -r requirements/full.txt`
188
- 4. Follow the coding standards outlined in [PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md)
189
- 5. Add tests for new features
190
- 6. Update documentation as needed
212
+ 4. Install for development with test tooling: `pip install -e ".[dev]"`
213
+ 5. Follow the coding standards outlined in [PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md)
214
+ 6. Add tests for new features and run `pytest`
215
+ 7. Update documentation as needed
191
216
 
192
217
  ### Reporting Issues
193
218
  If you encounter any bugs or have feature requests, please open an issue on the GitHub repository with:
@@ -196,5 +221,5 @@ If you encounter any bugs or have feature requests, please open an issue on the
196
221
  - Expected vs. actual behavior
197
222
  - Environment details (OS, Python version, etc.)
198
223
 
199
- ## 📄 License
224
+ ## License
200
225
  This project is licensed under the MIT License – see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,31 @@
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (82.0.0)
2
+ Generator: setuptools (84.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,31 +0,0 @@
1
- ImagePRO/__init__.py,sha256=LUqZaUWVUISpR6bm5K2cO6KjiVP3ZDPADZGZW051xGk,998
2
- ImagePRO/human_analysis/__init__.py,sha256=uSU0lM1p1HM6TNGv6u0nPHWy9QY505v43lqTkhClddM,190
3
- ImagePRO/human_analysis/body_analysis/__init__.py,sha256=czQoJJIrDAWz0UUY0h0mwxymSQ6L6CaZYYHhYFHyf4U,203
4
- ImagePRO/human_analysis/body_analysis/body_pose_estimation.py,sha256=69ybYkrbFl9EkuAc4ejCu2TW4m9TFLTn2Ae5fm_92lE,5549
5
- ImagePRO/human_analysis/body_analysis/hand_tracking.py,sha256=T7yM_VZN6mBZsDFJV6C-amCVzgklatvsZrtgcBrzVSg,6869
6
- ImagePRO/human_analysis/face_analysis/__init__.py,sha256=dKVZ6pq-0aQHL9vhMSt0BHs3WV_cTW65QPLJGnSiUgM,405
7
- ImagePRO/human_analysis/face_analysis/eye_status_analysis.py,sha256=9ydxEj4EhVCNf954gdFBQemS1uRNA-XGCMzyliI2AsQ,7126
8
- ImagePRO/human_analysis/face_analysis/face_comparison.py,sha256=RU-eSjFwpRIrV-QX8po8Mr-RhGwYEsCo3_Nt-IiA5Us,4315
9
- ImagePRO/human_analysis/face_analysis/face_detection.py,sha256=__s-lI6Egf-JgruncL_MfAkmwCq8Oe3F5Vvk9x9S_2Q,3897
10
- ImagePRO/human_analysis/face_analysis/face_mesh_analysis.py,sha256=8kLyEEnhMfdEALteltSHu2L2zbiFSNfzC73EuV0I5iQ,7964
11
- ImagePRO/human_analysis/face_analysis/head_pose_estimation.py,sha256=IidB4U0lQryw9T4J4_T-QmC-DgANUEgueto06RkKi2Q,7336
12
- ImagePRO/object_analysis/__init__.py,sha256=pj1vjY8uVUqeVONpaCacWufUzHF7rS5-nmy_C5IfI2w,148
13
- ImagePRO/object_analysis/object_detection.py,sha256=ZhxOpX5Zkiu-gq-2CRYPNzSo7ai1PRFZ3qopQeODIkQ,2890
14
- ImagePRO/pre_processing/__init__.py,sha256=nXUhE8RnDyW7T93fKsSDPfqzGHIW50OvgQvznY5UH0E,417
15
- ImagePRO/pre_processing/blur.py,sha256=zPWUKLEoKiL6kYwnZOtGRWBHM-dgEQ8WWdDt8_wGc0s,7961
16
- ImagePRO/pre_processing/contrast.py,sha256=XG69VsX3EKWIPDcQYm4D9qT7sA_BSP-sppSAa8qRUhA,5247
17
- ImagePRO/pre_processing/crop.py,sha256=p0esuZcn4-YsqcniDUmsVfPoWasxVH1OqzNBra8Pw4M,2442
18
- ImagePRO/pre_processing/dataset_generator.py,sha256=ekd_TnyflWKjJ6sYCiWc3vN2Q14cKiwZ1InOCslxoFM,7653
19
- ImagePRO/pre_processing/grayscale.py,sha256=MRCsFRIaL45sYVHzhuNyZBXsP7PF-yorn0Wt7xONvpY,1781
20
- ImagePRO/pre_processing/histogram.py,sha256=t1ykGUwB9ZbvO6J3bGPh4fDvrk4AJua1dN2BWzHIRIQ,2888
21
- ImagePRO/pre_processing/resize.py,sha256=GH3ObPe67ypPQG3a7ncrNR5WNDqGibXebAiuRXr6L10,1760
22
- ImagePRO/pre_processing/rotate.py,sha256=wqV2Qm7mIyvKTSFdwzr1tNAGnMG7rl5M3BRqC5m2oZE,4185
23
- ImagePRO/pre_processing/sharpen.py,sha256=C5AOxQNBL80JenkztlyRBV7yuCHqxG5dTGbRhtVRT9M,3544
24
- ImagePRO/utils/__init__.py,sha256=McVd-o9KtKOpAVYbLi19KxsatPPFFF-Qbt0gdgY3Ln8,170
25
- ImagePRO/utils/image.py,sha256=x93cBNycNOgET20a__TxZ9ZQo_2G84uB7QjXjBo9f8M,3973
26
- ImagePRO/utils/result.py,sha256=rGZX0FJ-dpA4v_m_GUO6ni0kCfcNJRnOjztbyRX9d88,6065
27
- imagepro_python-1.2.1.dist-info/licenses/LICENSE,sha256=sehkHN7dbe5umrINZJyJjIf9VTemZSgTfJlq6iIsbJQ,1069
28
- imagepro_python-1.2.1.dist-info/METADATA,sha256=KVaRtAoER1Ss2HS1R8w6YrIrfwt8zH5bw5u_29sMjGA,8513
29
- imagepro_python-1.2.1.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
30
- imagepro_python-1.2.1.dist-info/top_level.txt,sha256=UOuPzsoWrVKXgUupOSI96shJ6wE8Fhz-8bm8oMlLC3s,9
31
- imagepro_python-1.2.1.dist-info/RECORD,,