10
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-06-25

はじめに

あらすじ

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

参考

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

環境

Python2.7

brew install python

PATHの設定

if [ -d $(brew --prefix)/lib/python2.7/site-packages ];then
  export PYTHONPATH=$(brew --prefix)/lib/python2.7/site-packages:$PYTHONPAT
fi

OpenCV2

brew install opencv

Numpy

pip install numpy

Webカメラ

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

準備

アン○ンマンの画像を入手

パン工場で作ってもらう。

透過画像にする

参考
anpan.png

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

ソースコード

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

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)

結果

スクリーンショット 2017-06-26 3.05.34.png

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

まとめ

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

全ページリンク

10
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?