画像反転・高解像度化・GIF化・MP4化　pythonプログラム

# 記事の概要

Stable DiffusionのAnimateDiffを使っている時に、インプットの画像を判定させたり、出力後に解像度を上げたりなどの操作を行うことがあるので、その時に使っているプログラムを記載します。

# 環境
OS:Windows 11
GPU:GeForce RTX 4090
CPU:i9-13900KF
memory:64G
python:3.10.10
pytorch:2.0.1
CUDA:11.8
cuDNN:8.8

# 環境構築
以下のコマンドでライブラリをインストールする。
```
pip install transformers
pip install moviepy
```

# プログラム

## 画像反転
以下のプログラムを実行するディレクトリに「folder」を作成し、その中に判定対象の画像（複数可）を配置し。プログラムを実行すると、「folder/super_resolved」反転した画像が出力される。
```
from PIL import Image
from pathlib import Path

# 処理するフォルダの相対パス
folder_path = Path("folder")
output_folder = folder_path / "super_resolved"

# 出力フォルダがなければ作成
output_folder.mkdir(exist_ok=True)

# フォルダ内の全てのPNGとJPEGファイルに対して処理を行う
for image_format in ["*.png", "*.jpg", "*.jpeg"]:
    for image_path in folder_path.glob(image_format):
        # 画像ファイルを開く
        original_image = Image.open(image_path)
        
        # 画像を左右反転する
        flipped_image = original_image.transpose(Image.FLIP_LEFT_RIGHT)
        
        # 反転した画像を元のフォーマットで保存する
        # 保存するファイル名を元のファイル名に基づいて決定
        flipped_file_path = output_folder / f"flipped_{image_path.name}"
        flipped_image.save(flipped_file_path)
```

## 高解像度化
以下の学習済みモデルを利用し、解像度を２倍にする。

https://huggingface.co/caidas/swin2SR-classical-sr-x2-64

```
import torch
from PIL import Image
from pathlib import Path
from transformers import AutoImageProcessor, Swin2SRForImageSuperResolution

# GPUが利用可能か確認し、利用可能なら使用する
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")

# モデルとプロセッサのロード、モデルをデバイスに移動
processor = AutoImageProcessor.from_pretrained("caidas/swin2SR-classical-sr-x2-64")
model = Swin2SRForImageSuperResolution.from_pretrained("caidas/swin2SR-classical-sr-x2-64").to(device)

# 処理するフォルダのパス
folder_path = Path(r"folder")
output_folder = folder_path / "super_resolved"

# 出力フォルダがなければ作成
output_folder.mkdir(exist_ok=True)

# フォルダ内の全てのPNGファイルに対して処理を行う
for image_path in folder_path.glob("*.png"):
    # 入力画像のロード（RGBに変換）
    image = Image.open(image_path).convert("RGB")
    
    # 画像をモデルが期待するサイズに変換
    inputs = processor(image, return_tensors="pt").to(device)
    
    # スーパーリゾリューションの実行
    with torch.no_grad():
        outputs = model(**inputs)
    
    # 出力画像の取得
    output = outputs["reconstruction"].permute(0, 2, 3, 1)[0].cpu().numpy()
    output = (output * 255).astype("uint8")
    
    # PIL Imageに変換
    output_image = Image.fromarray(output)
    
    # 画像を保存
    output_image_path = output_folder / f"super_resolved_{image_path.name}"
    output_image.save(output_image_path)
    
    print(f"Processed and saved: {output_image_path}")
```

## 画像を統合してgifを作成
フォルダ内のファイルを統合し、gifファイルを作成する。（ファイル名順位統合する。）
```
from PIL import Image
import os
from pathlib import Path

# 画像が保存されているフォルダのパス
image_folder = Path("folder\super_resolved")

# 出力するGIFの名前
output_gif = image_folder / "output.gif"

# 画像フォルダからすべての画像ファイルのパスを取得
images = [os.path.join(image_folder, img) for img in os.listdir(image_folder) if img.endswith((".png", ".jpg", ".jpeg"))]

# ファイル名に基づいて画像をソート
images.sort(key=lambda x: os.path.basename(x))

# 画像ファイルを開く
frames = [Image.open(image) for image in images]

# 8FPSでGIFを保存するための遅延時間を設定（125ミリ秒）
# duration_per_frame = 125

# 24FPSでGIFを保存するための遅延時間を設定（41.6ミリ秒）
duration_per_frame = 41.6


# 最初の画像を基準にしてGIFを保存
frames[0].save(output_gif, format='GIF', append_images=frames[1:], save_all=True, duration=duration_per_frame, loop=0)

# print(f"GIF saved as {output_gif} with 8 FPS.")
print(f"GIF saved as {output_gif} with 24 FPS.")
```

