はじめに
あらすじ
- 先日、嵌ってしまった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に付属のカメラを使ってます。
準備
アン○ンマンの画像を入手
パン工場で作ってもらう。
透過画像にする
※ 大人の事情につき、目にモザイクいれてます。
ソースコード
そこまで大したことやってないので、コメントあまり入れていません。
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)
結果
※大人の事情につき、顔全体にモザイクを入れています。
まとめ
- 案外情報があって助かった。
- フレームと認識度合いをマッチさせるのに若干調整が必要だった。
- デフォルトだと顔しか認識しないものを、頭部全体かつ肩より上あたりだけを矩形描画するのに調整が必要だった。
- 胴体も認識して被せればもう少しそれっぽくなりそうな気がする。
- 今度こそSSDに挑戦できる。(はず)
- スマホアプリにできるならちょっとやってみたい。