hAmAruKi commited on
Commit
6ed89af
1 Parent(s): 42a71ed

update files

Browse files
.gitattributes ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.png filter=lfs diff=lfs merge=lfs -text
2
+ *.7z filter=lfs diff=lfs merge=lfs -text
3
+ *.arrow filter=lfs diff=lfs merge=lfs -text
4
+ *.bin filter=lfs diff=lfs merge=lfs -text
5
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
6
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
7
+ *.ftz filter=lfs diff=lfs merge=lfs -text
8
+ *.gz filter=lfs diff=lfs merge=lfs -text
9
+ *.h5 filter=lfs diff=lfs merge=lfs -text
10
+ *.joblib filter=lfs diff=lfs merge=lfs -text
11
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
12
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
13
+ *.model filter=lfs diff=lfs merge=lfs -text
14
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
15
+ *.npy filter=lfs diff=lfs merge=lfs -text
16
+ *.npz filter=lfs diff=lfs merge=lfs -text
17
+ *.onnx filter=lfs diff=lfs merge=lfs -text
18
+ *.ot filter=lfs diff=lfs merge=lfs -text
19
+ *.parquet filter=lfs diff=lfs merge=lfs -text
20
+ *.pb filter=lfs diff=lfs merge=lfs -text
21
+ *.pickle filter=lfs diff=lfs merge=lfs -text
22
+ *.pkl filter=lfs diff=lfs merge=lfs -text
23
+ *.pt filter=lfs diff=lfs merge=lfs -text
24
+ *.pth filter=lfs diff=lfs merge=lfs -text
25
+ *.rar filter=lfs diff=lfs merge=lfs -text
26
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
27
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
29
+ *.tar filter=lfs diff=lfs merge=lfs -text
30
+ *.tflite filter=lfs diff=lfs merge=lfs -text
31
+ *.tgz filter=lfs diff=lfs merge=lfs -text
32
+ *.wasm filter=lfs diff=lfs merge=lfs -text
33
+ *.xz filter=lfs diff=lfs merge=lfs -text
34
+ *.zip filter=lfs diff=lfs merge=lfs -text
35
+ *.zst filter=lfs diff=lfs merge=lfs -text
36
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.github/workflows/run.yaml ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Sync to Hugging Face hub
2
+ on:
3
+ push:
4
+ branches: [main]
5
+
6
+ # to run this workflow manually from the Actions tab
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ sync-to-hub:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v3
14
+ with:
15
+ fetch-depth: 0
16
+ lfs: true
17
+ - name: Push to hub
18
+ env:
19
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
20
+ run: git push --force https://MakiAi:$HF_TOKEN@huggingface.co/spaces/MakiAi/Image2VideoProcessingPipelin main
.gitignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ image/*
2
+ *.mp4
3
+ modules/__pycache__
4
+ modules/Transition/__pycache__/
5
+ modules/utils/__pycache__/
6
+ _tmp/
7
+ __pycache__/
README.md ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Image to Video Processing Pipelin
3
+ emoji: 🎥
4
+ colorFrom: green
5
+ colorTo: red
6
+ sdk: gradio
7
+ sdk_version: 3.41.2
8
+ app_file: app.py
9
+ pinned: false
10
+ license: apache-2.0
11
+ ---
12
+
13
+ # VideoProcessingPipeline(SNS投稿動画生成ツール)
14
+
15
+ SNSの投稿は、画像よりも動画の方が注目を集めやすいことが多いです。しかし、動画を作成するのは手間がかかるもの。そこで、手持ちの画像から自動で魅力的な動画を生成する方法をご紹介します。
16
+
17
+ ![](https://hamaruki.com/wp-content/uploads/2023/09/00028-1365031933-1-576x1024.png)
18
+
19
+
20
+ ## 概要
21
+
22
+ ### ステップ1: 必要なツールの準備
23
+ - Python環境
24
+ - OpenCV
25
+ - PIL (Pillow)
26
+
27
+ これらはpipを使って簡単にインストールできます。
28
+
29
+ ```bash
30
+
31
+ pip install opencv-python pillow
32
+ ```
33
+
34
+
35
+ ### ステップ2: 画像の準備
36
+
37
+ まず、動画に変換したい画像を一つのフォルダにまとめます。このフォルダのパスを後で使用します。
38
+ ### ステップ3: 画像のブラー処理
39
+
40
+ 動画を作成する前に、画像にブラー効果を適用します。これにより、動画が洗練された雰囲気を持つようになります。
41
+
42
+ 以下のクラス、`BlurredBackgroundEmbedder`を使用して、画像にブラー効果を適用します。
43
+
44
+ ```python
45
+
46
+ processor = BlurredBackgroundEmbedder(r"path/to/your/image_folder")
47
+ processor.process_all_images()
48
+ ```
49
+
50
+
51
+ ### ステップ4: 動画の作成
52
+
53
+ ブラー処理された画像を使用して、動画を作成します。この動画は、画像が上から下にスクロールするアニメーションを持っています。
54
+
55
+ 以下のクラス、`FrameVideoCreator`を使用して動画を作成します。
56
+
57
+ ```python
58
+
59
+ video_creator = FrameVideoCreator()
60
+ video_creator.process_folder(r"path/to/your/image_folder_Blurred")
61
+ ```
62
+
63
+
64
+ ### ステップ5: 動画の連結
65
+
66
+ 複数の動画を一つに連結します。また、動画間の遷移はスムーズなアルファブレンドが適用されます。
67
+
68
+ ```python
69
+
70
+ merger = VideoMergerWithSmoothTransition()
71
+ input_folder_path = r"path/to/your/image_folder_Blurred_mov"
72
+ output_folder_path = f"{input_folder_path}_Final"
73
+ os.makedirs(output_folder_path, exist_ok=True)
74
+ output_video_path = os.path.join(output_folder_path, "concatenated_video.mp4")
75
+ merger.merge_videos(input_folder_path, output_video_path)
76
+ ```
77
+
78
+
79
+ ### ステップ6: 動画の確認
80
+
81
+ 出力フォルダに保存された動画を確認します。この動画をSNSにアップロードすることで、魅力的な投稿を簡単に作成できます。
82
+
83
+
84
+ ## 使用方法
85
+
86
+ `VideoProcessingPipeline`は、指定された画像フォルダ内の画像を処理し、動画を作成し、動画を連結する一連のタスクを実行するPythonクラスです。
87
+
88
+ ### クイックスタート
89
+
90
+ 1. まず、必要なモジュールをインポートします。
91
+
92
+ ```python
93
+
94
+ from modules.utils import v_image_blurred_utils
95
+ from modules.BlurredBackgroundEmbedder import BlurredBackgroundEmbedder
96
+ from modules.FrameVideoCreator import FrameVideoCreator
97
+ from modules.Transition.VideoMergerWithSmoothTransition import VideoMergerWithSmoothTransition
98
+ ```
99
+
100
+
101
+ 1. `VideoProcessingPipeline`クラスを初期化します。このとき、画像が格納されているフォルダのパスを引数として渡します。
102
+
103
+ ```python
104
+
105
+ pipeline = VideoProcessingPipeline(r"path/to/your/image_folder")
106
+ ```
107
+
108
+
109
+ 1. `execute_pipeline`メソッドを呼び出して、画像の処理、動画の作成、動画の連結を順番に実行します。
110
+
111
+ ```python
112
+
113
+ pipeline.execute_pipeline()
114
+ ```
115
+
116
+
117
+ ### 内部の動作
118
+ - **画像のブラー処理** : 画像にブラー効果を適用し、新しいフォルダに保存します。
119
+ - **動画の作成** : ブラー処理された画像から、上から下に移動するアニメーション効果を持つ動画を作成します。
120
+ - **動画の連結** : すべての動画を一つの動画に連結します。動画間の遷移はスムーズなアルファブレンドが適用されます。
121
+
122
+ ### 注意点
123
+ - 入力として渡される画像フォルダには、連結したい画像のみが含まれていることを確認してください。
124
+ - 生成される動画は、`image_folder_Blurred_mov_Final`という名前のフォルダに保存されます。
125
+
126
+
127
+ ## 解説サイト
128
+
129
+ 詳細な解説はこちら
130
+
131
+ https://hamaruki.com/automatically-generate-posted-videos-from-images/
132
+
133
+ ## まとめ
134
+
135
+ Pythonを使用して、手持ちの画像からSNSに投稿するための動画を簡単に自動生成する方法を学びました。この方法を活用すれば、視覚的に魅力的なSNSの投稿を簡単に作成できます。初心者の方でも、ステップを追って実行すれば、手軽に動画を生成できるので、ぜひ試してみてください。
act.bat ADDED
@@ -0,0 +1 @@
 
 
1
+ conda activate vImage2MOV2
app.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ from main import VideoProcessingPipeline
4
+ import shutil
5
+
6
+ def remove_temp_folder():
7
+ """一時的なフォルダを削除する関数"""
8
+ temp_dir = "_tmp/temp_uploaded_images"
9
+ if os.path.exists(temp_dir):
10
+ shutil.rmtree(temp_dir)
11
+
12
+ def process_uploaded_images(files):
13
+ # _tmpフォルダ内に一時的なフォルダを作成して、アップロードされた画像を保存
14
+ temp_folder = "_tmp/temp_uploaded_images"
15
+ os.makedirs(temp_folder, exist_ok=True)
16
+
17
+ for file in files:
18
+ # 新しい保存先のパスを生成
19
+ new_path = os.path.join(temp_folder, os.path.basename(file.name))
20
+ # ファイルを新しい場所にコピー
21
+ shutil.copy(file.name, new_path)
22
+
23
+ # VideoProcessingPipelineを実行
24
+ pipeline = VideoProcessingPipeline(temp_folder)
25
+ pipeline.execute_pipeline()
26
+
27
+ # 最終的に生成された動画のパスを返す
28
+ return os.path.join(pipeline.final_folder, "concatenated_video.mp4")
29
+
30
+ demo = gr.Interface(
31
+ process_uploaded_images,
32
+ gr.File(file_count=5, file_types=[".jpg", ".jpeg", ".png"]),
33
+ gr.Video(),
34
+ title="Image to Video Processing"
35
+ )
36
+
37
+ if __name__ == "__main__":
38
+ remove_temp_folder() # 起動時に一時的なフォルダを削除
39
+ demo.launch()
main.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image, ImageFilter
2
+ import random
3
+ import os
4
+ from pathlib import Path
5
+ import cv2
6
+ import numpy as np
7
+ from modules.utils import v_image_blurred_utils
8
+ from modules.BlurredBackgroundEmbedder import BlurredBackgroundEmbedder
9
+ from modules.FrameVideoCreator import FrameVideoCreator
10
+ from modules.Transition.VideoMergerWithSmoothTransition import VideoMergerWithSmoothTransition
11
+
12
+
13
+ class VideoProcessingPipeline:
14
+ def __init__(self, image_folder: str):
15
+ """
16
+ VideoProcessingPipeline クラスの初期化関数
17
+
18
+ 引数:
19
+ - image_folder: 画像が格納されているフォルダのパス
20
+ """
21
+ self.image_folder = image_folder
22
+ self.blurred_folder = f"{image_folder}_Blurred"
23
+ self.video_folder = f"{self.blurred_folder}_mov"
24
+ self.final_folder = f"{self.video_folder}_Final"
25
+
26
+ def process_images(self):
27
+ """
28
+ 画像のブラー処理を実行
29
+ """
30
+ processor = BlurredBackgroundEmbedder(self.image_folder)
31
+ processor.process_all_images()
32
+
33
+ def create_videos_from_images(self):
34
+ """
35
+ ブラー処理された画像から動画を作成
36
+ """
37
+ video_creator = FrameVideoCreator()
38
+ video_creator.process_folder(self.blurred_folder)
39
+
40
+ def merge_videos(self):
41
+ """
42
+ 生成された動画を連結
43
+ """
44
+ os.makedirs(self.final_folder, exist_ok=True)
45
+ output_video_path = os.path.join(self.final_folder, "concatenated_video.mp4")
46
+ merger = VideoMergerWithSmoothTransition()
47
+ merger.merge_videos(self.video_folder, output_video_path)
48
+
49
+ def execute_pipeline(self):
50
+ """
51
+ 画像の処理、動画の作成、動画の連結を順番に実行
52
+ """
53
+ self.process_images()
54
+ self.create_videos_from_images()
55
+ self.merge_videos()
56
+ print("Video processing completed!")
57
+
58
+ if __name__ == '__main__':
59
+ pipeline = VideoProcessingPipeline(r"image\The-Multifaceted-Dawn")
60
+ pipeline.execute_pipeline()
modules/BlurredBackgroundEmbedder.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image, ImageFilter
2
+ import random
3
+ import os
4
+ from pathlib import Path
5
+ import cv2
6
+ import numpy as np
7
+ from modules.utils import v_image_blurred_utils
8
+
9
+ class BlurredBackgroundEmbedder:
10
+ def __init__(self, input_folder: str, height: int = 2000):
11
+ """
12
+ ImageProcessor クラスの初期化関数
13
+
14
+ 引数:
15
+ - input_folder: 画像が保存されているフォルダのパス
16
+ - height: 出力画像の希望の高さ(デフォルトは2000ピクセル)
17
+ """
18
+ self.input_folder = input_folder
19
+ self.height = height
20
+ self.output_folder = input_folder + "_Blurred"
21
+
22
+ # 出力フォルダを作成
23
+ if not os.path.exists(self.output_folder):
24
+ os.makedirs(self.output_folder)
25
+
26
+ def process_all_images(self):
27
+ """
28
+ 指定されたフォルダ内のすべての画像を処理します。
29
+ """
30
+ image_files = [f for f in os.listdir(self.input_folder) if os.path.isfile(os.path.join(self.input_folder, f))]
31
+ print("self.input_folder")
32
+ print(self.input_folder)
33
+
34
+ for image_file in image_files:
35
+ input_image_path = os.path.join(self.input_folder, image_file)
36
+ output_image_path = os.path.join(self.output_folder, image_file)
37
+ v_image_blurred_utils.embed_image_on_blurred_background(input_image_path, output_image_path)
38
+
39
+ if __name__ == '__main__':
40
+ # クラスの使用例
41
+ processor = BlurredBackgroundEmbedder(r"image\Echoes-of-Creation")
42
+ processor.process_all_images()
modules/FrameVideoCreator.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image, ImageFilter
2
+ import random
3
+ import os
4
+ from pathlib import Path
5
+ import cv2
6
+ import numpy as np
7
+ from modules.utils import image_frame_generator
8
+
9
+ class FrameVideoCreator:
10
+ def __init__(self, fps: int = 30):
11
+ """
12
+ FrameVideoCreator クラスの初期化関数
13
+
14
+ 引数:
15
+ - fps: 動画のフレームレート (デフォルトは30FPS)
16
+ """
17
+ self.fps = fps
18
+
19
+ # 昇順(上から下)のエフェクトを初めに適用
20
+ self.ascending_order = True
21
+
22
+ def create_video_from_frames(self, frames: list, output_path: str):
23
+ """
24
+ 与えられた画像フレームのリストから動画を作成します。動画ごとに昇順と降順のエフェクトを交互に適用します。
25
+
26
+ 引数:
27
+ - frames: 画像フレームのリスト
28
+ - output_path: 保存する動画のパス
29
+ """
30
+ frames_bgr = [cv2.cvtColor(np.array(frame), cv2.COLOR_RGB2BGR) for frame in frames]
31
+
32
+ # 昇順か降順のエフェクトを適用するかに基づいて、フレームの順番を変更
33
+ if not self.ascending_order:
34
+ frames_bgr = list(reversed(frames_bgr))
35
+
36
+ # 次回の動画生成のためにエフェクトの順番を切り替え
37
+ self.ascending_order = not self.ascending_order
38
+
39
+ height, width, layers = frames_bgr[0].shape
40
+ size = (width, height)
41
+ out = cv2.VideoWriter(output_path, cv2.VideoWriter_fourcc(*'MP4V'), self.fps, size)
42
+
43
+ for frame in frames_bgr:
44
+ out.write(frame)
45
+
46
+ out.release()
47
+
48
+ def process_folder(self, input_folder: str):
49
+ """
50
+ 指定したフォルダ内の画像を処理し、動画を生成します。
51
+
52
+ 引数:
53
+ - input_folder: 画像が保存されているフォルダのパス
54
+ """
55
+ output_folder = f"{input_folder}_mov"
56
+ Path(output_folder).mkdir(parents=True, exist_ok=True)
57
+
58
+ for image_file in Path(input_folder).glob("*.png"):
59
+ frames = image_frame_generator.generate_centered_moving_frames(str(image_file))
60
+ output_video_path = Path(output_folder) / f"{image_file.stem}.mp4"
61
+ self.create_video_from_frames(frames, str(output_video_path))
62
+
63
+ if __name__ == '__main__':
64
+ # クラスの使用例
65
+ video_creator = FrameVideoCreator()
66
+ video_creator.process_folder(r"image/Echoes-of-Creation_Blurred")
modules/Transition/SimpleVideoMerger.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image, ImageFilter
2
+ import random
3
+ import os
4
+ from pathlib import Path
5
+ import cv2
6
+ import numpy as np
7
+
8
+
9
+ class SimpleVideoMerger:
10
+ def __init__(self, fps: int = 30):
11
+ self.fps = fps
12
+
13
+ def merge_videos(self, input_folder: str, output_filename: str):
14
+ video_files = [f for f in Path(input_folder).glob("*.mp4")]
15
+
16
+ if not video_files:
17
+ print("No video files found in the specified directory.")
18
+ return
19
+
20
+ videos = []
21
+
22
+ for video_file in video_files:
23
+ video = cv2.VideoCapture(str(video_file))
24
+ videos.append(video)
25
+
26
+ width = int(videos[0].get(cv2.CAP_PROP_FRAME_WIDTH))
27
+ height = int(videos[0].get(cv2.CAP_PROP_FRAME_HEIGHT))
28
+
29
+ fourcc = cv2.VideoWriter_fourcc(*'MP4V')
30
+ out = cv2.VideoWriter(output_filename, fourcc, self.fps, (width, height))
31
+
32
+ for i, video in enumerate(videos):
33
+ ret, frame = video.read()
34
+
35
+ while ret:
36
+ out.write(frame)
37
+ ret, frame = video.read()
38
+
39
+ video.release()
40
+
41
+ out.release()
42
+
43
+ print(f"Concatenated video saved to {output_filename}.")
44
+
45
+ if __name__ == '__main__':
46
+ # 使用例 (コメントアウトされています)
47
+ merger = SimpleVideoMerger()
48
+ input_folder_path = r"image\Echoes-of-Creation_Blurred_mov"
49
+ output_folder_path = f"{input_folder_path}_Final"
50
+ os.makedirs(output_folder_path, exist_ok=True)
51
+ output_video_path = os.path.join(output_folder_path, "concatenated_video.mp4")
52
+ merger.merge_videos(input_folder_path, output_video_path)
modules/Transition/VideoMergerWithSmoothTransition.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image, ImageFilter
2
+ import random
3
+ import os
4
+ from pathlib import Path
5
+ import cv2
6
+ import numpy as np
7
+
8
+ class VideoMergerWithSmoothTransition:
9
+ def __init__(self, fps: int = 30, transition_duration: float = 0.5):
10
+ self.fps = fps
11
+ self.transition_duration = transition_duration
12
+
13
+ def merge_videos(self, input_folder: str, output_filename: str):
14
+ video_files = [f for f in Path(input_folder).glob("*.mp4")]
15
+
16
+ if not video_files:
17
+ print("No video files found in the specified directory.")
18
+ return
19
+
20
+ videos = []
21
+
22
+ for video_file in video_files:
23
+ video = cv2.VideoCapture(str(video_file))
24
+ videos.append(video)
25
+
26
+ width = int(videos[0].get(cv2.CAP_PROP_FRAME_WIDTH))
27
+ height = int(videos[0].get(cv2.CAP_PROP_FRAME_HEIGHT))
28
+
29
+ fourcc = cv2.VideoWriter_fourcc(*'MP4V')
30
+ out = cv2.VideoWriter(output_filename, fourcc, self.fps, (width, height))
31
+
32
+ transition_frames_count = int(self.fps * self.transition_duration)
33
+
34
+ for i, video in enumerate(videos):
35
+ ret, prev_frame = video.read()
36
+
37
+ while ret:
38
+ if i < len(videos) - 1 and not video.get(cv2.CAP_PROP_POS_FRAMES) < video.get(cv2.CAP_PROP_FRAME_COUNT) - transition_frames_count:
39
+ alpha = (video.get(cv2.CAP_PROP_POS_FRAMES) - (video.get(cv2.CAP_PROP_FRAME_COUNT) - transition_frames_count)) / transition_frames_count
40
+ ret_next, next_frame = videos[i + 1].read()
41
+
42
+ if ret_next:
43
+ blended_frame = cv2.addWeighted(prev_frame, 1 - alpha, next_frame, alpha, 0)
44
+ out.write(blended_frame)
45
+ ret, prev_frame = video.read()
46
+ continue
47
+
48
+ out.write(prev_frame)
49
+ ret, prev_frame = video.read()
50
+
51
+ video.release()
52
+
53
+ out.release()
54
+
55
+ print(f"Concatenated video saved to {output_filename}.")
56
+
57
+ if __name__ == '__main__':
58
+ # 使用例 (コメントアウトされています)
59
+ merger = VideoMergerWithSmoothTransition()
60
+ input_folder_path = r"image\Echoes-of-Creation_Blurred_mov"
61
+ output_folder_path = f"{input_folder_path}_Final"
62
+ os.makedirs(output_folder_path, exist_ok=True)
63
+ output_video_path = os.path.join(output_folder_path, "concatenated_video.mp4")
64
+ merger.merge_videos(input_folder_path, output_video_path)
modules/utils/image_frame_generator.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image, ImageFilter
2
+ import random
3
+ import os
4
+ from pathlib import Path
5
+ import cv2
6
+ import numpy as np
7
+
8
+ def generate_centered_moving_frames(input_path: str, crop_width: int = 1620, crop_height: int = 2880, min_frames_required: int = 120):
9
+ """
10
+ 画像を上から下に移動させて、指定されたサイズでクロップしたフレームを生成します。
11
+ クロップは画像の中心を基準に行います。
12
+
13
+ 引数:
14
+ - input_path: 入力画像のパス
15
+ - crop_width: クロップする幅
16
+ - crop_height: クロップする高さ
17
+
18
+ 戻り値:
19
+ - クロップされたフレームのリスト
20
+ """
21
+
22
+ image = Image.open(input_path)
23
+ aspect_ratio = image.height / image.width
24
+ new_height_initial_resize = int(crop_width * aspect_ratio)
25
+ resized_initial = image.resize((crop_width, new_height_initial_resize))
26
+
27
+ resize_factor = random.uniform(1.2, 1.5)
28
+ new_width = int(resized_initial.width * resize_factor)
29
+ new_height = int(resized_initial.height * resize_factor)
30
+ resized_image = resized_initial.resize((new_width, new_height))
31
+
32
+ frames = []
33
+ max_y_offset = max(new_height - crop_height, 0)
34
+
35
+ # クロップの中心を維持するためのx_offsetを計算
36
+ x_offset = (new_width - crop_width) // 2
37
+
38
+ step = max_y_offset // min_frames_required
39
+ for y_offset in range(0, max_y_offset + 1, step):
40
+ frame = resized_image.crop((x_offset, y_offset, x_offset + crop_width, y_offset + crop_height))
41
+ frames.append(frame)
42
+
43
+ return frames
44
+
45
+ if __name__ == '__main__':
46
+ # フレームを生成する
47
+ frames_modified = generate_centered_moving_frames(r"image\Echoes-of-Creation_Blurred\00028-1365031933.png")
48
+
49
+ print(len(frames_modified))
modules/utils/v_image_blurred_utils.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image, ImageFilter
2
+ import random
3
+ import os
4
+ from pathlib import Path
5
+ import cv2
6
+ import numpy as np
7
+
8
+ def embed_image_on_blurred_background(input_path: str, output_path: str, height: int = 2000) -> None:
9
+ """
10
+ 入力画像をブラーしたバージョンの上に配置し、その結果を保存します。
11
+
12
+ 引数:
13
+ - input_path: 入力画像のパス
14
+ - output_path: 処理された画像を保存する場所
15
+ - height: 出力画像の希望の高さ(デフォルトは2000ピクセル)
16
+ """
17
+
18
+ # 与えられたパスから画像を読み込む
19
+ image = Image.open(input_path)
20
+
21
+ # 画像の元のサイズを取得する
22
+ original_width, original_height = image.size
23
+
24
+ # 9:16のアスペクト比と指定された高さに基づいて、出力画像の幅を計算する
25
+ target_width = int(height * 9 / 16)
26
+
27
+ # 元の画像のブラーしたバージョンを作成する
28
+ blurred_image = image.filter(ImageFilter.GaussianBlur(20))
29
+
30
+ # ブラー画像を希望の出力サイズにリサイズする
31
+ resized_blurred_background = blurred_image.resize((target_width, height))
32
+
33
+ # 元のアスペクト比を保持したまま、元の画像を指定された高さにリサイズする
34
+ new_width = int(original_width * (height / original_height))
35
+ resized_image_keep_aspect = image.resize((new_width, height), Image.ANTIALIAS)
36
+
37
+ # リサイズされた元の画像をブラーした背景の中央に配置する位置を計算する
38
+ x_offset = (resized_blurred_background.width - resized_image_keep_aspect.width) // 2
39
+ y_offset = (resized_blurred_background.height - resized_image_keep_aspect.height) // 2
40
+
41
+ # 画像に透明度がある場合(RGBAモード)、背景にペーストする際のマスクとして使用する
42
+ mask_keep_aspect = resized_image_keep_aspect if resized_image_keep_aspect.mode == "RGBA" else None
43
+
44
+ # リサイズされた元の画像をブラーした背景の上にオーバーレイする
45
+ resized_blurred_background.paste(resized_image_keep_aspect, (x_offset, y_offset), mask_keep_aspect)
46
+
47
+ # 指定されたパスに結合された画像を保存する
48
+ resized_blurred_background.save(output_path)
modules/video_merger.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image, ImageFilter
2
+ import random
3
+ import os
4
+ from pathlib import Path
5
+ import cv2
6
+ import numpy as np
7
+
8
+ from modules.Transition.VideoMergerWithSmoothTransition import VideoMergerWithSmoothTransition
9
+
10
+ if __name__ == '__main__':
11
+ # 使用例 (コメントアウトされています)
12
+ merger = VideoMergerWithSmoothTransition()
13
+ input_folder_path = r"image\Echoes-of-Creation_Blurred_mov"
14
+ output_folder_path = f"{input_folder_path}_Final"
15
+ os.makedirs(output_folder_path, exist_ok=True)
16
+ output_video_path = os.path.join(output_folder_path, "concatenated_video.mp4")
17
+ merger.merge_videos(input_folder_path, output_video_path)
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio
2
+ opencv-python
3
+ Pillow==9.5.0