PCAで動画圧縮

最近、機械学習でsciket-learnを色々と使っていたりで、なんとなく動画をPCA次元削減して遊んでみた。元々はPCAを行ったあとにk-meansでカテゴライズをしたりする時に使ったりする訳だけど、画像を次元削減して見てみると面白いフィルターとして使えそうな。
動画は元々はMaker Faire Bay Areaで撮った1920×1080のmp4ファイルをJPEGで取り出して、ちょっと大きいから半分にサイズを減らした後、10(右下), 60(左下), 120(右上), 240(左上)次元削減している。次元が少ない方が面白い感じに。動画から切り出した写真で10・240次元削減した物はこんな感じになる。

ソースコードはこんな感じ。とっても簡単。PCAのモデルは処理が終わったら保存しておいて、別途回せるように保存している。

import cv2
from PIL import Image
import numpy as np
import pickle
from sklearn.decomposition import PCA

# 動画の読み込み
cap = cv2.VideoCapture("movie.mp4")
dataset = []

while(cap.isOpened()):
    ret, img = cap.read()
    
    if ret == True:
        # CV2ImageをPILImageに変換
        img = img[:, :, ::-1].copy()
        img = Image.fromarray(img).resize((int(960), int(540)), Image.BICUBIC)
        
        # (540, 960, 3)配列にして1次元にする
        img = np.asarray(img)
        img = img.reshape(1, img.shape[0] * img.shape[1] * img.shape[2])
        dataset.append(img[0])
    else:
        break

# PCA実行
pca = PCA(n_components=10)
pca.fit(np.array(dataset).astype(np.float64))

# モデルを保存しとく(後で使うとき用)
with open('pca.pickle', mode='wb') as fp:
    pickle.dump(pca, fp)

# 動画を作成
fourcc = cv2.VideoWriter_fourcc('m','p','4','v')
video = cv2.VideoWriter('result.mp4', fourcc, 30.0, (960, 540))

for img in dataset:
    # PCAして動画に突っ込む
    transformed = pca.transform([img])
    pilImg = Image.fromarray(255 - (transformed.dot(pca.components_).reshape([540, 960, 3])).astype(np.uint8))
    cv2Img = np.asarray(pilImg)
    video.write(cv2Img)

video.release()

画像を色々と集めてきてPCAをかけたモデルを保存して、思わずJamiroquaiのVirtual Insanityの動画をmp4で取得してきてPCAをかけた。なんとなく最初に浮かんだのがJamiroquaiだったからで、特に深い意味は無いけど。

面白いフィルターとして使えそうな気がちょっぴりしていたり。RGB成分をそれぞれ分離して、それぞれの成分毎に圧縮して掛け合わせてみても面白いかも。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください