ImagePRO-Python 0.1.0__py3-none-any.whl → 0.2.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/human_analysis/body_analysis/body_pose_estimation.py +61 -57
- ImagePRO/human_analysis/body_analysis/hand_tracking.py +68 -73
- ImagePRO/human_analysis/face_analysis/eye_status_analysis.py +73 -43
- ImagePRO/human_analysis/face_analysis/face_detection.py +54 -29
- ImagePRO/human_analysis/face_analysis/face_mesh_analysis.py +131 -78
- ImagePRO/human_analysis/face_analysis/head_pose_estimation.py +68 -39
- ImagePRO/pre_processing/blur.py +134 -66
- ImagePRO/pre_processing/contrast.py +111 -63
- ImagePRO/pre_processing/crop.py +42 -17
- ImagePRO/pre_processing/grayscale.py +33 -11
- ImagePRO/pre_processing/resize.py +40 -19
- ImagePRO/pre_processing/rotate.py +92 -71
- ImagePRO/pre_processing/sharpen.py +54 -38
- ImagePRO/utils/__init__.py +0 -0
- ImagePRO/utils/io_handler.py +180 -0
- {imagepro_python-0.1.0.dist-info → imagepro_python-0.2.0.dist-info}/METADATA +1 -1
- imagepro_python-0.2.0.dist-info/RECORD +25 -0
- imagepro_python-0.1.0.dist-info/RECORD +0 -23
- {imagepro_python-0.1.0.dist-info → imagepro_python-0.2.0.dist-info}/WHEEL +0 -0
- {imagepro_python-0.1.0.dist-info → imagepro_python-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {imagepro_python-0.1.0.dist-info → imagepro_python-0.2.0.dist-info}/top_level.txt +0 -0
|
@@ -1,43 +1,64 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
|
|
3
|
+
import numpy as np
|
|
4
4
|
import cv2
|
|
5
5
|
|
|
6
6
|
# Add parent directory to sys.path for importing custom modules
|
|
7
7
|
parent_dir = Path(__file__).resolve().parent.parent
|
|
8
8
|
sys.path.append(str(parent_dir))
|
|
9
9
|
|
|
10
|
-
from io_handler import IOHandler
|
|
10
|
+
from utils.io_handler import IOHandler
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def resize_image(
|
|
13
|
+
def resize_image(
|
|
14
|
+
new_size: tuple[int, int],
|
|
15
|
+
src_image_path: str | None = None,
|
|
16
|
+
src_np_image: np.ndarray | None = None,
|
|
17
|
+
output_image_path: str | None = None
|
|
18
|
+
) -> np.ndarray:
|
|
14
19
|
"""
|
|
15
|
-
Resize image to specified dimensions.
|
|
20
|
+
Resize an image to the specified dimensions.
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
new_size : tuple[int, int]
|
|
25
|
+
(width, height) in pixels, both must be positive integers.
|
|
26
|
+
src_image_path : str | None, optional
|
|
27
|
+
Path to the input image. Overrides `src_np_image` if provided.
|
|
28
|
+
src_np_image : np.ndarray | None, optional
|
|
29
|
+
Preloaded image array, used if `src_image_path` is None.
|
|
30
|
+
output_image_path : str | None, optional
|
|
31
|
+
Path to save the resized image.
|
|
22
32
|
|
|
23
|
-
Returns
|
|
24
|
-
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
np.ndarray
|
|
36
|
+
Resized image.
|
|
25
37
|
|
|
26
|
-
Raises
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
Raises
|
|
39
|
+
------
|
|
40
|
+
TypeError
|
|
41
|
+
If `new_size` is not a tuple of two integers.
|
|
42
|
+
ValueError
|
|
43
|
+
If width or height are not positive integers.
|
|
44
|
+
FileNotFoundError
|
|
45
|
+
If `src_image_path` does not exist.
|
|
46
|
+
IOError
|
|
47
|
+
If saving the image fails.
|
|
29
48
|
"""
|
|
30
49
|
if (
|
|
31
|
-
not isinstance(new_size, tuple)
|
|
32
|
-
len(new_size) != 2
|
|
33
|
-
not all(isinstance(x, int) for x in new_size)
|
|
50
|
+
not isinstance(new_size, tuple)
|
|
51
|
+
or len(new_size) != 2
|
|
52
|
+
or not all(isinstance(x, int) for x in new_size)
|
|
34
53
|
):
|
|
35
54
|
raise TypeError("'new_size' must be a tuple of two integers: (width, height).")
|
|
36
55
|
|
|
37
56
|
if new_size[0] <= 0 or new_size[1] <= 0:
|
|
38
57
|
raise ValueError("Both width and height must be positive integers.")
|
|
39
58
|
|
|
40
|
-
np_image = IOHandler.load_image(image_path=
|
|
59
|
+
np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
41
60
|
resized = cv2.resize(np_image, dsize=new_size)
|
|
42
61
|
|
|
43
|
-
|
|
62
|
+
if output_image_path:
|
|
63
|
+
print(IOHandler.save_image(resized, output_image_path))
|
|
64
|
+
return resized
|
|
@@ -1,94 +1,115 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
|
|
3
|
+
import numpy as np
|
|
4
4
|
import cv2
|
|
5
5
|
|
|
6
6
|
# Add parent directory to sys.path for custom imports
|
|
7
7
|
parent_dir = Path(__file__).resolve().parent.parent
|
|
8
8
|
sys.path.append(str(parent_dir))
|
|
9
9
|
|
|
10
|
-
from io_handler import IOHandler
|
|
10
|
+
from utils.io_handler import IOHandler
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def rotate_image_90(
|
|
13
|
+
def rotate_image_90(
|
|
14
|
+
src_image_path: str | None = None,
|
|
15
|
+
src_np_image: np.ndarray | None = None,
|
|
16
|
+
output_image_path: str | None = None
|
|
17
|
+
) -> np.ndarray:
|
|
14
18
|
"""
|
|
15
|
-
Rotate image 90 degrees clockwise.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
Rotate an image 90 degrees clockwise.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
src_image_path : str | None, optional
|
|
24
|
+
Path to the input image file.
|
|
25
|
+
src_np_image : np.ndarray | None, optional
|
|
26
|
+
Preloaded image array.
|
|
27
|
+
output_image_path : str | None, optional
|
|
28
|
+
Path to save the rotated image.
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
np.ndarray
|
|
33
|
+
Rotated image.
|
|
24
34
|
"""
|
|
25
|
-
np_image = IOHandler.load_image(image_path=
|
|
35
|
+
np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
26
36
|
rotated = cv2.rotate(np_image, cv2.ROTATE_90_CLOCKWISE)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Returns:
|
|
40
|
-
str or np.ndarray: Save message if result_path is given, else rotated image.
|
|
41
|
-
"""
|
|
42
|
-
np_image = IOHandler.load_image(image_path=image_path, np_image=np_image)
|
|
37
|
+
if output_image_path:
|
|
38
|
+
print(IOHandler.save_image(rotated, output_image_path))
|
|
39
|
+
return rotated
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def rotate_image_180(
|
|
43
|
+
src_image_path: str | None = None,
|
|
44
|
+
src_np_image: np.ndarray | None = None,
|
|
45
|
+
output_image_path: str | None = None
|
|
46
|
+
) -> np.ndarray:
|
|
47
|
+
"""Rotate an image 180 degrees."""
|
|
48
|
+
np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
43
49
|
rotated = cv2.rotate(np_image, cv2.ROTATE_180)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
Returns:
|
|
57
|
-
str or np.ndarray: Save message if result_path is given, else rotated image.
|
|
58
|
-
"""
|
|
59
|
-
np_image = IOHandler.load_image(image_path=image_path, np_image=np_image)
|
|
50
|
+
if output_image_path:
|
|
51
|
+
print(IOHandler.save_image(rotated, output_image_path))
|
|
52
|
+
return rotated
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def rotate_image_270(
|
|
56
|
+
src_image_path: str | None = None,
|
|
57
|
+
src_np_image: np.ndarray | None = None,
|
|
58
|
+
output_image_path: str | None = None
|
|
59
|
+
) -> np.ndarray:
|
|
60
|
+
"""Rotate an image 270 degrees clockwise (90° counter-clockwise)."""
|
|
61
|
+
np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
60
62
|
rotated = cv2.rotate(np_image, cv2.ROTATE_90_COUNTERCLOCKWISE)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
if output_image_path:
|
|
64
|
+
print(IOHandler.save_image(rotated, output_image_path))
|
|
65
|
+
return rotated
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def rotate_image_custom(
|
|
69
|
+
angle: float,
|
|
70
|
+
scale: float = 1.0,
|
|
71
|
+
src_image_path: str | None = None,
|
|
72
|
+
src_np_image: np.ndarray | None = None,
|
|
73
|
+
output_image_path: str | None = None
|
|
74
|
+
) -> np.ndarray:
|
|
65
75
|
"""
|
|
66
|
-
Rotate image by custom angle around its center
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
Rotate an image by a custom angle around its center with optional scaling.
|
|
77
|
+
|
|
78
|
+
Parameters
|
|
79
|
+
----------
|
|
80
|
+
angle : float
|
|
81
|
+
Rotation angle in degrees (positive = counter-clockwise).
|
|
82
|
+
scale : float, default=1.0
|
|
83
|
+
Scaling factor (> 0).
|
|
84
|
+
src_image_path : str | None, optional
|
|
85
|
+
Path to the input image file.
|
|
86
|
+
src_np_image : np.ndarray | None, optional
|
|
87
|
+
Preloaded image array.
|
|
88
|
+
output_image_path : str | None, optional
|
|
89
|
+
Path to save the rotated image.
|
|
90
|
+
|
|
91
|
+
Returns
|
|
92
|
+
-------
|
|
93
|
+
np.ndarray
|
|
94
|
+
Rotated image.
|
|
95
|
+
|
|
96
|
+
Raises
|
|
97
|
+
------
|
|
98
|
+
TypeError
|
|
99
|
+
If `angle` or `scale` are of incorrect type.
|
|
100
|
+
ValueError
|
|
101
|
+
If `scale` is not positive.
|
|
81
102
|
"""
|
|
82
103
|
if not isinstance(angle, (int, float)):
|
|
83
104
|
raise TypeError("'angle' must be a number.")
|
|
84
105
|
if not isinstance(scale, (int, float)) or scale <= 0:
|
|
85
106
|
raise ValueError("'scale' must be a positive number.")
|
|
86
107
|
|
|
87
|
-
np_image = IOHandler.load_image(image_path=
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
center = (width / 2, height / 2)
|
|
108
|
+
np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
109
|
+
h, w = np_image.shape[:2]
|
|
110
|
+
center = (w / 2, h / 2)
|
|
91
111
|
matrix = cv2.getRotationMatrix2D(center=center, angle=angle, scale=scale)
|
|
92
|
-
rotated = cv2.warpAffine(np_image, matrix, (
|
|
93
|
-
|
|
94
|
-
|
|
112
|
+
rotated = cv2.warpAffine(np_image, matrix, (w, h))
|
|
113
|
+
if output_image_path:
|
|
114
|
+
print(IOHandler.save_image(rotated, output_image_path))
|
|
115
|
+
return rotated
|
|
@@ -1,74 +1,90 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
|
|
4
|
-
import cv2
|
|
5
3
|
import numpy as np
|
|
4
|
+
import cv2
|
|
6
5
|
|
|
7
6
|
# Add parent directory to path for importing local modules
|
|
8
7
|
parent_dir = Path(__file__).resolve().parent.parent
|
|
9
8
|
sys.path.append(str(parent_dir))
|
|
10
9
|
|
|
11
|
-
from io_handler import IOHandler
|
|
12
|
-
from blur import apply_average_blur
|
|
10
|
+
from utils.io_handler import IOHandler
|
|
11
|
+
from pre_processing.blur import apply_average_blur
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
def apply_laplacian_sharpening(
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
coefficient: float = 3.0,
|
|
16
|
+
src_image_path: str | None = None,
|
|
17
|
+
src_np_image: np.ndarray | None = None,
|
|
18
|
+
output_image_path: str | None = None
|
|
19
|
+
) -> np.ndarray:
|
|
18
20
|
"""
|
|
19
21
|
Apply Laplacian filter to enhance image sharpness.
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
coefficient : float, default=3.0
|
|
26
|
+
Intensity of sharpening effect (>= 0).
|
|
27
|
+
src_image_path : str | None
|
|
28
|
+
Path to the input image file.
|
|
29
|
+
src_np_image : np.ndarray | None
|
|
30
|
+
Preloaded image array.
|
|
31
|
+
output_image_path : str | None
|
|
32
|
+
Path to save the sharpened image.
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
np.ndarray
|
|
37
|
+
Sharpened image.
|
|
32
38
|
"""
|
|
33
|
-
if not isinstance(
|
|
34
|
-
raise ValueError("'
|
|
35
|
-
|
|
36
|
-
np_image = IOHandler.load_image(image_path=image_path, np_image=np_image)
|
|
39
|
+
if not isinstance(coefficient, (int, float)) or coefficient < 0:
|
|
40
|
+
raise ValueError("'coefficient' must be a non-negative number.")
|
|
37
41
|
|
|
42
|
+
np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
38
43
|
laplacian = cv2.Laplacian(np_image, cv2.CV_64F)
|
|
39
44
|
laplacian = np.uint8(np.absolute(laplacian))
|
|
40
45
|
|
|
41
|
-
sharpened = np_image +
|
|
46
|
+
sharpened = np_image + coefficient * laplacian
|
|
42
47
|
sharpened = np.uint8(np.clip(sharpened, 0, 255))
|
|
43
48
|
|
|
44
|
-
|
|
49
|
+
if output_image_path:
|
|
50
|
+
print(IOHandler.save_image(sharpened, output_image_path))
|
|
51
|
+
return sharpened
|
|
45
52
|
|
|
46
53
|
|
|
47
54
|
def apply_unsharp_masking(
|
|
48
|
-
coefficient
|
|
49
|
-
|
|
55
|
+
coefficient: float = 1.0,
|
|
56
|
+
src_image_path: str | None = None,
|
|
57
|
+
src_np_image: np.ndarray | None = None,
|
|
58
|
+
output_image_path: str | None = None
|
|
59
|
+
) -> np.ndarray:
|
|
50
60
|
"""
|
|
51
61
|
Apply Unsharp Masking to enhance image sharpness.
|
|
52
62
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
coefficient : float, default=1.0
|
|
66
|
+
Intensity of sharpening effect (>= 0).
|
|
67
|
+
src_image_path : str | None
|
|
68
|
+
Path to the input image file.
|
|
69
|
+
src_np_image : np.ndarray | None
|
|
70
|
+
Preloaded image array.
|
|
71
|
+
output_image_path : str | None
|
|
72
|
+
Path to save the sharpened image.
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
np.ndarray
|
|
77
|
+
Sharpened image.
|
|
64
78
|
"""
|
|
65
79
|
if not isinstance(coefficient, (int, float)) or coefficient < 0:
|
|
66
80
|
raise ValueError("'coefficient' must be a non-negative number.")
|
|
67
81
|
|
|
68
|
-
np_image = IOHandler.load_image(image_path=
|
|
82
|
+
np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
69
83
|
blurred = apply_average_blur(np_image=np_image)
|
|
70
84
|
|
|
71
85
|
mask = cv2.subtract(np_image, blurred)
|
|
72
86
|
sharpened = cv2.addWeighted(np_image, 1 + coefficient, mask, -coefficient, 0)
|
|
73
87
|
|
|
74
|
-
|
|
88
|
+
if output_image_path:
|
|
89
|
+
print(IOHandler.save_image(sharpened, output_image_path))
|
|
90
|
+
return sharpened
|
|
File without changes
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# io_handler.py
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
5
|
+
import csv
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import cv2
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class IOHandler:
|
|
13
|
+
@staticmethod
|
|
14
|
+
def load_image(image_path=None, np_image=None):
|
|
15
|
+
"""
|
|
16
|
+
Load an image from disk or use an existing NumPy array.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
image_path (str, optional): Path to the image file.
|
|
20
|
+
np_image (np.ndarray, optional): Image as a NumPy array.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
np.ndarray: Loaded image.
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
TypeError: Invalid input types.
|
|
27
|
+
FileNotFoundError: File not found.
|
|
28
|
+
ValueError: Both inputs are None or image loading failed.
|
|
29
|
+
"""
|
|
30
|
+
if image_path is not None:
|
|
31
|
+
if not isinstance(image_path, str):
|
|
32
|
+
raise TypeError("'image_path' must be a string.")
|
|
33
|
+
if not os.path.isfile(image_path):
|
|
34
|
+
raise FileNotFoundError(f"File not found: {image_path}")
|
|
35
|
+
img = cv2.imread(image_path)
|
|
36
|
+
if img is None:
|
|
37
|
+
raise ValueError(f"Unable to load image: {image_path}")
|
|
38
|
+
return img
|
|
39
|
+
|
|
40
|
+
if np_image is not None:
|
|
41
|
+
if not isinstance(np_image, np.ndarray):
|
|
42
|
+
raise TypeError("'np_image' must be a NumPy array.")
|
|
43
|
+
return np_image
|
|
44
|
+
|
|
45
|
+
raise ValueError("Provide at least 'image_path' or 'np_image'.")
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def save_image(np_image, result_path=None):
|
|
49
|
+
"""
|
|
50
|
+
Save a NumPy image array (or list of arrays) to disk or return it.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
np_image (np.ndarray or list[np.ndarray]): Image(s) to save.
|
|
54
|
+
result_path (str, optional): Save path.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
str or np.ndarray or list[np.ndarray]:
|
|
58
|
+
Save message if path given, otherwise returns input.
|
|
59
|
+
|
|
60
|
+
Raises:
|
|
61
|
+
TypeError: Invalid input types.
|
|
62
|
+
IOError: Saving failed.
|
|
63
|
+
"""
|
|
64
|
+
if not isinstance(np_image, (np.ndarray, list)):
|
|
65
|
+
raise TypeError("'np_image' must be a NumPy array or list of arrays.")
|
|
66
|
+
|
|
67
|
+
if isinstance(np_image, list) and not all(isinstance(i, np.ndarray) for i in np_image):
|
|
68
|
+
raise TypeError("All items in the list must be NumPy arrays.")
|
|
69
|
+
|
|
70
|
+
if result_path is not None and not isinstance(result_path, str):
|
|
71
|
+
raise TypeError("'result_path' must be a string or None.")
|
|
72
|
+
|
|
73
|
+
if result_path:
|
|
74
|
+
if isinstance(np_image, np.ndarray):
|
|
75
|
+
if not cv2.imwrite(result_path, np_image):
|
|
76
|
+
raise IOError(f"Failed to save image: {result_path}")
|
|
77
|
+
return f"Image saved at {result_path}"
|
|
78
|
+
|
|
79
|
+
for i, img in enumerate(np_image):
|
|
80
|
+
suffix = f"_{i}" if i > 0 else ""
|
|
81
|
+
path = result_path.replace(".jpg", f"{suffix}.jpg")
|
|
82
|
+
if not cv2.imwrite(path, img):
|
|
83
|
+
raise IOError(f"Failed to save image: {path}")
|
|
84
|
+
return f"Images saved using base path {result_path}"
|
|
85
|
+
|
|
86
|
+
return "Skipped saving image because no file path was provided"
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def save_csv(data, result_path=None):
|
|
90
|
+
"""
|
|
91
|
+
Save a list of lists as a CSV file or return it.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
data (list[list]): Tabular data.
|
|
95
|
+
result_path (str, optional): Save path.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
str or list[list]: Save message or original data.
|
|
99
|
+
|
|
100
|
+
Raises:
|
|
101
|
+
TypeError: Invalid input types.
|
|
102
|
+
"""
|
|
103
|
+
if not isinstance(data, list) or not all(isinstance(row, list) for row in data):
|
|
104
|
+
raise TypeError("'data' must be a list of lists.")
|
|
105
|
+
|
|
106
|
+
if result_path:
|
|
107
|
+
if not isinstance(result_path, str):
|
|
108
|
+
raise TypeError("'result_path' must be a string or None.")
|
|
109
|
+
with open(result_path, "w", newline='') as f:
|
|
110
|
+
writer = csv.writer(f)
|
|
111
|
+
writer.writerows(data)
|
|
112
|
+
return f"CSV saved at {result_path}"
|
|
113
|
+
|
|
114
|
+
return "Skipped saving csv because no file path was provided"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def save_json(data, result_path=None):
|
|
119
|
+
"""
|
|
120
|
+
Save data as a JSON file or return it.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
data (Any): JSON-serializable data.
|
|
124
|
+
result_path (str, optional): Save path.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
str or Any: Save message or original data.
|
|
128
|
+
|
|
129
|
+
Raises:
|
|
130
|
+
TypeError: Invalid path type.
|
|
131
|
+
"""
|
|
132
|
+
if result_path:
|
|
133
|
+
if not isinstance(result_path, str):
|
|
134
|
+
raise TypeError("'result_path' must be a string or None.")
|
|
135
|
+
with open(result_path, "w") as f:
|
|
136
|
+
json.dump(data, f, indent=4)
|
|
137
|
+
return f"JSON saved at {result_path}"
|
|
138
|
+
|
|
139
|
+
return "Skipped saving json because no file path was provided"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@staticmethod
|
|
143
|
+
def save(data, result_path=None, file_type=None):
|
|
144
|
+
"""
|
|
145
|
+
Save data to disk automatically based on file type or extension.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
data (Any): Data to save.
|
|
149
|
+
result_path (str, optional): Save path.
|
|
150
|
+
file_type (str, optional): 'image', 'csv', or 'json'.
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
str or Any: Save message or original data.
|
|
154
|
+
|
|
155
|
+
Raises:
|
|
156
|
+
ValueError: Unsupported file type or extension.
|
|
157
|
+
TypeError: Invalid input types.
|
|
158
|
+
"""
|
|
159
|
+
if file_type is None:
|
|
160
|
+
if result_path is None:
|
|
161
|
+
return data
|
|
162
|
+
|
|
163
|
+
ext = Path(result_path).suffix.lower()
|
|
164
|
+
if ext in [".jpg", ".jpeg", ".png"]:
|
|
165
|
+
file_type = "image"
|
|
166
|
+
elif ext == ".csv":
|
|
167
|
+
file_type = "csv"
|
|
168
|
+
elif ext == ".json":
|
|
169
|
+
file_type = "json"
|
|
170
|
+
else:
|
|
171
|
+
raise ValueError(f"Unsupported file extension: {ext}")
|
|
172
|
+
|
|
173
|
+
if file_type == "image":
|
|
174
|
+
return IOHandler.save_image(data, result_path)
|
|
175
|
+
elif file_type == "csv":
|
|
176
|
+
return IOHandler.save_csv(data, result_path)
|
|
177
|
+
elif file_type == "json":
|
|
178
|
+
return IOHandler.save_json(data, result_path)
|
|
179
|
+
|
|
180
|
+
raise ValueError(f"Unsupported file type: {file_type}")
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
ImagePRO/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
ImagePRO/human_analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
ImagePRO/human_analysis/body_analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
ImagePRO/human_analysis/body_analysis/body_pose_estimation.py,sha256=GTVcTdASiaM8MKbv0u9xxl2mFQEMbPT2w91Dkf7dLGw,4084
|
|
5
|
+
ImagePRO/human_analysis/body_analysis/hand_tracking.py,sha256=ivCvveMI3s51obxWggLy4PvXRoW1Hn6NsR9wy8Nfbfs,5205
|
|
6
|
+
ImagePRO/human_analysis/face_analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
ImagePRO/human_analysis/face_analysis/eye_status_analysis.py,sha256=ykmGgUsVXBMImFwcC7B3L2CUZrn2Q0KOqiOsT7EBU7c,5559
|
|
8
|
+
ImagePRO/human_analysis/face_analysis/face_detection.py,sha256=qob4dIVGZPZRDMy7_wS3LYWpaUNe7Q-P2_9IENrbc2E,4019
|
|
9
|
+
ImagePRO/human_analysis/face_analysis/face_mesh_analysis.py,sha256=SSAMHu93dGYQ7RupP7s6_-V4DmrBgX1YZI_uVeno1-A,8341
|
|
10
|
+
ImagePRO/human_analysis/face_analysis/head_pose_estimation.py,sha256=qQ9OI7PGHkAYJjTazxmFLwvj0OTnNxklKBVibnfsyYI,5752
|
|
11
|
+
ImagePRO/pre_processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
ImagePRO/pre_processing/blur.py,sha256=JqkM0cLfRrBlQEixkC-iuhu6rR62VPMA2KObzmcmt_Q,5909
|
|
13
|
+
ImagePRO/pre_processing/contrast.py,sha256=00qp_BZ8-t1TqLE-bTWcLFS5bMCeAXTT7cNnADHUR3w,4341
|
|
14
|
+
ImagePRO/pre_processing/crop.py,sha256=a5tF5nDOekCA-SqJqddYXzJo7PN2DZpcdIJsObpZBmA,2351
|
|
15
|
+
ImagePRO/pre_processing/grayscale.py,sha256=PtdONZPmLzZpj7YpeBA9D_pYcVNTmOZPNJasDpeO9Yo,1325
|
|
16
|
+
ImagePRO/pre_processing/resize.py,sha256=1ceEKZ7bHJK9a07QEzfEd6H3oqNT2yL5PWKI0HXmIkE,1890
|
|
17
|
+
ImagePRO/pre_processing/rotate.py,sha256=tBNkiSZFpMPOjlQFQw9dR1y1zuT0Owqd4iBIRVEBrYs,3544
|
|
18
|
+
ImagePRO/pre_processing/sharpen.py,sha256=CneU-avwfRsWRUU-COmAtpfWlMQgCN1WVp3hd96YJmc,2708
|
|
19
|
+
ImagePRO/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
ImagePRO/utils/io_handler.py,sha256=lWc_UzoihbzZ7sObCFK7KXCOhsp00V6KUoMVpV-6tSs,6059
|
|
21
|
+
imagepro_python-0.2.0.dist-info/licenses/LICENSE,sha256=sehkHN7dbe5umrINZJyJjIf9VTemZSgTfJlq6iIsbJQ,1069
|
|
22
|
+
imagepro_python-0.2.0.dist-info/METADATA,sha256=z8cuVv_h8U5dN4kXhHm37wqduX2FauE8sSd-XBppu-w,656
|
|
23
|
+
imagepro_python-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
24
|
+
imagepro_python-0.2.0.dist-info/top_level.txt,sha256=UOuPzsoWrVKXgUupOSI96shJ6wE8Fhz-8bm8oMlLC3s,9
|
|
25
|
+
imagepro_python-0.2.0.dist-info/RECORD,,
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
ImagePRO/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
ImagePRO/human_analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
ImagePRO/human_analysis/body_analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
ImagePRO/human_analysis/body_analysis/body_pose_estimation.py,sha256=dQAcgXR7crYH-G_oawSZQWo1nLE4BzGvD1t10oBn-qY,4200
|
|
5
|
-
ImagePRO/human_analysis/body_analysis/hand_tracking.py,sha256=6amBMgpyv9npt7ASr0d_iTQ2VImWQf2Rh8b_scvnAXU,5588
|
|
6
|
-
ImagePRO/human_analysis/face_analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
ImagePRO/human_analysis/face_analysis/eye_status_analysis.py,sha256=xftGux-5c_QqvN04xAYoCVVWoH9rCBEYQuDn3EuD3aY,4479
|
|
8
|
-
ImagePRO/human_analysis/face_analysis/face_detection.py,sha256=l63Ggbr4pMkBRWiEmc1rgrQNrY3X51DQzsM0-Uiga80,2773
|
|
9
|
-
ImagePRO/human_analysis/face_analysis/face_mesh_analysis.py,sha256=20DB5xeErNctvrSK7D1h8iKykjHwpi-EmZzW9LQkyCM,5953
|
|
10
|
-
ImagePRO/human_analysis/face_analysis/head_pose_estimation.py,sha256=1KHul5RXv1FXhgmYtuV67TfWCEb6WthB_DLfyHqvKH0,4672
|
|
11
|
-
ImagePRO/pre_processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
ImagePRO/pre_processing/blur.py,sha256=5I5unsDXr34EVSrlBrgiQdTp4j3Ct4eRYhMoV1rXe8c,4532
|
|
13
|
-
ImagePRO/pre_processing/contrast.py,sha256=wt4LHmbyPZ4aYaKwo4IYCzZjSQ4FUNXD1FyyR-r679E,3426
|
|
14
|
-
ImagePRO/pre_processing/crop.py,sha256=ubQ5loEJnVXefbOcR93lj875fZkrOdMYufTWiVJ2oLU,1880
|
|
15
|
-
ImagePRO/pre_processing/grayscale.py,sha256=_wSSxniJzui2xIZGHjQ3r987ldE-yBdJBADB2W6-nVk,889
|
|
16
|
-
ImagePRO/pre_processing/resize.py,sha256=0MoM34U_SFLloRa1JN3JbUm7JHLB6JrO5UxVxH0EtBE,1463
|
|
17
|
-
ImagePRO/pre_processing/rotate.py,sha256=2cT_s47LwuQbOExyUDdcRMIbgsqA1JNPhhezaRYLIw8,3423
|
|
18
|
-
ImagePRO/pre_processing/sharpen.py,sha256=mRJRyvN9YwnqQfuGgzmOWThnEbp4lDcE5OmDuGHuyQk,2575
|
|
19
|
-
imagepro_python-0.1.0.dist-info/licenses/LICENSE,sha256=sehkHN7dbe5umrINZJyJjIf9VTemZSgTfJlq6iIsbJQ,1069
|
|
20
|
-
imagepro_python-0.1.0.dist-info/METADATA,sha256=uMimqz6NPlUkCRxTbqfS1vTDZ0gYqYQbgXi3s7UktKs,656
|
|
21
|
-
imagepro_python-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
22
|
-
imagepro_python-0.1.0.dist-info/top_level.txt,sha256=UOuPzsoWrVKXgUupOSI96shJ6wE8Fhz-8bm8oMlLC3s,9
|
|
23
|
-
imagepro_python-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|