## gifをmp4に変換
gifファイルをmp4ファイルに変換する。
```
from moviepy.editor import VideoFileClip

# GIFファイルのパス
gif_path = r'folder\super_resolved\output.gif'

# 出力するMP4ファイルのパス
mp4_path = r'folder\super_resolved\mp4.mp4'

# GIFを読み込み
clip = VideoFileClip(gif_path)

# MP4として書き出し
clip.write_videofile(mp4_path, fps=24)  # FPSは必要に応じて調整できます
# clip.write_videofile(mp4_path, fps=8)  # FPSは必要に応じて調整できます
```


## 全処理実行（高解像度化→gif統合→mp4変換）
複数のpngファイルを高解像度化し、gif・mp4ファイルを作成する。
```
import torch
from PIL import Image
from pathlib import Path
from transformers import AutoImageProcessor, Swin2SRForImageSuperResolution

# GPUが利用可能か確認し、利用可能なら使用する
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")

# モデルとプロセッサのロード、モデルをデバイスに移動
processor = AutoImageProcessor.from_pretrained("caidas/swin2SR-classical-sr-x2-64")
model = Swin2SRForImageSuperResolution.from_pretrained("caidas/swin2SR-classical-sr-x2-64").to(device)

# 処理するフォルダのパス
folder_path = Path(r"folder")
output_folder = folder_path / "super_resolved"

# 出力フォルダがなければ作成
output_folder.mkdir(exist_ok=True)

# フォルダ内の全てのPNGファイルに対して処理を行う
for image_path in folder_path.glob("*.png"):
    # 入力画像のロード（RGBに変換）
    image = Image.open(image_path).convert("RGB")
    
    # 画像をモデルが期待するサイズに変換
    inputs = processor(image, return_tensors="pt").to(device)
    
    # スーパーリゾリューションの実行
    with torch.no_grad():
        outputs = model(**inputs)
    
    # 出力画像の取得
    output = outputs["reconstruction"].permute(0, 2, 3, 1)[0].cpu().numpy()
    output = (output * 255).astype("uint8")
    
    # PIL Imageに変換
    output_image = Image.fromarray(output)
    
    # 画像を保存
    output_image_path = output_folder / f"super_resolved_{image_path.name}"
    output_image.save(output_image_path)
    
    print(f"Processed and saved: {output_image_path}")

import os

# 画像が保存されているフォルダのパス
image_folder = Path(r'folder\super_resolved')

# 出力するGIFの名前
output_gif = image_folder / "output.gif"

# 画像フォルダからすべての画像ファイルのパスを取得
images = [os.path.join(image_folder, img) for img in os.listdir(image_folder) if img.endswith((".png", ".jpg", ".jpeg"))]

# ファイル名に基づいて画像をソート
images.sort(key=lambda x: os.path.basename(x))

# 画像ファイルを開く
frames = [Image.open(image) for image in images]

# 8FPSでGIFを保存するための遅延時間を設定（125ミリ秒）
# duration_per_frame = 125

# 24FPSでGIFを保存するための遅延時間を設定（41.6ミリ秒）
duration_per_frame = 41.6


# 最初の画像を基準にしてGIFを保存
frames[0].save(output_gif, format='GIF', append_images=frames[1:], save_all=True, duration=duration_per_frame, loop=0)

# print(f"GIF saved as {output_gif} with 8 FPS.")
print(f"GIF saved as {output_gif} with 24 FPS.")

from moviepy.editor import VideoFileClip

# GIFファイルのパス
gif_path = r'folder\super_resolved\output.gif'

# 出力するMP4ファイルのパス
mp4_path = r'folder\super_resolved\mp4.mp4'

# GIFを読み込み
clip = VideoFileClip(gif_path)

# MP4として書き出し
clip.write_videofile(mp4_path, fps=24)  # FPSは必要に応じて調整できます
# clip.write_videofile(mp4_path, fps=8)  # FPSは必要に応じて調整できます
```