yta-editor-utils 0.0.1__tar.gz

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.
@@ -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,19 @@
1
+ Metadata-Version: 2.4
2
+ Name: yta-editor-utils
3
+ Version: 0.0.1
4
+ Summary: Youtube Autonomous Main Editor Utils module
5
+ License-File: LICENSE
6
+ Author: danialcala94
7
+ Author-email: danielalcalavalera@gmail.com
8
+ Requires-Python: ==3.9
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Requires-Dist: moderngl (>=0.0.1,<9.0.0)
12
+ Requires-Dist: numpy (>=0.0.1,<9.0.0)
13
+ Requires-Dist: yta_programming (>=0.0.1,<1.0.0)
14
+ Requires-Dist: yta_validation (>=0.0.1,<1.0.0)
15
+ Description-Content-Type: text/markdown
16
+
17
+ # Youtube Autonomous Main Editor Utils module
18
+
19
+ The utils to share in between the different libraries related to the main editor.
@@ -0,0 +1,3 @@
1
+ # Youtube Autonomous Main Editor Utils module
2
+
3
+ The utils to share in between the different libraries related to the main editor.
@@ -0,0 +1,33 @@
1
+ [project]
2
+ name = "yta-editor-utils"
3
+ version = "0.0.1"
4
+ description = "Youtube Autonomous Main Editor Utils module"
5
+ authors = [
6
+ {name = "danialcala94",email = "danielalcalavalera@gmail.com"}
7
+ ]
8
+ readme = "README.md"
9
+ requires-python = "==3.9"
10
+ dependencies = [
11
+ "yta_validation (>=0.0.1,<1.0.0)",
12
+ "yta_programming (>=0.0.1,<1.0.0)",
13
+ "moderngl (>=0.0.1,<9.0.0)",
14
+ "numpy (>=0.0.1,<9.0.0)",
15
+ ]
16
+
17
+ [tool.poetry]
18
+ packages = [{include = "yta_editor_utils", from = "src"}]
19
+
20
+ [tool.poetry.group.dev.dependencies]
21
+ pytest = "^8.3.5"
22
+ yta_testing = ">=0.0.1"
23
+
24
+ [tool.poetry.group.optional]
25
+ optional = true
26
+
27
+ [tool.poetry.group.optional.dependencies]
28
+ pillow = ">=0.0.1"
29
+ opencv-python = ">=0.0.1"
30
+
31
+ [build-system]
32
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
33
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1,235 @@
1
+ """
2
+ This is the utils module related to the main
3
+ editor.
4
+ """
5
+ from yta_validation import PythonValidator
6
+ from yta_programming.decorators.requires_dependency import requires_dependency
7
+ from typing import Union
8
+
9
+ import numpy as np
10
+ import moderngl
11
+
12
+
13
+ def frame_to_texture(
14
+ frame: Union['VideoFrame', 'np.ndarray'],
15
+ context: moderngl.Context,
16
+ numpy_format: str = 'rgb24'
17
+ ):
18
+ """
19
+ Transform the given 'frame' to an opengl
20
+ texture. The frame can be a VideoFrame
21
+ instance (from pyav library) or a numpy
22
+ array.
23
+
24
+ (!) This method is useful to transform a
25
+ frame into a texture quick and for a single
26
+ use, but we have the GPUTextureHandler class
27
+ to handle it in an specific contexto to
28
+ optimize the performance and avoid creating
29
+ textures but rewriting on them.
30
+ """
31
+ # To numpy RGB inverted for opengl
32
+ frame: np.ndarray = (
33
+ np.flipud(frame.to_ndarray(format = numpy_format))
34
+ if PythonValidator.is_instance_of(frame, 'VideoFrame') else
35
+ np.flipud(frame)
36
+ )
37
+
38
+ # Sometimes we have 'float32' values but we need to
39
+ # force 'uint8' to be able to work with
40
+ if frame.dtype != np.uint8:
41
+ frame = np.clip(frame, 0, 255).astype(np.uint8)
42
+
43
+ return context.texture(
44
+ size = (frame.shape[1], frame.shape[0]),
45
+ components = frame.shape[2],
46
+ data = frame.tobytes()
47
+ )
48
+
49
+ # TODO: I should make different methods to
50
+ # obtain a VideoFrame or a numpy array frame
51
+ def texture_to_frame(
52
+ texture: moderngl.Texture,
53
+ do_include_alpha: bool = True
54
+ ) -> np.ndarray:
55
+ """
56
+ Transform an opengl texture into numpy array.
57
+
58
+ The `do_include_alpha` will include the
59
+ alpha channel if True.
60
+ """
61
+ data = texture.read(alignment = 1)
62
+ # Read 4 channels always (RGBA8)
63
+ frame = np.frombuffer(data, dtype = np.uint8).reshape((texture.size[1], texture.size[0], 4))
64
+ # TODO: Do this with a utils
65
+ frame = (
66
+ frame
67
+ if do_include_alpha else
68
+ # Discard alpha channel if not needed
69
+ frame[:, :, :3]
70
+ )
71
+ # Opengl gives it with the 'y' inverted
72
+ frame = np.flipud(frame)
73
+ # TODO: This can be returned as a numpy frame
74
+
75
+ # This is if we need an 'av' VideoFrame (to
76
+ # export through the demuxer, for example)
77
+ # TODO: I avoid this by now because we don't
78
+ # want to import the pyav library, so this
79
+ # below has to be done with the numpy array
80
+ # received...
81
+ # frame = av.VideoFrame.from_ndarray(frame, format = 'rgba')
82
+ # # TODO: Make this customizable
83
+ # frame = frame.reformat(format = 'yuv420p')
84
+
85
+ return frame
86
+
87
+ # TODO: The code of this one is similar to the
88
+ # 'texture_to_frame', so we should keep only one
89
+ # (maybe this one)
90
+ def texture_to_numpy(
91
+ texture: moderngl.Texture,
92
+ do_include_alpha: bool = True
93
+ ) -> np.ndarray:
94
+ """
95
+ Transform the provided OpenGL `texture` into a numpy
96
+ array to be able to validate the values that are
97
+ contained in the texture.
98
+
99
+ The alpha layer will be removed if the parameter
100
+ `do_include_alpha` is set as False.
101
+ """
102
+ data = texture.read()
103
+
104
+ # OpenGL uses only f4 and u1 for the textures so
105
+ # we don't need a mapping
106
+ dtype = (
107
+ np.float32
108
+ if texture.dtype == 'f4' else
109
+ np.uint8
110
+ )
111
+
112
+ frame = np.frombuffer(
113
+ buffer = data,
114
+ dtype = dtype
115
+ ).reshape(
116
+ texture.height,
117
+ texture.width,
118
+ texture.components
119
+ )
120
+
121
+ # Discard alpha channel if not needed
122
+ frame = (
123
+ frame
124
+ if do_include_alpha else
125
+ frame[:, :, :3]
126
+ )
127
+
128
+ # Opengl gives it with the 'y' inverted
129
+ frame = np.flipud(frame)
130
+
131
+ return frame
132
+
133
+ # TODO: I think I have this methods in other library
134
+ # maybe yta-image-utils (?)
135
+ @requires_dependency('cv2', 'yta_video_opengl', 'opencv-python')
136
+ def scale_numpy(
137
+ input: np.ndarray,
138
+ size: tuple[int, int]
139
+ ) -> np.ndarray:
140
+ """
141
+ *Optional dependency `opencv-python` required*
142
+
143
+ Resize the 'input' numpy array to the provided 'size'
144
+ if needed, using a rescaling method with 'opencv-python'
145
+ (cv2).
146
+
147
+ The 'size' provided must be (width, height).
148
+ """
149
+ import cv2
150
+
151
+ return cv2.resize(input, size, interpolation = cv2.INTER_LINEAR)
152
+
153
+ @requires_dependency('PIL', 'yta_video_opengl', 'pillow')
154
+ def scale_numpy_pillow(
155
+ input: np.ndarray,
156
+ size: tuple[int, int]
157
+ ) -> np.ndarray:
158
+ """
159
+ *Optional dependency `pillow` (imported as `PIL`) required*
160
+
161
+ Resize the 'input' numpy array to the provided 'size'
162
+ if needed, using a rescaling method with 'pillow'
163
+ (PIL).
164
+
165
+ The 'size' provided must be (width, height).
166
+ """
167
+ from PIL import Image
168
+
169
+ return np.array(Image.fromarray(input).resize(size, Image.BILINEAR))
170
+
171
+ @requires_dependency('PIL', 'yta_video_opengl', 'pillow')
172
+ def read_image_as_numpy(
173
+ path: str,
174
+ do_read_as_rgba: bool = True,
175
+ size: Union[tuple[int, int], None] = None
176
+ ) -> np.ndarray:
177
+ """
178
+ *Optional dependency `pillow` (imported as `PIL`) required*
179
+
180
+ Read an image from a file and transform it into a
181
+ numpy array. It will force the 'size' if provided,
182
+ or leave the original one if it is None.
183
+ """
184
+ from PIL import Image
185
+
186
+ mode = (
187
+ 'RGBA'
188
+ if do_read_as_rgba else
189
+ 'RGB'
190
+ )
191
+
192
+ with Image.open(path) as img:
193
+ img = img.convert(mode)
194
+ np_img = np.array(img, dtype = np.uint8)
195
+
196
+ return (
197
+ scale_numpy_pillow(
198
+ input = np_img,
199
+ size = size
200
+ ) if size is not None else
201
+ np_img
202
+ )
203
+
204
+ @requires_dependency('PIL', 'yta_video_opengl', 'pillow')
205
+ def numpy_to_file(
206
+ input: np.ndarray,
207
+ output_filename: str
208
+ ) -> str:
209
+ """
210
+ *Optional dependency `pillow` (imported as `PIL`) required*
211
+
212
+ Export the provided 'array' numpy array as a file
213
+ with the given 'output_filename' name.
214
+ """
215
+ from PIL import Image
216
+
217
+ Image.fromarray(input).save(output_filename)
218
+
219
+ return output_filename
220
+
221
+ @requires_dependency('PIL', 'yta_video_opengl', 'pillow')
222
+ def texture_to_file(
223
+ texture: 'moderngl.Texture',
224
+ output_filename: str
225
+ ) -> str:
226
+ """
227
+ *Optional dependency `pillow` (imported as `PIL`) required*
228
+
229
+ Export the provided OpenGL texture 'texture' as a
230
+ file with the given 'output_filename' name.
231
+ """
232
+ return numpy_to_file(
233
+ input = texture_to_frame(texture),
234
+ output_filename = output_filename
235
+ )