グリーンバック動画からgifファイルを作る
記事で猫memeを使いたい
皆さん、記事で猫memeを使いたいですよね!!!!(ヤケクソ)
ということで謎のユーティリティツールを紹介します!!!!
記事作成までの流れ
- mp4動画をダウンロード
- mp4動画をgifに変換
- 好きなとこにgifを貼り付けよう
mp4動画をダウンロード
ここが素晴らしいです!!
mp4動画をgifに変換
ちょっとネット探すと動画を透過してgifにするサイトが見つかるが
https通信じゃないとかウォータマークがつくつかダルい!!!
pythonで作ろう!!
自分用の殴り書きなので、自分好みに調整してください
mp4_to_gif_with_GB_chroma_key.py
import cv2
import numpy as np
from PIL import Image
import os
def create_palette_from_frames(frames):
"""
フレームから最適なパレットを作成する
"""
# 一時的な画像を作成してパレットを抽出
total_pixels = np.zeros((0, 3), dtype=np.uint8)
for frame in frames:
frame_array = np.array(frame.convert('RGB'))
pixels = frame_array.reshape(-1, 3)
total_pixels = np.vstack((total_pixels, pixels))
# K-means クラスタリングで代表的な色を選択
total_pixels = total_pixels[::10] # サンプリングして処理を軽くする
if len(total_pixels) > 0:
total_pixels = total_pixels.astype(np.float32)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
_, labels, palette = cv2.kmeans(total_pixels, 255, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
palette = palette.astype(np.uint8)
return Image.new('P', (1, 1))._new(palette.tolist())
return None
def process_video(input_file, output_file, green_sensitivity=40, default_fps=30):
"""
MP4動画をクロマキー処理してGIFに変換する関数(パレット最適化版)
Parameters:
input_file (str): 入力MP4ファイルのパス
output_file (str): 出力GIFファイルのパス
green_sensitivity (int): 緑色の検出感度(値が大きいほど広い範囲を透過)
default_fps (int): FPSが取得できない場合のデフォルト値
"""
# 動画を読み込む
cap = cv2.VideoCapture(input_file)
if not cap.isOpened():
print("動画ファイルを開けませんでした。")
return
frames = []
while True:
ret, frame = cap.read()
if not ret:
break
# BGRからRGBに変換
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# HSV色空間に変換
frame_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 緑色の範囲を定義
lower_green = np.array([60 - green_sensitivity, 50, 50])
upper_green = np.array([60 + green_sensitivity, 255, 255])
# マスクを作成
mask = cv2.inRange(frame_hsv, lower_green, upper_green)
# マスクの微調整
kernel = np.ones((3,3), np.uint8)
mask = cv2.erode(mask, kernel, iterations=1)
mask = cv2.dilate(mask, kernel, iterations=1)
# マスクを反転
mask = cv2.bitwise_not(mask)
# PILイメージに変換
pil_image = Image.fromarray(frame_rgb)
# RGBA形式に変換
pil_image = pil_image.convert('RGBA')
# アルファチャンネルを設定
data = np.array(pil_image)
data[:, :, 3] = mask
# 完全に透明なピクセルのRGB値をクリア
data[data[:, :, 3] == 0] = [0, 0, 0, 0]
pil_image = Image.fromarray(data)
frames.append(pil_image)
cap.release()
if not frames:
print("フレームを取得できませんでした。")
return
# FPSを30に指定
original_fps = 30
frame_duration = int(1000 / original_fps)
print(f"FPS: {original_fps}")
print(f"フレーム間隔: {frame_duration}ms")
# リサイズしたい幅を指定
target_width = 400 # 出力GIFの幅を指定(例: 640px)
print(f"リサイズ幅: {target_width}px")
# 透過情報をmaskとしてindex255として貼り付け、リサイズも一緒にやる
converted_frames = []
for frame in frames:
# 元のサイズ
original_width, original_height = frame.size
# 縦横比を保持して新しい高さを計算
aspect_ratio = original_height / original_width
target_height = int(target_width * aspect_ratio)
# フレームをリサイズ
frame = frame.resize((target_width, target_height), Image.Resampling.LANCZOS)
alpha = frame.split()[3]
frame = frame.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255)
mask = Image.eval(alpha, lambda a: 255 if a <= 128 else 0)
frame.paste(255, mask=mask)
converted_frames.append(frame)
converted_frames[0].save(
output_file,
save_all=True,
append_images=converted_frames[1:],
duration=frame_duration,
loop=0,
disposal=2,
transparency=255, # 設定したインデックスを渡す
optimize=False
)
print(f"変換完了: {output_file}")
# 使用例
if __name__ == "__main__":
input_video = r'mp4動画のfull path'
output_gif = r'出力gifのfull path'
if os.path.exists(input_video):
process_video(input_video, output_gif, green_sensitivity=40)
else:
print(f"入力ファイル {input_video} が見つかりません。")