BETA

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

投稿日:2019-10-12
最終更新:2019-11-01

OpenCVで顔検出した箇所にモザイク画像をつける
使ったツールバージョンは以下

  • MacOS Catalina / python3.5.6 / Opencv3.4.2 / VS code1.38.1

コメント

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

概要

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

イメージ画像(その1)

ファイル構成(その1)

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

ソースコード(その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)


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

ファイル構成(その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")  
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

@主にプログラム技術ブログ

よく一緒に読まれる記事

6件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
10/17 11:26

はじめまして、ka2norinoma と申します。(まだ記事が書けるほどのスキルもなく..) 記事を拝見いたし、とてもためになりました。私の環境でも動作させることができ、感謝いたしております。 もし可能であれば教えてください。 カメラからの画像ではなく、画像ファイル(上記サンプルにあるような)を指定して、それを対象とするにはどのようにすればよろしいでしょうか? お手数ですが、ご指導のほどよろしくお願い申し上げます。

10/17 21:19

@ka2norinoma さん 参考にしていただきありがとうございます。 自分もまだ勉強中で試行錯誤中です。 参考までにコードを添付しますね。

# 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('human.png')

# 最小Windowサイズを定義
minW = 0.1*640
minH = 0.1*480

##### モザイクをかけるメソッド ######
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('mosaic_photo.png',img) 
# Do a bit of cleanup
print("\n Exit Program")
10/21 09:50

返事が遅れましてすみません。 サンプルコードのご提供心より感謝いたします。早速今晩試してみようと思います。 横向きの顔については別途学習が必要なのですかね? 例えば、公園で撮った写真に写り込んだ人物(親、子ども)の顔にモザイクをかけたいのですが、そもそもの写り込みが小さいので難しそうだなと考えております。

10/21 23:27

@ka2norinoma さん ご返信ありがとうございます。本ページを更新しましたのでご確認頂ければ幸いです。顔検出は「haarcascade_frontalface_alt2」のカスケードファイルに依存するため、なんとなく横向きは難しそうです。少し斜めぐらいでしたら検出は可能と思います。横向き顔検出の実現性については時間がありましたら調べてみようと思います(深層学習が濃厚)。写り込みが小さい顔については、detectMultiScaleのminSizeを変更することで可能と思います(サイズにもよりますが...)。一度お試しください。

10/24 16:39

@Atomさん、早速のご対応ありがとうございます。さすがというか素早さに脱帽です。 サイズ縮小版を試してみましたところ、15x19pxのサイズの顔までモザイクがかかりました。 鮮明な顔の画像を少しずつ小さく縮小した画像で試してみました。ただ、元が不鮮明な画像だと そもそもの顔認識ができないようで、同じ15x19pxでも当然モザイクは掛かりませんでした。 ちなみにサイズ縮小版ではない当初の画像ファイル読み込み版だと、43x55pxまでモザイクが 掛かりました。

10/24 20:37

@ka2norinomaさん ご確認いただきありがとうございました。ご希望のサイズなのかわかりませんが、小さいサイズまでモザイクかけることができてよかったです。また何かありましたらコメントください。よろしくお願いします!

目次をみる
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
or 外部アカウントではじめる
10秒で技術ブログが作れます!