【笑い男事件2024】OpenCVで顔を検出して笑い男にする

# 笑い男事件発生
Qiitaを利用しているプログラマやエンジニアのほとんどが履修してるであろう作品、「攻殻機動隊」。その中の2002年から2003年に放映されたシリーズ「STAND ALONE COMPLEX」の劇中に出てくる笑い男事件と呼ばれる一連の事件の発端が2024年の2月に起こります。

ついに、時代が追い付きました！まだ電脳化もしてないのに…ｗ。
笑い男事件の詳細を知らない方は、この機会に攻殻機動隊SACを観ましょう。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">2024年2月、笑い男事件発生。<br>ここから何が始まる？詳細情報は特設サイトで…<a href="https://t.co/b4m9uAXn7u">https://t.co/b4m9uAXn7u</a><a href="https://twitter.com/hashtag/%E6%94%BB%E6%AE%BB%E6%A9%9F%E5%8B%95%E9%9A%8A?src=hash&amp;ref_src=twsrc%5Etfw">#攻殻機動隊</a> <a href="https://twitter.com/hashtag/ghostintheshell?src=hash&amp;ref_src=twsrc%5Etfw">#ghostintheshell</a> <a href="https://twitter.com/hashtag/standalonecomplex?src=hash&amp;ref_src=twsrc%5Etfw">#standalonecomplex</a> <a href="https://twitter.com/hashtag/%E7%AC%91%E3%81%84%E7%94%B72024?src=hash&amp;ref_src=twsrc%5Etfw">#笑い男2024</a> <a href="https://twitter.com/hashtag/thelaughingman2024?src=hash&amp;ref_src=twsrc%5Etfw">#thelaughingman2024</a></p>&mdash; 攻殻機動隊【公式】GHOST IN THE SHELL official (@thegitsofficial) <a href="https://twitter.com/thegitsofficial/status/1752859316019708093?ref_src=twsrc%5Etfw">February 1, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


Twitter(X)の公式アカウントもお祭り騒ぎです。これは攻殻ファンにはたまりませんねぇ。
アニメの限定公開や、特設サイトまでできています。

https://thelaughingman2024.jp/

笑い男といえばやはり、特徴的な笑い男マークですね。彼は自分の顔を知られないように人々の電脳をハッキングしてこのマークを表示させていました。事件発生を記念して、上記の特設サイトでは作中で出てきたものとは少し違った記念版の画像が配布されています。劇中ではマークの縁の文字が「I thought what I'd do was, I'd pretend I was one of those deaf-mutes(僕は耳と目を閉じ、口をつぐんだ人間になろうと考えた)」となっていたところが、「The Laughing Man Incidente 0th Anniversary:February 2024(笑い男事件0周年:2024年2月)」となっていますね。
粋なことするなぁ、公式。
![img_mark_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413678/bbdeffdf-d5c7-cd88-d401-90ab7377662e.png)


というわけで、この画像を使ってプログラムを作ってみることにしました。目指せ特A級ハッカー。

# 実装

タイトルにある通り、画像や動画処理用のライブラリであるOpenCV (https://opencv.org/) を使って写真から認識した顔の位置に笑い男マークを張り付けるプログラムを作ります。言語はPythonを使います。今回使ったPythonのバージョンは3.10.6です。

OpenCVをインストールするときはコマンドラインで以下のコマンドを実行します。
```
pip install opencv-python
```

OpenCVを使って画像から人の顔を識別するには人の顔を学習させたモデルである「カスケード分類器」と呼ばれるものを使います。今回は[こちら](https://github.com/opencv/opencv/tree/4.9.0/data/haarcascades)から正面からの顔を認識するカスケード分類器「haarcascade_frontalface_default.xml」をダウンロードして使います。
Pythonのパッケージの中には`pip install`のときに入れられたものがあるらしいけど、探すのめんどいんでこっちを使いますｗ。

ソースコードは以下の通り。
```python:thelaughingman.py
import os # ファイル関係いじるので
import cv2 # OpenCVのPython用ライブラリ

# 入力画像のファイルパス
path = 'input_img/(入力画像のファイル名)'

# ファイルがなければプログラム終了
if not os.path.exists(path):
    print(("No File!"))
    exit()

# 入力画像の読み込み
input_img = cv2.imread(path)
# 笑い男マークの読み込み(アルファチャンネルで)
laughingman = cv2.imread('img/img_mark_01.png', cv2.IMREAD_UNCHANGED)

# カスケード分類器の読み込み
cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 顔の検出, パラメータは適当に変えてください
face = cascade.detectMultiScale(input_img, scaleFactor=1.1, minNeighbors=3, minSize=(75, 75))

for (x, y, w, h) in face:
    # 画像合成用にコピー
    laughingman_tmp = laughingman.copy()
    # 顔のサイズに合わせる
    laughingman_tmp = cv2.resize(laughingman_tmp, dsize=(w, h))

    # 入力画像の顔の部分にはめ込む
    for dx in range(0, w):
        for dy in range(0, h):
            # 透過していなければ画像を入れ替える
            if laughingman_tmp[dy, dx, 3] != 0:
                for i in range(0, 3):
                    input_img[y + dy, x + dx, i] = laughingman_tmp[dy, dx, i]

# 画像の出力
cv2.imwrite('output_img/(出力画像のファイル名)', input_img)
cv2.waitKey(0)
```

ディレクトリ構造は次のようにします。
```
thelaughingman
├ thelaughingman.py -ソースコード
├ haarcascade_frontalface_default.xml -学習済みカスケード分類器
├ img -笑い男マークの画像を入れるフォルダ
│ └ 笑い男の画像
├ input_img -入力画像を入れるフォルダ
│ └ 入力画像
└ output_img -入力画像を入れるフォルダ
  └ 出力画像
```

さっそく実行してみます。サンプル画像は[神奈川工科大学 情報学部 情報工学科 信号処理応用研究室のページ](http://www.ess.ic.kanagawa-it.ac.jp/app_images_j.html)からダウンロードしました。


入力画像
![Lenna.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413678/7735a417-cca0-351d-5c8b-6c4c43964522.png)

出力画像
![thelaughingman.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413678/5c3a9280-8471-f257-bcb1-047cd088abb2.png)


みんな大好きレナさんも笑い男に電脳をハックされしまいました。

OpenCVと学習済みカスケード分類器を使えば簡単に笑い男的なことができました。彼も電脳向けのOpenCV的なライブラリを使ってたんでしょうか？

# 最後に

現実では全然電脳化も義体化もまだまだ技術的に無理っぽいですね。少佐みたいに全身義体の人が現れるのはいつ頃になるんでしょうか…。はよ電脳化したいなぁ。

ちなみに私事ですが、この記事を書いている現在、大学の卒論の締め切りが1週間を切っています。ヤバいです。本当は笑い男とか言ってる場合じゃないです。でもきっと卒業できると信じています。そう囁くのよ、私のゴーストが…(卒論書け)。