yta-image-base 0.0.1__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.
- yta_image_base/__init__.py +309 -0
- yta_image_base/background.py +91 -0
- yta_image_base/color/__init__.py +0 -0
- yta_image_base/color/picker.py +201 -0
- yta_image_base/converter.py +283 -0
- yta_image_base/edition/__init__.py +0 -0
- yta_image_base/edition/editor.py +376 -0
- yta_image_base/edition/settings.py +16 -0
- yta_image_base/parser.py +128 -0
- yta_image_base/region/__init__.py +0 -0
- yta_image_base/region/finder.py +248 -0
- yta_image_base/size.py +135 -0
- yta_image_base-0.0.1.dist-info/LICENSE +19 -0
- yta_image_base-0.0.1.dist-info/METADATA +24 -0
- yta_image_base-0.0.1.dist-info/RECORD +16 -0
- yta_image_base-0.0.1.dist-info/WHEEL +4 -0
yta_image_base/parser.py
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
from yta_image_base.converter import ImageConverter
|
2
|
+
from yta_file.handler import FileHandler
|
3
|
+
from yta_file.filename.handler import FilenameHandler, FileType
|
4
|
+
from yta_validation import PythonValidator
|
5
|
+
from PIL import Image
|
6
|
+
from typing import Union
|
7
|
+
|
8
|
+
import numpy as np
|
9
|
+
|
10
|
+
|
11
|
+
class ImageParser:
|
12
|
+
"""
|
13
|
+
Class to simplify the way we handle the image parameters
|
14
|
+
so we can parse them as Pillow images, as numpy arrays,
|
15
|
+
etc.
|
16
|
+
"""
|
17
|
+
|
18
|
+
@staticmethod
|
19
|
+
def to_pillow(
|
20
|
+
image: Union[str, Image.Image, np.ndarray],
|
21
|
+
mode: str = 'RGB'
|
22
|
+
) -> Image.Image:
|
23
|
+
"""
|
24
|
+
Returns an instance of a Pillow Image.Image of the given
|
25
|
+
'image' if it is a valid image and no error found.
|
26
|
+
|
27
|
+
Result is a Pillow image which is in RGB (or RGBA) format.
|
28
|
+
"""
|
29
|
+
# TODO: By now we are only accepting string filenames,
|
30
|
+
# Pillow Image.Image instances and numpy arrays.
|
31
|
+
if image is None:
|
32
|
+
raise Exception('No "image" parameter provided.')
|
33
|
+
|
34
|
+
if (
|
35
|
+
not PythonValidator.is_string(image) and
|
36
|
+
not PythonValidator.is_numpy_array(image) and
|
37
|
+
not PythonValidator.is_instance(image, Image.Image)
|
38
|
+
):
|
39
|
+
raise Exception('The "image" parameter provided is not a string nor a Image.Image nor a np.ndarray.')
|
40
|
+
|
41
|
+
mode = (
|
42
|
+
'RGB'
|
43
|
+
if not mode else
|
44
|
+
mode
|
45
|
+
)
|
46
|
+
|
47
|
+
if mode not in ['RGB', 'RGBA']:
|
48
|
+
raise Exception('The provided "mode" parameters is not a valid mode: RGB or RGBA.')
|
49
|
+
|
50
|
+
# We can have problems with np.ndarray
|
51
|
+
if PythonValidator.is_numpy_array(image):
|
52
|
+
image = ImageConverter.numpy_image_to_pil(image)
|
53
|
+
elif PythonValidator.is_string(image):
|
54
|
+
if not FilenameHandler.is_of_type(image, FileType.IMAGE):
|
55
|
+
raise Exception('The "image" parameter provided is not a valid image filename.')
|
56
|
+
|
57
|
+
if not FileHandler.is_image_file(image):
|
58
|
+
raise Exception('The "image" parameter provided is not a valid image.')
|
59
|
+
|
60
|
+
image = Image.open(image)
|
61
|
+
|
62
|
+
return image.convert(mode)
|
63
|
+
|
64
|
+
@staticmethod
|
65
|
+
def to_numpy(
|
66
|
+
image: Union[str, Image.Image, np.ndarray],
|
67
|
+
mode: str = 'RGB'
|
68
|
+
) -> np.ndarray:
|
69
|
+
"""
|
70
|
+
Returns a numpy array representing the given 'image'
|
71
|
+
if it is a valid image and no error found.
|
72
|
+
|
73
|
+
The 'mode' parameter will be used to open the image
|
74
|
+
with Pillow library and then turning into numpy when
|
75
|
+
necessary. Must be 'RGB' or 'RGBA'.
|
76
|
+
|
77
|
+
Result is in RGB or RGBA format.
|
78
|
+
"""
|
79
|
+
# TODO: By now we are only accepting string filenames,
|
80
|
+
# Pillow Image.Image instances and numpy arrays.
|
81
|
+
if image is None:
|
82
|
+
raise Exception('No "image" parameter provided.')
|
83
|
+
|
84
|
+
if not PythonValidator.is_instance(image, [str, Image.Image, np.ndarray]):
|
85
|
+
raise Exception('The "image" parameter provided is not a string nor a Image.Image nor a np.ndarray.')
|
86
|
+
|
87
|
+
mode = 'RGB' if not mode else mode
|
88
|
+
|
89
|
+
if mode not in ['RGB', 'RGBA']:
|
90
|
+
raise Exception('The provided "mode" parameters is not a valid mode: RGB or RGBA.')
|
91
|
+
|
92
|
+
# We can have problems with np.ndarray
|
93
|
+
if PythonValidator.is_instance(image, Image.Image):
|
94
|
+
image = ImageConverter.pil_image_to_numpy(image.convert(mode))
|
95
|
+
elif PythonValidator.is_string(image):
|
96
|
+
if not FilenameHandler.is_of_type(image, FileType.IMAGE):
|
97
|
+
raise Exception('The "image" parameter provided is not a valid image filename.')
|
98
|
+
|
99
|
+
if not FileHandler.is_image_file(image):
|
100
|
+
raise Exception('The "image" parameter provided is not a valid image.')
|
101
|
+
|
102
|
+
image = ImageConverter.pil_image_to_numpy(Image.open(image).convert(mode))
|
103
|
+
elif PythonValidator.is_numpy_array(image):
|
104
|
+
if image.shape[2] == 3 and mode == 'RGBA':
|
105
|
+
# numpy but RGB to RGBA
|
106
|
+
image = np.dstack((image, np.ones((image.shape[0], image.shape[1]), dtype = np.uint8) * 255))
|
107
|
+
# Moviepy uses the alpha channel as 0 or 1, not as 255
|
108
|
+
# but this is only an image parser not a moviepy parser
|
109
|
+
#image = np.dstack((image, np.ones((image.shape[0], image.shape[1]), dtype = np.uint8)))
|
110
|
+
elif image.shape[2] == 4 and mode == 'RGB':
|
111
|
+
# numpy but RGBA to RGB
|
112
|
+
image = image[:, :, :3]
|
113
|
+
|
114
|
+
return image
|
115
|
+
|
116
|
+
@staticmethod
|
117
|
+
def to_opencv(
|
118
|
+
image: Union[str, Image.Image, np.ndarray],
|
119
|
+
mode: str = 'RGB'
|
120
|
+
) -> np.ndarray:
|
121
|
+
"""
|
122
|
+
The 'image' is read as a RGB numpy array and then
|
123
|
+
transformed into an BGR numpy array because Opencv
|
124
|
+
uses BGR format.
|
125
|
+
|
126
|
+
Result is in BGR format.
|
127
|
+
"""
|
128
|
+
return ImageParser.to_numpy(image, mode)[:, :, ::-1]
|
File without changes
|
@@ -0,0 +1,248 @@
|
|
1
|
+
from yta_image_base.parser import ImageParser
|
2
|
+
from yta_image_base.color.picker import PixelFilterFunction
|
3
|
+
from yta_validation.parameter import ParameterValidator
|
4
|
+
from yta_general_utils.region import Region
|
5
|
+
from typing import Union
|
6
|
+
from PIL import Image
|
7
|
+
|
8
|
+
import numpy as np
|
9
|
+
import cv2
|
10
|
+
|
11
|
+
|
12
|
+
MIN_REGION_SIZE = (1920 / 20, 1080 / 20)
|
13
|
+
"""
|
14
|
+
The minimum size a region must have to be accepted
|
15
|
+
as a valid region.
|
16
|
+
"""
|
17
|
+
|
18
|
+
class ImageRegionFinder:
|
19
|
+
|
20
|
+
DIRECTIONS = [
|
21
|
+
(-1, 0),
|
22
|
+
(1, 0),
|
23
|
+
(0, -1),
|
24
|
+
(0, 1),
|
25
|
+
(-1, -1),
|
26
|
+
(-1, 1),
|
27
|
+
(1, -1),
|
28
|
+
(1, 1)
|
29
|
+
]
|
30
|
+
"""
|
31
|
+
The directions to move while searching, that are
|
32
|
+
the 8 possible options: up, up-right, right, etc.,
|
33
|
+
expressed as (x, y) tuples.
|
34
|
+
"""
|
35
|
+
|
36
|
+
@staticmethod
|
37
|
+
def is_valid(
|
38
|
+
position: tuple[int, int],
|
39
|
+
image,
|
40
|
+
visited,
|
41
|
+
filter_func: callable
|
42
|
+
) -> bool:
|
43
|
+
"""
|
44
|
+
This method verifies if the pixel is between the limits
|
45
|
+
and fits the filter and is unvisited.
|
46
|
+
"""
|
47
|
+
rows, cols, _ = image.shape
|
48
|
+
|
49
|
+
return (
|
50
|
+
0 <= position[0] < rows and
|
51
|
+
0 <= position[1] < cols and
|
52
|
+
not visited[position[0], position[1]] and
|
53
|
+
filter_func(image[position[0], position[1]])
|
54
|
+
)
|
55
|
+
|
56
|
+
@staticmethod
|
57
|
+
def _dfs(
|
58
|
+
image: np.ndarray,
|
59
|
+
visited,
|
60
|
+
x,
|
61
|
+
y,
|
62
|
+
region,
|
63
|
+
filter_func: callable
|
64
|
+
):
|
65
|
+
"""
|
66
|
+
A Deep First Search algorithm applied to the
|
67
|
+
image to obtain all the pixels connected within
|
68
|
+
a region.
|
69
|
+
"""
|
70
|
+
if not isinstance(image, np.ndarray):
|
71
|
+
raise Exception('The provided "image" parameter is not a valid np.ndarray.')
|
72
|
+
|
73
|
+
stack = [(x, y)]
|
74
|
+
visited[x, y] = True
|
75
|
+
region.append((x, y))
|
76
|
+
|
77
|
+
while stack:
|
78
|
+
current_x, current_y = stack.pop()
|
79
|
+
for direction_x, direction_y in ImageRegionFinder.DIRECTIONS:
|
80
|
+
new_x, new_y = current_x + direction_x, current_y + direction_y
|
81
|
+
if ImageRegionFinder.is_valid((new_x, new_y), image, visited, filter_func):
|
82
|
+
visited[new_x, new_y] = True
|
83
|
+
region.append((new_x, new_y))
|
84
|
+
stack.append((new_x, new_y))
|
85
|
+
|
86
|
+
@staticmethod
|
87
|
+
def is_inside(
|
88
|
+
small_bounds,
|
89
|
+
large_bounds
|
90
|
+
):
|
91
|
+
"""
|
92
|
+
This method verifies if the bounds of a found region are
|
93
|
+
inside another bounds to discard the smaller regions.
|
94
|
+
"""
|
95
|
+
min_x_small, max_x_small, min_y_small, max_y_small = small_bounds
|
96
|
+
min_x_large, max_x_large, min_y_large, max_y_large = large_bounds
|
97
|
+
|
98
|
+
return (
|
99
|
+
min_x_small >= min_x_large and max_x_small <= max_x_large and
|
100
|
+
min_y_small >= min_y_large and max_y_small <= max_y_large
|
101
|
+
)
|
102
|
+
|
103
|
+
@staticmethod
|
104
|
+
def find_regions(
|
105
|
+
image: np.ndarray,
|
106
|
+
filter_func: PixelFilterFunction
|
107
|
+
) -> list[Region]:
|
108
|
+
"""
|
109
|
+
This method looks for all the existing regions of transparent
|
110
|
+
pixels that are connected ones to the others (neighbours). The
|
111
|
+
'filter_func' parameter is the one that will classify the pixels
|
112
|
+
as, for example, transparent or green. That 'filter_func' must
|
113
|
+
be a method contained in the PixelFilterFunction class.
|
114
|
+
|
115
|
+
This method returns the found regions as objects with 'top_left'
|
116
|
+
and 'bottom_right' fields that are arrays of [x, y] positions
|
117
|
+
corresponding to the corners of the found regions.
|
118
|
+
"""
|
119
|
+
ParameterValidator.validate_mandatory_numpy_array('image', image)
|
120
|
+
|
121
|
+
rows, cols, _ = image.shape
|
122
|
+
visited = np.zeros((rows, cols), dtype=bool)
|
123
|
+
regions = []
|
124
|
+
|
125
|
+
for row in range(rows):
|
126
|
+
for col in range(cols):
|
127
|
+
# If we find a transparent pixel, we search
|
128
|
+
if filter_func(image[row, col]) and not visited[row, col]:
|
129
|
+
region = []
|
130
|
+
ImageRegionFinder._dfs(image, visited, row, col, region, filter_func)
|
131
|
+
|
132
|
+
# TODO: What is this for? Maybe just a break
|
133
|
+
# if len(region) = 10 (?)
|
134
|
+
for i, _ in enumerate(region):
|
135
|
+
if i == 10:
|
136
|
+
break
|
137
|
+
|
138
|
+
if region:
|
139
|
+
min_x = min(px[0] for px in region)
|
140
|
+
max_x = max(px[0] for px in region)
|
141
|
+
min_y = min(px[1] for px in region)
|
142
|
+
max_y = max(px[1] for px in region)
|
143
|
+
|
144
|
+
# These are the limits of the region, calculated as a
|
145
|
+
# rectangle that wraps the whole region, but not the
|
146
|
+
# real region and limits
|
147
|
+
bounds = (min_x, max_x, min_y, max_y)
|
148
|
+
|
149
|
+
# We need to avoid small regions contained in others and
|
150
|
+
# also use a minimum size to accept a region as valid
|
151
|
+
if (
|
152
|
+
max_x - min_x >= MIN_REGION_SIZE[0] and
|
153
|
+
max_y - min_y >= MIN_REGION_SIZE[1] and
|
154
|
+
not any(
|
155
|
+
ImageRegionFinder.is_inside(bounds, r['bounds'])
|
156
|
+
for r in regions
|
157
|
+
)
|
158
|
+
):
|
159
|
+
regions.append({
|
160
|
+
'bounds': bounds,
|
161
|
+
'coordinates': region
|
162
|
+
})
|
163
|
+
|
164
|
+
# I want another format, so:
|
165
|
+
for index, region in enumerate(regions):
|
166
|
+
regions[index] = Region(region['bounds'][2], region['bounds'][0], region['bounds'][3], region['bounds'][1], region['coordinates'])
|
167
|
+
|
168
|
+
return regions
|
169
|
+
|
170
|
+
@staticmethod
|
171
|
+
def find_green_regions(
|
172
|
+
image: Union[str, Image.Image, np.ndarray]
|
173
|
+
) -> list[Region]:
|
174
|
+
"""
|
175
|
+
Get the green regions that exist in the provided
|
176
|
+
'image' (if existing), ignoring the ones whose
|
177
|
+
dimensions are below the MIN_REGION_SIZE constant.
|
178
|
+
"""
|
179
|
+
image = ImageParser.to_numpy(image, 'RGB')
|
180
|
+
|
181
|
+
return ImageRegionFinder.find_regions(image, PixelFilterFunction.is_green)
|
182
|
+
|
183
|
+
@staticmethod
|
184
|
+
def find_transparent_regions(
|
185
|
+
image: Union[str, Image.Image, np.ndarray]
|
186
|
+
) -> list[Region]:
|
187
|
+
"""
|
188
|
+
Get the transparent (alpha) regions that exist in
|
189
|
+
the provided 'image' (if existing), ignoring the
|
190
|
+
ones whose dimensions are below the MIN_REGION_SIZE
|
191
|
+
constant.
|
192
|
+
"""
|
193
|
+
image = ImageParser.to_numpy(image, 'RGBA')
|
194
|
+
|
195
|
+
return ImageRegionFinder.find_regions(image, PixelFilterFunction.is_transparent)
|
196
|
+
|
197
|
+
|
198
|
+
|
199
|
+
|
200
|
+
|
201
|
+
|
202
|
+
|
203
|
+
|
204
|
+
|
205
|
+
# TODO: This below need work, is using a HSV mask to
|
206
|
+
# recognize regions, but this is actually a new class
|
207
|
+
# to bring functionality from 'yta_general_utils'
|
208
|
+
|
209
|
+
class RegionFinderTest:
|
210
|
+
|
211
|
+
@staticmethod
|
212
|
+
def detect_regions(image, low_range, high_range):
|
213
|
+
# Convertir la imagen de BGR a HSV
|
214
|
+
imagen_hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
215
|
+
|
216
|
+
# Crear una máscara con los píxeles que están dentro del rango de color
|
217
|
+
mascara = cv2.inRange(imagen_hsv, low_range, high_range)
|
218
|
+
|
219
|
+
# Encontrar los contornos de las regiones detectadas
|
220
|
+
contornos, _ = cv2.findContours(mascara, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
221
|
+
|
222
|
+
# Dibujar los contornos sobre la imagen original
|
223
|
+
imagen_contornos = image.copy()
|
224
|
+
for contorno in contornos:
|
225
|
+
if cv2.contourArea(contorno) > 100: # Filtrar contornos pequeños
|
226
|
+
cv2.drawContours(imagen_contornos, [contorno], -1, (0, 255, 0), 2)
|
227
|
+
|
228
|
+
return imagen_contornos, mascara
|
229
|
+
|
230
|
+
@staticmethod
|
231
|
+
def test():
|
232
|
+
imagen = cv2.imread('imagen.jpg')
|
233
|
+
|
234
|
+
# Definir el rango de color en HSV (por ejemplo, un verde brillante)
|
235
|
+
rango_bajo = np.array([35, 50, 50]) # El valor mínimo del verde en HSV
|
236
|
+
rango_alto = np.array([85, 255, 255]) # El valor máximo del verde en HSV
|
237
|
+
|
238
|
+
# Llamar a la función para detectar las regiones del color
|
239
|
+
imagen_contornos, mascara = RegionFinderTest.detect_regions(imagen, rango_bajo, rango_alto)
|
240
|
+
|
241
|
+
# Mostrar los resultados
|
242
|
+
cv2.imshow('Regiones Detectadas', imagen_contornos)
|
243
|
+
cv2.imshow('Máscara', mascara)
|
244
|
+
|
245
|
+
# Esperar a que se presione una tecla para cerrar las ventanas
|
246
|
+
cv2.waitKey(0)
|
247
|
+
cv2.destroyAllWindows()
|
248
|
+
|
yta_image_base/size.py
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
from yta_image_base.parser import ImageParser
|
2
|
+
# TODO: Get this method from other library
|
3
|
+
from yta_multimedia.utils.resize import get_cropping_points_to_keep_aspect_ratio
|
4
|
+
from yta_constants.file import FileExtension
|
5
|
+
from yta_programming.output import Output
|
6
|
+
# TODO: I should avoid using this FileReturn
|
7
|
+
from yta_general_utils.dataclasses import FileReturn
|
8
|
+
from PIL import Image
|
9
|
+
from typing import Union
|
10
|
+
|
11
|
+
import cv2
|
12
|
+
|
13
|
+
|
14
|
+
class ImageResizer:
|
15
|
+
"""
|
16
|
+
Class to resize images.
|
17
|
+
"""
|
18
|
+
|
19
|
+
@staticmethod
|
20
|
+
def resize(
|
21
|
+
image: Union[str, any],
|
22
|
+
size: tuple[int, int],
|
23
|
+
output_filename: Union[str, None] = None
|
24
|
+
) -> FileReturn:
|
25
|
+
"""
|
26
|
+
Resizes the image to the provided 'size' by cropping a
|
27
|
+
region of the given 'image' that fits the 'size' aspect
|
28
|
+
ratio and resizing that region to the 'size'.
|
29
|
+
|
30
|
+
This method is using the whole image and then resizing,
|
31
|
+
so the quality of the image is preserved and no small
|
32
|
+
regions are used. The most part of the image is
|
33
|
+
preserved.
|
34
|
+
|
35
|
+
This method returns the image modified.
|
36
|
+
|
37
|
+
This method will write the image if 'output_filename' is
|
38
|
+
provided.
|
39
|
+
"""
|
40
|
+
image = ImageParser.to_pillow(image)
|
41
|
+
|
42
|
+
# TODO: Maybe move the method to another library (?)
|
43
|
+
top_left, bottom_right = get_cropping_points_to_keep_aspect_ratio(image.size, size)
|
44
|
+
image = image.crop((top_left[0], top_left[1], bottom_right[0], bottom_right[1]))
|
45
|
+
image = image.resize(size)
|
46
|
+
|
47
|
+
if output_filename is not None:
|
48
|
+
output_filename = Output.get_filename(output_filename, FileExtension.PNG)
|
49
|
+
image.save(output_filename)
|
50
|
+
|
51
|
+
return FileReturn(
|
52
|
+
image,
|
53
|
+
output_filename
|
54
|
+
)
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
# TODO: This below is so raw... remove if
|
60
|
+
# no longer used and replaceable with others
|
61
|
+
def resize_scaling(image_filename, width, height, output_filename = None):
|
62
|
+
"""
|
63
|
+
Resizes the provided 'image_filename' to the provided 'width' and 'height' keeping the
|
64
|
+
aspect ratio. This method enlarges the image to fit the desired size and then makes a
|
65
|
+
crop to obtain that size from the center of the resized image. If 'output_filename' is
|
66
|
+
provided, the image is saved locally with that name.
|
67
|
+
"""
|
68
|
+
image = Image.open(image_filename)
|
69
|
+
image_width, image_height = image.size
|
70
|
+
|
71
|
+
if image_width == width and image_height == height:
|
72
|
+
return image.save(output_filename)
|
73
|
+
|
74
|
+
aspect_ratio = image_width / image_height
|
75
|
+
if aspect_ratio > (width / height):
|
76
|
+
# Image is very horizontal, so width changes faster, we need to focus on height
|
77
|
+
factor = (height * 100 / image_height) / 100
|
78
|
+
image_width = int(image_width * factor)
|
79
|
+
image_height = height
|
80
|
+
else:
|
81
|
+
# Image is very vertical, so height changes faster, we need to focus on width
|
82
|
+
factor = (width * 100 / image_width) / 100
|
83
|
+
image_width = 1920
|
84
|
+
image_height = int(image_height * factor)
|
85
|
+
image = image.resize((image_width, image_height))
|
86
|
+
|
87
|
+
# We will crop form the center to edges
|
88
|
+
left = 0
|
89
|
+
right = width
|
90
|
+
top = 0
|
91
|
+
bottom = height
|
92
|
+
if image_width > width:
|
93
|
+
# If it is 1960 => leave [0, 20], get [20, 1940], leave [1940, 1960]
|
94
|
+
margin = int((image_width - width) / 2)
|
95
|
+
left = 0 + margin
|
96
|
+
right = image_width - margin
|
97
|
+
# We make and adjustment if some pixel left
|
98
|
+
while (right - left) > width:
|
99
|
+
right -= 1
|
100
|
+
while (right - left) < width:
|
101
|
+
if left > 0:
|
102
|
+
left -= 1
|
103
|
+
else:
|
104
|
+
right += 1
|
105
|
+
if image_height > height:
|
106
|
+
# If it is 1140 => leave [0, 30], get [30, 1110], leave [1110, 1140]
|
107
|
+
margin = int((image_height - height) / 2)
|
108
|
+
top = 0 + margin
|
109
|
+
bottom = image_height - margin
|
110
|
+
# We make and adjustment if some pixel left
|
111
|
+
while (bottom - top) > height:
|
112
|
+
bottom -= 1
|
113
|
+
while (bottom - top) < height:
|
114
|
+
if top > 0:
|
115
|
+
top -= 1
|
116
|
+
else:
|
117
|
+
bottom += 1
|
118
|
+
|
119
|
+
image = image.crop((left, top, right, bottom))
|
120
|
+
# Image that is 1920x1080 and is the center of the original image
|
121
|
+
if output_filename:
|
122
|
+
image.save(output_filename)
|
123
|
+
|
124
|
+
return image
|
125
|
+
|
126
|
+
def resize_without_scaling(image_filename, width = 1920, height = 1080):
|
127
|
+
"""
|
128
|
+
This method gets an image, resizes it and overwrites the original one.
|
129
|
+
|
130
|
+
TODO: This method need work.
|
131
|
+
"""
|
132
|
+
# TODO: We resize it simply, we don't care about scale
|
133
|
+
image = cv2.imread(image_filename)
|
134
|
+
resized_image = cv2.resize(image, dsize = (width, height), interpolation = cv2.INTER_CUBIC)
|
135
|
+
cv2.imwrite(image_filename, resized_image)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2018 The Python Packaging Authority
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Metadata-Version: 2.3
|
2
|
+
Name: yta-image-base
|
3
|
+
Version: 0.0.1
|
4
|
+
Summary: Youtube Autonomous Image Base Module.
|
5
|
+
Author: danialcala94
|
6
|
+
Author-email: danielalcalavalera@gmail.com
|
7
|
+
Requires-Python: ==3.9
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
10
|
+
Requires-Dist: numpy (>=1.23.5,<2.0.0)
|
11
|
+
Requires-Dist: opencv-python (>=4.11.0.86,<5.0.0.0)
|
12
|
+
Requires-Dist: pillow (>=9.5.0,<10.0.0)
|
13
|
+
Requires-Dist: yta_constants (>=0.0.1,<1.0.0)
|
14
|
+
Requires-Dist: yta_file (>=0.0.1,<1.0.0)
|
15
|
+
Requires-Dist: yta_programming (>=0.0.1,<1.0.0)
|
16
|
+
Requires-Dist: yta_temp (>=0.0.1,<1.0.0)
|
17
|
+
Requires-Dist: yta_validation (>=0.0.1,<1.0.0)
|
18
|
+
Description-Content-Type: text/markdown
|
19
|
+
|
20
|
+
# Youtube Autonomous Audio Editor Module
|
21
|
+
|
22
|
+
The Audio editor module.
|
23
|
+
|
24
|
+
Please, check the 'pyproject.toml' file to see the dependencies.
|
@@ -0,0 +1,16 @@
|
|
1
|
+
yta_image_base/__init__.py,sha256=adJ0wH4CVSHCXwlvbcl7BMV9Xy8JuEsLgYjBr3uIGug,8715
|
2
|
+
yta_image_base/background.py,sha256=8Vbe_fcaKrW2E5w3zf4URN5iUlU4VEjxzh3Gp2bDpSY,3136
|
3
|
+
yta_image_base/color/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
+
yta_image_base/color/picker.py,sha256=uPgFQVS4dE36EF_bxJsFxhqe8Z9M1xR_YpDDtU_1mHA,5712
|
5
|
+
yta_image_base/converter.py,sha256=83fK4yMarkQ4hEkBMzzvKrozyFfmlUpl6yzspB3YAuY,9222
|
6
|
+
yta_image_base/edition/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
+
yta_image_base/edition/editor.py,sha256=fRd3qZInOUfPyMbzktc877iqeSVrTZw43f4EhfBwdzE,13477
|
8
|
+
yta_image_base/edition/settings.py,sha256=N3NSxlc7NBZbB9R-Uv8GkgJU_TvjNTSgpw5bXF11YDc,577
|
9
|
+
yta_image_base/parser.py,sha256=5GGDBxpqyjzM95sGtxaQ259LnCmYxxs1BJtvkhDuMj0,5090
|
10
|
+
yta_image_base/region/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
+
yta_image_base/region/finder.py,sha256=-R2EV0sw-74ltEeAbO3VLIjzfWKGWNQdvsVb_ucSI8U,8859
|
12
|
+
yta_image_base/size.py,sha256=q_Q26CV_iVsb1yWDfCnDANlJ-zTNR-b1Ac-j8207WGE,4858
|
13
|
+
yta_image_base-0.0.1.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
|
14
|
+
yta_image_base-0.0.1.dist-info/METADATA,sha256=wpac1WKMTa6_Jkz3MOQrWq66QX2CDYISDjgj0h9f0W0,818
|
15
|
+
yta_image_base-0.0.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
16
|
+
yta_image_base-0.0.1.dist-info/RECORD,,
|