Atom's tech blog

OpenCVで顔検出した箇所にモザイクをかけてみた

概要

  • 顔検出は「haarcascade_frontalface_alt2」を使用
  • 顔検出箇所のX値,Y値,幅,高を取得
  • 顔位置にモザイク画像を貼り付け

コメント

  • 顔認証で作成したソースコードの顔検出部分を活用
  • 下のイメージ画像はカメラから取得した画像ではなく、フリー画像を読み込みしたファイルにモザイクをつけるようにソースコードを変更して作成
  • 実際の掲載したソースコードはカメラからキャプチャしたものにモザイクをつける
  • モザイク部分の画像作成はサンプルコードをそのまま活用
  • ラズパイでも動作可能
  • 使ったツールバージョンは以下
  • MacOS Catalina / python3.5.6 / Opencv3.4.2 / VS code1.38.1

イメージ画像(その1)

f:id:iAtom:20201008144633j:plain

ファイル構成(その1)

ソースコード(その1)

# coding: utf-8
import cv2

# 顔検出インスタンス生成
cascadePath = '/Users/local/source/opencv/face_recognition/data_xml/haarcascade_frontalface_alt2.xml'
faceCascade = cv2.CascadeClassifier(cascadePath)

###############################
# VideoCapture用インスタンス生成
###############################
cap = cv2.VideoCapture(0)

###############################
# 画像サイズをVGAサイズに変更する
###############################
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) 
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# 最小Windowサイズを定義
minW = 0.1*cap.get(cv2.CAP_PROP_FRAME_WIDTH)
minH = 0.1*cap.get(cv2.CAP_PROP_FRAME_HEIGHT)

##### モザイクをかけるメソッド ######
def mosaic(img,rect,size):
    # モザイクをかける領域を取得
    (x1,y1,x2,y2)=rect
    w=x2-x1
    h=y2-y1
    i_rect = img[y1:y2,x1:x2]
    # 一度縮小して拡大する
    i_small = cv2.resize(i_rect,(size,size))
    i_mos = cv2.resize(i_small,(w,h),interpolation=cv2.INTER_AREA)
    # モザイクに画像を重ねる
    img2=img.copy()
    img2[y1:y2,x1:x2]=i_mos
    return img2

while True:
    # カメラから画像データ取得
    ret, img =cap.read()
    # グレースケールに変換
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    # 顔検出
    faces = faceCascade.detectMultiScale( 
        gray,
        scaleFactor = 1.2,
        minNeighbors = 3,
        minSize = (int(minW), int(minH)),
       )

    # 顔検出箇所にモザイクをかけるためのループ
    for(x,y,w,h) in faces:
        # モザイクをかける
        img = mosaic(img,(x,y,x+w,y+h),10)

    # 画像表示
    cv2.imshow('face mosaic',img) 

    # ESCキーで終了
    k = cv2.waitKey(10) & 0xff 
    if k == 27:
        break

# Do a bit of cleanup
print("\n Exit Program")
cap.release()
cv2.destroyAllWindows()

画像ファイル内のピクセルが小さい顔を検出してモザイクをかけてみる

  • その1はカメラからキャプチャーしたデータに対して、今回は画像ファイルにモザイクをかける
  • その1は顔検出の detectMultiScaleのパラメータ「minSize=64幅,48高さ」に対して、今回は「minSize=10幅,10高さ」。
  • minSize変更で小さい顔画像の検出が可能となる。しかしサイズの単位がよくわかっていない...(ピクセル数?)
  • 顔検出は「haarcascade_frontalface_alt2」のカスケードファイルに依存するため、横向きは難しそう。少し斜めぐらいならいけそうかも。

detectMultiScaleのパラメータ説明(一部)

cascade.detectMultiScale(img, scaleFactor, minNeighbors, flags, minSize, maxSize)
  • scaleFactor : 画像をスケーリングして検出するときの設定変数(scaleFactorは縮小量の「ステップ」) scaleFactorが1.1のとき10%ずつ元画像を縮小して検出をする
  • minNeighbors : 検出する領域の間隔を調節 0 : 検出にマッチする数が多くなる。検出の少ないが誤検出が増える 大きいとき : 検出にマッチする数は少なくなる。見逃しは多いが誤検出は少なくなる
  • minSize : 物体が取り得る最小サイズ。これよりも小さい物体は検出できない
  • maxSize : 検出領域の最大の大きさを調節

イメージ画像(その2)

f:id:iAtom:20201008144659p:plain

小さめの顔にもモザイクはかかっているが、モザイクが若干薄め。 モザイクがかからないのは顔検出ができないものと思われる。

ファイル構成(その2)

  • face_mosaic2.py : 顔検出モザイク処理その2 ソースファイル(下のソースコード

ソースコード(その2)

# coding: utf-8
import cv2

# 顔検出インスタンス生成
cascadePath = '/Users/local/source/opencv/face_recognition/data_xml/haarcascade_frontalface_alt2.xml'
faceCascade = cv2.CascadeClassifier(cascadePath)

# 画像ファイル読み込み
img = cv2.imread('facedata.png')

# 顔検出のサイズを最小幅10、高さ10にする
minW = 10
minH = 10

##### モザイクをかけるメソッド ######
def mosaic(img,rect,size):
    # モザイクをかける領域を取得
    (x1,y1,x2,y2)=rect
    w=x2-x1
    h=y2-y1
    i_rect = img[y1:y2,x1:x2]
    # 一度縮小して拡大する
    i_small = cv2.resize(i_rect,(size,size))
    i_mos = cv2.resize(i_small,(w,h),interpolation=cv2.INTER_AREA)
    # モザイクに画像を重ねる
    img2=img.copy()
    img2[y1:y2,x1:x2]=i_mos
    return img2

# グレースケールに変換
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 顔検出
faces = faceCascade.detectMultiScale( 
    gray,
    scaleFactor = 1.2,
    minNeighbors = 3,
    minSize = (int(minW), int(minH)),
    )

# 顔検出箇所にモザイクをかけるためのループ
for(x,y,w,h) in faces:
    # モザイクをかける
    img = mosaic(img,(x,y,x+w,y+h),10)

# 画像保存
cv2.imwrite('facedata_photo.png',img) 
# Do a bit of cleanup
print("\n Exit Program")