モザイク処理(カラー)とOpenCVでの動画

■カラーRGBでのモザイク処理とそれが消える感じの動画。
前回白黒で試したので今回はカラーで作ってみた。また、モザイク処理した画像から徐々に弱いモザイク処理にしていき最終的に元の画像まで表示する動画にした。これにはOpenCVを使う。

コードは下のもの。大きくモザイク処理。動画用の画像を増やす。動画にする。の3つに分かれる。

import numpy as np
from PIL import Image
import cv2

FILENAME = 'sample044.JPG'
VIDEONAME = 'sample045_video.avi'

img = Image.open(FILENAME)
xsize, ysize = img.size

imglist = []
vallist = [40, 20, 10, 8, 4, 2]

#モザイクの画像を作る。上のvallistの粗さのものを作る。
for sideval in vallist:
    resultImg = Image.new("RGB", [xsize, ysize], (0, 0, 0))
    if sideval * sideval > 256:
        maxcolor = sideval * sideval
    else:
        maxcolor = 256

    for i in range(0, int(xsize / sideval)):
        for j in range(0, int(ysize / sideval)):
            part = img.crop(((i * sideval), (j * sideval), (i * sideval + sideval), (j * sideval + sideval)))
            info = part.getcolors(maxcolor)
            sumNum = 0
            sumColinfo1 = 0
            sumColinfo2 = 0
            sumColinfo3 = 0
            for pixelCol in info:
                sumNum = sumNum + pixelCol[0]
                sumColinfo1 = sumColinfo1 + (pixelCol[1][0] * pixelCol[0])
                sumColinfo2 = sumColinfo2 + (pixelCol[1][1] * pixelCol[0])
                sumColinfo3 = sumColinfo3 + (pixelCol[1][2] * pixelCol[0])
            result1 = int(sumColinfo1 / sumNum)
            result2 = int(sumColinfo2 / sumNum)
            result3 = int(sumColinfo3 / sumNum)
            imgsect = Image.new("RGB", [sideval, sideval], (result1, result2, result3))
            resultImg.paste(imgsect, (i * sideval, j * sideval))
    imglist.append(resultImg)

#得たモザイクの画像を隣り合う粗さで割合をかえて結合。動画にする画像を増やす。
imgforvideo = []
for i in range(0, len(imglist)):
    img1 = np.array(imglist[i], dtype=np.uint8)
    img1 = cv2.cvtColor(img1, cv2.COLOR_RGB2BGR)
    if i < len(imglist) - 1:
        img2 = np.array(imglist[i + 1], dtype=np.uint8)
        img2 = cv2.cvtColor(img2, cv2.COLOR_RGB2BGR)
    else:
        img2 = cv2.imread(FILENAME)
    for j in range(1, 20):
        dst = cv2.addWeighted(img1, (20 - j) / 20, img2, j / 20, 0)
        imgforvideo.append(dst)

#画像のリストを動画(avi)にする
height, width, layers = imgforvideo[0].shape
fourcc = cv2.VideoWriter_fourcc(*'XVID')
video = cv2.VideoWriter(VIDEONAME, fourcc, 6, (width, height))

for j in range(0, len(imgforvideo)):
    video.write(imgforvideo[j])

cv2.destroyAllWindows()
video.release()

モザイク処理の部分は、前回のコードの修正。カラーRGBにすると、getcolors() で取得されるデータがR、G、Bの3つになる。それぞれで回りのピクセルと平均化。getcolors()で引数を指定しないと、デフォルトの256となり、超える場合は空が返却される仕様のよう。カラーにすると白黒より同じになるピクセルが少なくなるので、40 × 40とした際に不具合が出た。ので、すべてのピクセルが別の色になっても問題ないように引数を指定した。

このモザイク処理で、一辺が40、20、10、8、4、2ピクセルのモザイク処理後の画像が得られる。
元の図は、360×200 なので割り切れる数を指定している。

次に、この6つの画像に元の図を含めた7つの画像から、隣り合う画像同士で OpenCV の addWeighted を使って画像を合成する。例えば、40、20の画像に対して、19:1、18:2、17:3、...、2:18、1:19 の割合で合成して19つにする。これで6*19 = 114 の画像ができる。

最後に6fpsで動画作成。1秒間に6枚なので、114枚→19秒ほどになる。
出来上がった動画が下。