OpenCVを使ってアン○ンマンになってみた

# はじめに

## あらすじ

- [先日](http://qiita.com/neriai/items/98b0bf747f829c4a3b58)、嵌ってしまったOpenCVを使って動画の認識が上手くいかなかった件ですが、具体的にはcv2.imshowでエラーが発生しておりそれを解決できないままでいました。
- ふと、動画は駄目でも画像なら認識はできるのかと試したところ同じエラーが発生したので動画だけではなく画像も駄目な状態だということがわかりました。
- そういえば、[以前](http://qiita.com/neriai/items/448a36992e308f4cabe2)は画像で動いていたやんけ！と思って試してみたところ、どうやらOpenCV3では動かず、OpenCV2では正常に動作するみたいでした。
- Mac環境下でHomebrewやpip経由でOpenCV2を利用する場合は、Python2でないとインストールできないみたいなので、今回はそちらで行うことにしました。
- ネタとしては面白そうなのと、これならうちの子供が喜ぶかもしれないと思って安易なアイデアで作ってみましたが、結構雑な物になってしまいました。

# 参考
[Python + OpenCV で雑コラ動画を作成する② 静止画コラ作成](http://qiita.com/k_sui_14/items/bb9dc8395da85400e518)

# 環境

## Python2.7
```zsh
brew install python
```

## PATHの設定
```zsh
if [ -d $(brew --prefix)/lib/python2.7/site-packages ];then
  export PYTHONPATH=$(brew --prefix)/lib/python2.7/site-packages:$PYTHONPAT
fi
```

## OpenCV2
```zsh
brew install opencv
```

## Numpy
```zsh
pip install numpy
```

## Webカメラ
MacBookに付属のカメラを使ってます。

# 準備

## アン○ンマンの画像を入手
パン工場で作ってもらう。

## 透過画像にする
[参考](http://qiita.com/na1412/items/90a9641d9644e1bfbb49)
![anpan.png](https://qiita-image-store.s3.amazonaws.com/0/90598/a0b12782-56ce-0ac6-76b6-7a370561695b.png)

※ 大人の事情につき、目にモザイクいれてます。

# ソースコード

そこまで大したことやってないので、コメントあまり入れていません。

```py:webcam.py
#! -*- coding: utf-8 -*-

import cv2
import numpy as np
from PIL import Image

def facedetect(face_cascade, cap, image):
    cnt = 0

    while(True):
        ret, frame = cap.read()

        if ret == False:
            break
        else:
            if (cnt % 10) == 0:
                gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

                facerect = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))

            cnt += 1

            if len(facerect) > 0:
                for rect in facerect:

                    x = rect[0]
                    y = rect[1]
                    w = rect[2]
                    h = rect[3]

                    # 顔の形状によっては調整が必要かもしれません
                    x = x - w / 2
                    y = y - h / 1.8
                    w = w * 1.7
                    h = h * 1.7

                    x = int(round(x))
                    y = int(round(y))
                    w = int(round(w))
                    h = int(round(h))

                    # 矩形に合わせて合成する画像をリサイズします。
                    image = cv2.resize(image, (w, h))

                    # カメラの顔を画像を合成します。
                    frame = overlay(frame, image, x, y)

                    # モザイク処理をしたい場合はこちらを使ってください。
                    # dst = frame[y:y+h, x:x+w]
                    # blur = cv2.blur(dst, (50, 50))
                    # frame[y:y+h, x:x+w] = blur

        cv2.imshow('fram', frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

def overlay(frame, image, x, y):
    height, width = image.shape[:2]

    layer1 = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    layer2 = cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA)

    layer1 = Image.fromarray(layer1)
    layer2 = Image.fromarray(layer2)

    layer1 = layer1.convert('RGBA')
    layer2 = layer2.convert('RGBA')

    tmp = Image.new('RGBA', layer1.size, (255, 255, 255, 0))
    tmp.paste(layer2, (x, y), layer2)

    result = Image.alpha_composite(layer1, tmp)

    return cv2.cvtColor(np.asarray(result), cv2.COLOR_RGBA2BGRA)

if __name__ == '__main__':
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')
    image = cv2.imread('anpan.png', cv2.IMREAD_UNCHANGED)

    cap = cv2.VideoCapture(0)
    cap.set(3, 640)
    cap.set(4, 480)

    facedetect(face_cascade, cap, image)
```

# 結果

<img width="651" alt="スクリーンショット 2017-06-26 3.05.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/90598/f6f69cc8-16d6-e9cf-9e76-f6859816bc24.png">

※大人の事情につき、顔全体にモザイクを入れています。

# まとめ

- 案外情報があって助かった。
- フレームと認識度合いをマッチさせるのに若干調整が必要だった。
- デフォルトだと顔しか認識しないものを、頭部全体かつ肩より上あたりだけを矩形描画するのに調整が必要だった。
- 胴体も認識して被せればもう少しそれっぽくなりそうな気がする。
- 今度こそSSDに挑戦できる。（はず）
- スマホアプリにできるならちょっとやってみたい。


# 全ページリンク
- [OpenCVを使ってアン○ンマンになってみた](http://qiita.com/neriai/items/9155263f4b5e93d90906)
- [SkyWayを使って多人数ビデオチャットを作ってみた](http://qiita.com/neriai/items/b96bb88f39903a2abf85)
- [SkyWayを使ったビデオチャットに顔認識ができるか試してみた](http://qiita.com/neriai/items/e6e697efa01e9806757e)