Python + OpenCV で雑コラ動画を作成する② 静止画コラ作成

##0. はじめに
前回([その① 顔認識](http://qiita.com/k_sui_14/items/5386db1a118103b1828f))からの続きです。
前回認識した顔を他の画像で上書きします。
以下のサイトを参考にしました。
[python+Opencvによる画像処理5（リサイズ）](http://tatabox.hatenablog.com/entry/2013/07/15/164015)
[Python + OpenCV + pillowで笑い男を顔に上書き](http://symfoware.blog68.fc2.com/blog-entry-1557.html?sp)


上書きする画像はやっぱりコレでしょう。
[笑い男パーツ](http://ledmyway.seesaa.net/article/181382754.html)


##1. 画像のリサイズ
認識した顔の大きさと上書きしようとしている画像の大きさが異なるので、OpenCVのresize()関数を使って画像のサイズを変更する関数を作成します。
画像と変更後のサイズを与えるとそれに合わせて伸縮します。
元画像のアスペクト比を変えたくなかったので、サイズの差(比率)が小さい方に合わせて伸縮します。
以下がコードです。


```py3:resize_image
def resize_image(image, height, width):
    
    # 元々のサイズを取得
    org_height, org_width = image.shape[:2]
    
    # 大きい方のサイズに合わせて縮小
    if float(height)/org_height > float(width)/org_width:
        ratio = float(height)/org_height
    else:
        ratio = float(width)/org_width
    
    # リサイズ
    resized = cv2.resize(image,(int(org_height*ratio),int(org_width*ratio)))
    
    return resized    
```

##2. リサイズ結果
サイズ変更の関数をテストしてみます。試しに100×100の大きさにしてみました。

```py3:resizetest
    # 上書きする画像の読み込み
    ol_imgae_path = "target/warai_otoko.png"    
    ol_image = cv2.imread(ol_imgae_path,cv2.IMREAD_UNCHANGED)   # アルファチャンネル(透過)も読みこむようにIMREAD_INCHANGEDを指定

    # リサイズ
    resized_image = resize_image(ol_image, 100, 100)

    # 認識結果の出力
    cv2.imwrite("result/warai_otoko_result.png", resized_image)
```
**Before**
![warai_otoko.png](https://qiita-image-store.s3.amazonaws.com/0/3099/ce12977d-52df-a0af-627d-5bcba39a1088.png)

**After**
![warai_otoko_result.png](https://qiita-image-store.s3.amazonaws.com/0/3099/65d59e24-41d8-85bb-5b45-a80cee96f2a6.png)

うまく縮小できました。


##3. 画像の上書きを行う関数の作成
顔部分に画像を上書きします。
Pillow(PIL)というライブラリを用いて、指定した位置に画像を合成する関数を作成します。
流れは
・画像をOpenCVの形式からPILの形式に変換
・オーバレイ画像で上書き
・PILの形式からOpenCVの形式に直して返す。
という感じです。

```py3:overlayOnPart
import numpy as np
from PIL import Image

def overlayOnPart(src_image, overlay_image, posX, posY):

    # オーバレイ画像のサイズを取得
    ol_height, ol_width = overlay_image.shape[:2]

    # OpenCVの画像データをPILに変換
    #　BGRAからRGBAへ変換
    src_image_RGBA = cv2.cvtColor(src_image, cv2.COLOR_BGR2RGB)
    overlay_image_RGBA = cv2.cvtColor(overlay_image, cv2.COLOR_BGRA2RGBA)
    
    #　PILに変換
    src_image_PIL=Image.fromarray(src_image_RGBA)
    overlay_image_PIL=Image.fromarray(overlay_image_RGBA)

    # 合成のため、RGBAモードに変更
    src_image_PIL = src_image_PIL.convert('RGBA')
    overlay_image_PIL = overlay_image_PIL.convert('RGBA')

    # 同じ大きさの透過キャンパスを用意
    tmp = Image.new('RGBA', src_image_PIL.size, (255, 255,255, 0))
    # 用意したキャンパスに上書き
    tmp.paste(overlay_image_PIL, (posX, posY), overlay_image_PIL)
    # オリジナルとキャンパスを合成して保存
    result = Image.alpha_composite(src_image_PIL, tmp)
    
    return  cv2.cvtColor(np.asarray(result), cv2.COLOR_RGBA2BGRA)
```



##4. 上書き関数の組み込み
前回認識したLenna画像の顔に笑い男を載せてみます。
前回のソースに上書きする画像の読み込みを追加し、
顔の大きさに合わせて縮小した後、上書きをします。

```py3:overlay_face
#coding=utf-8

import cv2
import numpy as np
from PIL import Image


def overlay_face():

    # 認識対象ファイルの読み込み
    image_path = "target/Lenna.png"
    image = cv2.imread(image_path)

    # 上書きする画像の読み込み
    ol_imgae_path = "target/warai_otoko.png"    
    ol_image = cv2.imread(ol_imgae_path,cv2.IMREAD_UNCHANGED)   # アルファチャンネル(透過)も読みこむようにIMREAD_INCHANGEDを指定
 
    # グレースケールに変換
    image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # 顔認識用特徴量のファイル指定
    cascade_path = "haarcascades/haarcascade_frontalface_alt.xml"
    # カスケード分類器の特徴量を取得する
    cascade = cv2.CascadeClassifier(cascade_path)

    # 顔認識の実行
    facerecog = cascade.detectMultiScale(image_gray, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))

  
    if len(facerecog) > 0:


        # 認識した顔全てに画像を上書きする
        for rect in facerecog:

            # 認識結果を表示
            print ("認識結果")
            print ("(x,y)=(" + str(rect[0]) + "," + str(rect[1])+ ")" + \
                "  高さ："+str(rect[2]) + \
                "  幅："+str(rect[3]))

            # 認識範囲にあわせて画像をリサイズ
            resized_ol_image = resize_image(ol_image, rect[2], rect[3])
            
            # 上書きした画像の作成
            image = overlayOnPart(image, resized_ol_image, rect[0], rect[1])
    
    # 認識結果の出力
    cv2.imwrite("result/Lenna_result.png", image)


if __name__ == '__main__':
    overlay_face()
```

##5. 上書き結果
![Lenna_result.png](https://qiita-image-store.s3.amazonaws.com/0/3099/bda41b74-875c-116a-8a99-b3e1c234b46d.png)

うまくいきました。

##6. 最後に
これで静止画像のコラ作成が出来るようになったので、
次回からは動画に適用していきます。
[Python + OpenCV で雑コラ動画を作成する③ 雑コラ動画作成](http://qiita.com/k_sui_14/items/92fd84f35245ad0be464)