siss 0.1.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.
- siss-0.1.0.dist-info/METADATA +29 -0
- siss-0.1.0.dist-info/RECORD +8 -0
- siss-0.1.0.dist-info/WHEEL +5 -0
- siss-0.1.0.dist-info/entry_points.txt +2 -0
- siss-0.1.0.dist-info/licenses/LICENSE +21 -0
- siss-0.1.0.dist-info/top_level.txt +1 -0
- utils/__init__.py +3 -0
- utils/video_processing.py +226 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: siss
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A command-line utility for applying artistic effects to videos
|
|
5
|
+
Home-page: https://github.com/MichailSemoglou/siss
|
|
6
|
+
Author: Michail Semoglou
|
|
7
|
+
Author-email: m.semoglou@tongji.edu.cn
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Topic :: Multimedia :: Video
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Requires-Python: >=3.6
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: opencv-python>=4.5.0
|
|
20
|
+
Requires-Dist: numpy>=1.20.0
|
|
21
|
+
Requires-Dist: tqdm>=4.60.0
|
|
22
|
+
Dynamic: author
|
|
23
|
+
Dynamic: author-email
|
|
24
|
+
Dynamic: classifier
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
Dynamic: requires-dist
|
|
28
|
+
Dynamic: requires-python
|
|
29
|
+
Dynamic: summary
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
siss-0.1.0.dist-info/licenses/LICENSE,sha256=EV4Gnsw0m4vG_pBZ_lEEjxqvjtLQhsFwYTRpghuQQJ0,1073
|
|
2
|
+
utils/__init__.py,sha256=TlVhlzfVc5kZ00IZsqXnkip0zimCYX42SVREmYo6_WQ,34
|
|
3
|
+
utils/video_processing.py,sha256=egB-8JdNr14XEpJaK9F8jpfFaJj4l2bMXxDcCrkYXLo,6453
|
|
4
|
+
siss-0.1.0.dist-info/METADATA,sha256=pIYJrMntwUHKp-6naH6hdlqTmx1iZfw-vgdZeCxKssk,965
|
|
5
|
+
siss-0.1.0.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
|
|
6
|
+
siss-0.1.0.dist-info/entry_points.txt,sha256=PS4XNV3ztvrHjdFFemElxT6dg8Ov9T1pcpLalSD3Czg,39
|
|
7
|
+
siss-0.1.0.dist-info/top_level.txt,sha256=BXdhaaHBJTl5WDScj-NdcpdW6F1g7hNN3YP0CLPxk-0,6
|
|
8
|
+
siss-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Michail Semoglou
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
utils
|
utils/__init__.py
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utility functions for video processing operations.
|
|
3
|
+
|
|
4
|
+
This module provides helper functions for common video operations like
|
|
5
|
+
loading videos, extracting frames, and saving processed results.
|
|
6
|
+
"""
|
|
7
|
+
import cv2
|
|
8
|
+
import numpy as np
|
|
9
|
+
import os
|
|
10
|
+
from tqdm import tqdm
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_codec_for_file(output_path):
|
|
14
|
+
"""
|
|
15
|
+
Determine the appropriate codec based on the file extension.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
output_path (str): Path where the video will be saved
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
str: Four character codec code
|
|
22
|
+
"""
|
|
23
|
+
# Get file extension (lowercase)
|
|
24
|
+
_, ext = os.path.splitext(output_path)
|
|
25
|
+
ext = ext.lower()
|
|
26
|
+
|
|
27
|
+
# Map extensions to codecs
|
|
28
|
+
codec_map = {
|
|
29
|
+
'.avi': 'XVID',
|
|
30
|
+
'.mp4': 'mp4v', # H.264 codec
|
|
31
|
+
'.mov': 'mp4v', # H.264 codec for MOV container
|
|
32
|
+
'.mkv': 'X264',
|
|
33
|
+
'.wmv': 'WMV2',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# Default to mp4v if extension not found
|
|
37
|
+
return codec_map.get(ext, 'mp4v')
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def load_video(video_path):
|
|
41
|
+
"""
|
|
42
|
+
Load a video file and return a VideoCapture object.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
video_path (str): Path to the video file
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
cv2.VideoCapture: OpenCV VideoCapture object
|
|
49
|
+
|
|
50
|
+
Raises:
|
|
51
|
+
FileNotFoundError: If the video file cannot be opened
|
|
52
|
+
"""
|
|
53
|
+
video_capture = cv2.VideoCapture(video_path)
|
|
54
|
+
if not video_capture.isOpened():
|
|
55
|
+
raise FileNotFoundError(f"Cannot open video file: {video_path}")
|
|
56
|
+
return video_capture
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def get_video_properties(video_capture):
|
|
60
|
+
"""
|
|
61
|
+
Get properties of a video.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
video_capture (cv2.VideoCapture): OpenCV VideoCapture object
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
dict: Dictionary with video properties (fps, width, height, frame_count)
|
|
68
|
+
"""
|
|
69
|
+
properties = {
|
|
70
|
+
'fps': video_capture.get(cv2.CAP_PROP_FPS),
|
|
71
|
+
'width': int(video_capture.get(cv2.CAP_PROP_FRAME_WIDTH)),
|
|
72
|
+
'height': int(video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT)),
|
|
73
|
+
'frame_count': int(video_capture.get(cv2.CAP_PROP_FRAME_COUNT))
|
|
74
|
+
}
|
|
75
|
+
return properties
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def extract_frames(video_capture, show_progress=True):
|
|
79
|
+
"""
|
|
80
|
+
Extract all frames from a video.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
video_capture (cv2.VideoCapture): OpenCV VideoCapture object
|
|
84
|
+
show_progress (bool): Whether to show a progress bar
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
list: List of frames as numpy arrays
|
|
88
|
+
"""
|
|
89
|
+
frames = []
|
|
90
|
+
|
|
91
|
+
# Get frame count for progress bar
|
|
92
|
+
frame_count = int(video_capture.get(cv2.CAP_PROP_FRAME_COUNT))
|
|
93
|
+
|
|
94
|
+
# Create progress bar if requested
|
|
95
|
+
if show_progress:
|
|
96
|
+
progress_bar = tqdm(total=frame_count, desc="Extracting frames")
|
|
97
|
+
|
|
98
|
+
while True:
|
|
99
|
+
ret, frame = video_capture.read()
|
|
100
|
+
if not ret:
|
|
101
|
+
break
|
|
102
|
+
frames.append(frame)
|
|
103
|
+
|
|
104
|
+
# Update progress bar
|
|
105
|
+
if show_progress:
|
|
106
|
+
progress_bar.update(1)
|
|
107
|
+
|
|
108
|
+
# Close progress bar
|
|
109
|
+
if show_progress:
|
|
110
|
+
progress_bar.close()
|
|
111
|
+
|
|
112
|
+
return frames
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def save_video(output_path, frames, fps, show_progress=True):
|
|
116
|
+
"""
|
|
117
|
+
Save a list of frames as a video file.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
output_path (str): Path where the video will be saved
|
|
121
|
+
frames (list): List of frames as numpy arrays
|
|
122
|
+
fps (float): Frames per second for the output video
|
|
123
|
+
show_progress (bool): Whether to show a progress bar
|
|
124
|
+
|
|
125
|
+
Raises:
|
|
126
|
+
ValueError: If no frames are provided
|
|
127
|
+
"""
|
|
128
|
+
if not frames:
|
|
129
|
+
raise ValueError("No frames to save.")
|
|
130
|
+
|
|
131
|
+
height, width, _ = frames[0].shape
|
|
132
|
+
codec = get_codec_for_file(output_path)
|
|
133
|
+
fourcc = cv2.VideoWriter_fourcc(*codec)
|
|
134
|
+
video_writer = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
|
|
135
|
+
|
|
136
|
+
# Create progress bar if requested
|
|
137
|
+
if show_progress:
|
|
138
|
+
progress_bar = tqdm(total=len(frames), desc="Saving video")
|
|
139
|
+
|
|
140
|
+
for frame in frames:
|
|
141
|
+
video_writer.write(frame)
|
|
142
|
+
|
|
143
|
+
# Update progress bar
|
|
144
|
+
if show_progress:
|
|
145
|
+
progress_bar.update(1)
|
|
146
|
+
|
|
147
|
+
# Close progress bar
|
|
148
|
+
if show_progress:
|
|
149
|
+
progress_bar.close()
|
|
150
|
+
|
|
151
|
+
video_writer.release()
|
|
152
|
+
print(f"Video saved to {output_path}")
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def process_video_frames(video_path, output_path, process_function, **kwargs):
|
|
156
|
+
"""
|
|
157
|
+
Process a video by applying a function to each frame.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
video_path (str): Path to the input video
|
|
161
|
+
output_path (str): Path where processed video will be saved
|
|
162
|
+
process_function (callable): Function to apply to each frame
|
|
163
|
+
The function should take a frame and return a processed frame
|
|
164
|
+
**kwargs: Additional arguments to pass to the process_function
|
|
165
|
+
|
|
166
|
+
Example:
|
|
167
|
+
def grayscale(frame):
|
|
168
|
+
return cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
|
169
|
+
|
|
170
|
+
process_video_frames('input.mp4', 'output.mp4', grayscale)
|
|
171
|
+
"""
|
|
172
|
+
# Load video
|
|
173
|
+
cap = load_video(video_path)
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
# Get video properties
|
|
177
|
+
props = get_video_properties(cap)
|
|
178
|
+
|
|
179
|
+
# Create output video writer with appropriate codec
|
|
180
|
+
codec = get_codec_for_file(output_path)
|
|
181
|
+
fourcc = cv2.VideoWriter_fourcc(*codec)
|
|
182
|
+
out = cv2.VideoWriter(output_path, fourcc, props['fps'],
|
|
183
|
+
(props['width'], props['height']))
|
|
184
|
+
|
|
185
|
+
# Process frames with progress bar
|
|
186
|
+
progress_bar = tqdm(total=props['frame_count'], desc="Processing frames")
|
|
187
|
+
|
|
188
|
+
while True:
|
|
189
|
+
ret, frame = cap.read()
|
|
190
|
+
if not ret:
|
|
191
|
+
break
|
|
192
|
+
|
|
193
|
+
# Apply processing function
|
|
194
|
+
processed_frame = process_function(frame, **kwargs)
|
|
195
|
+
|
|
196
|
+
# Write processed frame
|
|
197
|
+
out.write(processed_frame)
|
|
198
|
+
|
|
199
|
+
# Update progress
|
|
200
|
+
progress_bar.update(1)
|
|
201
|
+
|
|
202
|
+
# Close progress bar
|
|
203
|
+
progress_bar.close()
|
|
204
|
+
|
|
205
|
+
print(f"Processed video saved to {output_path}")
|
|
206
|
+
|
|
207
|
+
finally:
|
|
208
|
+
# Release resources
|
|
209
|
+
cap.release()
|
|
210
|
+
if 'out' in locals():
|
|
211
|
+
out.release()
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def release_resources(video_capture, video_writer=None):
|
|
215
|
+
"""
|
|
216
|
+
Release video resources.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
video_capture (cv2.VideoCapture): OpenCV VideoCapture object
|
|
220
|
+
video_writer (cv2.VideoWriter, optional): OpenCV VideoWriter object
|
|
221
|
+
"""
|
|
222
|
+
if video_capture is not None:
|
|
223
|
+
video_capture.release()
|
|
224
|
+
|
|
225
|
+
if video_writer is not None:
|
|
226
|
+
video_writer.release()
|