前回の記事で画像の中から顔を検出し、モザイクをかけることができるようになりました。
今回は動画の中から人の顔を検出してモザイクをかけてみようと思います。
動画だと難しそう・・・と尻込みしてしまいそうですが「静止画像の連続が動画である」と考えると、それほど怖がる必要もないのかなという印象です。
最終的なコードはこちらになります。
import cv2
#モザイク処理を施す関数
def mosaic(img, mosaic_rate):
w = img.shape[1]
h = img.shape[0]
#画像を縮小→その後元の大きさに戻すことがモザイク処理
img = cv2.resize(img, (int(w * mosaic_rate), int(h * mosaic_rate)))
img = cv2.resize(img, (w, h), interpolation = cv2.INTER_NEAREST)
return img
#識別器を読み込む
cascade_file= cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
clas = cv2.CascadeClassifier(cascade_file)
cap = cv2.VideoCapture("movie2.mp4")
#1フレームずつモザイクをかける
while True:
ret, frame = cap.read()
#retがFalseの場合は終了
if not ret:
break
#グレースケールに変換
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#1フレーム(=静止画)の顔をすべて検出して周囲の四角形の座標を取得
#検出できた顔のすべてについて[四角の左上のx座標、四角の左上のy座標、幅、高さ]の数値を取得
face_list = clas.detectMultiScale(gray, scaleFactor = 1.1, minNeighbors = 3, minSize=(30,30))
#モザイク処理
#[四角の左上のx座標、四角の左上のy座標、幅、高さ]をそれぞれ変数x, y, w, hに代入
for x, y, w, h in face_list:
frame[y : y+h, x : x+w] = mosaic(frame[y : y + h, x : x + w], 0.05)
cv2.imshow("frame", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
今回は下記の部分を「モザイク関数」として切り出しました。
def mosaic(img, mosaic_rate):
w = img.shape[1]
h = img.shape[0]
#画像を縮小→その後元の大きさに戻すことがモザイク処理
img = cv2.resize(img, (int(w * mosaic_rate), int(h * mosaic_rate)))
img = cv2.resize(img, (w, h), interpolation = cv2.INTER_NEAREST)
return img
顔の部分一度縮小してその後拡大することでモザイク化し、その結果を返す処理をしています。
特に下記の部分。
w = img.shape[1]
h = img.shape[0]
OpenCVで画像を読み込むと列の数、行の数などの属性情報がタプルで付与されるので、shape[]で取得しています(こちらのチュートリアル「画像の属性情報の取得」参照)。モザイク処理の「画像縮小→拡大」あたりの説明は以前の記事で書いた内容が参考になるかと思います。
識別器の読み込み
cascade_file= cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
OpenCVが準備している分類器をダウンロードして使っていたのですが、上記の記述でダウンロードせずに使えるそうなので活用しています。
whileループで動画処理
そしてここから始めるwhileループが動画向けの処理になります。
while True:
ret, frame = cap.read()
#retがFalseの場合は終了
if not ret:
break
ret, frame = cap.read() で画像の1フレーム分を読み込んで、戻り値をそれぞれretとframeに代入しています。
①retに代入される値は、正しくフレームが読み込まれていればtrue,そうでなければfalse
②読み込んだ画像のデータを数値化したもの
あとは写真と同じ処理をして、whileループで繰り返す
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
face_list = clas.detectMultiScale(gray, scaleFactor = 1.1, minNeighbors = 3, minSize=(30,30))
for x, y, w, h in face_list:
frame[y : y + h, x : x + w] = mosaic(frame[y : y + h, x : x + w], 0.05)
cv2.imshow("frame", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
上記は前回の記事で説明した通り、顔のある部分にモザイクを当てて、動画ではなく静止画を表示しています。あくまで「動画ではなく静止画」です。
ここでモザイクをかけた静止画を1枚表示した後、whileループの先頭に戻り、次の1フレームの顔部分にモザイクをかけて表示→whileループの先頭に戻る → 次の1フレームの顔部分にモザイクをかけて表示・・・という作業を高速で繰り返しています。要はパラパラ漫画の要領で、人間の目には動画に見えるというわけですね。
モザイク処理済みの動画を掲載しようとしたのですが、動画を埋め込むのが上手くいかなかったので今回はありません。。