LoginSignup
0
1

More than 1 year has passed since last update.

OpenCVで画像を読み込んで顔を検出して丸く加工し、それ以外はぼかしをかける

Posted at

はじめに

題名の文章では伝わりにくいので、始めにサンプルを(ぱくたそさんから拝借)

  • 加工前
    sample.jpg

  • 加工後
    blursample.jpg

環境

  • Windows10
  • Python 3.9.4
    ※python3.6以降とかであれば問題ないかと

pip

python -m pip install cv2
python -m pip install numpy

コード

blur_except_face.py
import cv2
import logging
import numpy as np
import os
import sys


"""
指定画像に対して、顔を検出してそれ以外はモザイクをかけた画像を出力する

Parameters
----------
args[1] : 読み込み画像パス
args[2] : 出力画像パス
"""


def get_detect_data(face_cv2img):
    """
    検出処理

    Parameters
    ----------
    face_cv2img : numpy.ndarray(cv2画像読み込みデータ)
        モザイク加工前のcv2データ

    Returns
    -------
    detect_data : numpy.ndarray
        検出データ(座標とサイズ)
    """

    # 検出設定
    SCALE_FACTOR = 1.11
    MIN_NEIGHBORS = 3
    MIN_SIZE = (5, 5)
    CASCADE_XML = "haarcascade_frontalface_default.xml"

    # 検出速度向上のため、モノクロにする
    gray_img = cv2.cvtColor(face_cv2img, cv2.COLOR_BGR2GRAY)

    # カスケード分類器を設定
    cascade = cv2.CascadeClassifier(os.path.join(cv2.data.haarcascades, CASCADE_XML))

    # 検出処理&検出データ取得
    detect_data = cascade.detectMultiScale(
        gray_img, scaleFactor=SCALE_FACTOR, minNeighbors=MIN_NEIGHBORS, minSize=MIN_SIZE
    )

    return detect_data


def make_blurimg_except_face(face_cv2img, detect_data):
    """
    顔以外のぼかし画像を作成

    Parameters
    ----------
    face_cv2img : numpy.ndarray(cv2)
        モザイク加工前のcv2データ(cv2画像読み込みデータ)
    detect_data : numpy.ndarray
        検出データ(座標とサイズ)

    Returns
    -------
    blur_face_img : numpy.ndarray(cv2)
        顔検出してぼかし加工したcv2データ
        ※検出が出来ない時は、すべてぼかし
    """

    # ぼかしの強弱
    BLUR_SIZE = (20, 20)

    # 下地のぼかし画像を作成する
    blur_face_img = cv2.blur(face_cv2img, BLUR_SIZE)

    # 検出できているか(出来ていない場合は、モザイク画像をそのまま返す)
    if len(detect_data) > 0:
        # 検出値のループ処理
        for loc_x, loc_y, size_w, size_h in detect_data:

            # 検出内容を抽出
            detect_img = face_cv2img[loc_y : loc_y + size_h, loc_x : loc_x + size_w]

            # 円形マスク画像の作成
            mask_img = np.zeros((size_h, size_w), dtype=np.uint8)
            cv2.circle(
                mask_img,
                center=(size_h // 2, size_w // 2),
                radius=max(size_h, size_w) // 2,
                color=255,
                thickness=-1,
            )
            # 検出画像をマスク画像を使って円形にする
            detect_img[mask_img == 0] = [0, 0, 0]

            # RGBA形式に変換する
            detect_img_rgba = cv2.cvtColor(detect_img, cv2.COLOR_RGB2RGBA)

            # 黒の部分を透明にする
            detect_img_rgba[..., 3] = np.where(np.all(detect_img == 0, axis=-1), 0, 255)

            # 下地のぼかし画像に検出画像を上に重ねる
            blur_face_img[loc_y : size_h + loc_y, loc_x : size_w + loc_x,] = (
                blur_face_img[
                    loc_y : size_h + loc_y,
                    loc_x : size_w + loc_x,
                ]
                * (1 - detect_img_rgba[:, :, 3:] / 255)
                + detect_img_rgba[:, :, :3] * (detect_img_rgba[:, :, 3:] / 255)
            )

    return blur_face_img


if __name__ == "__main__":

    # コマンド引数取得
    args = sys.argv
    # 引数エラー処理
    if len(args) == 3:
        # パス取得
        base_photo_path = args[1]
        make_photo_path = args[2]

        # ベース画像取得
        face_cv2img = cv2.imread(base_photo_path)

        # 画像ファイルとして読み込めたとき
        if face_cv2img is not None:
            # 検出処理
            detect_data = get_detect_data(face_cv2img)
            # モザイク画像作成
            blur_face_img = make_blurimg_except_face(face_cv2img, detect_data)
            # 画像をファイル出力
            cv2.imwrite(make_photo_path, blur_face_img)
        else:
            # 指定パスに画像がないとき
            print("Can not file reading")

実行方法

python blur_except_face.py sample.jpg blursample.jpg

※引数は [読み込みファイル名] [出力ファイル名]

参考

さいごに

透過の扱いが難しい、、、

0
1
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
0
1