Help us understand the problem. What is going on with this article?

[Python, OpenCV]動画から検出した円をぴえんに変換する

動画を作りました。よろしければご視聴ください。
https://youtu.be/4xfmPCFUplU

ぴえんという顔文字をご存じでしょうか。
2019年ぐらいからJKやJCの間で流行りはじめた顔文字で、2020年には上半期のインスタ流行語大賞に選ばれたらしいです。
実際に見てもらった方が早いですね。

002・pien.png

いつからか誰かがこの顔文字と一緒に「ぴえん」という単語を使い始めて、それが定着してこの顔文字自体がぴえんと呼ばれるようになった・・・らしいです。

なんというかカルト的な人気を博したこのぴえん🥺ですが、この顔をした八頭身に追いかけられるようなゲームが出たり、「ぴえんこえてぱおん」というまた新しいよくわからない単語が登場したりしています。

さて、今回はこのぴえんをPythonとOpenCVを使ってカメラの映像に表示したいと思います。
まだどちらも触って1,2ヶ月程度なのでおかしな部分があるかもしれませんが、よろしくお願いします。

開発環境

  • macOS Catalina(使っているのはMacBookPro Mid 2014)
  • Python 3.7.7
  • numpy 1.18.5
  • OpenCV 3.4.2

Anacondaで仮想環境を作成しています。
カメラはeMeetのNovaを使っています。

ソース

pien.py
# -*- coding: utf-8 -*-
import cv2
import numpy as np

#カメラの取得
cap = cv2.VideoCapture(1)

while True:
    ret, frame = cap.read()
    #ハフ変換用にリサイズし、グレーカラーに変更
    frame = cv2.resize(frame, dsize=(640, 480))
    gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
    gray = cv2.GaussianBlur(gray, (33, 33), 1)

    #ハフ変換による円形の抽出
    circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 60, param1=10, param2=85, minRadius=1, maxRadius=80)

    #変換結果がある場合にぴえんの描写を行う
    if circles is not None:
        circles = np.uint16(np.around(circles))
        for i in circles[0,:]:
            #i[0]=x座標 i[1]=y座標 i[2]=半径
            x = i[0]; y = i[1]; r = i[2]
            #cv2.circleは円形 cv2.ellipseは楕円や楕円弧
            #輪郭
            cv2.circle(frame, (x, y), r, (0, 215, 255), -1)
            #眉毛右
            cv2.ellipse(frame, (x+int(r*2/3), y-int(r*2/3)), (int(r/3), int(r/4)), 0, 90, 165, (19, 69, 139), 3)
            #眉毛左
            cv2.ellipse(frame, (x-int(r*2/3), y-int(r*2/3)), (int(r/3), int(r/4)), 0, 15, 90, (19, 69, 139), 3)
            #涙右
            cv2.circle(frame, (x+int(r*2/5), y), int(r*3/10), (255, 255, 255), -1)
            #涙左
            cv2.circle(frame, (x-int(r*2/5), y), int(r*3/10), (255, 255, 255), -1)
            #黒目右
            cv2.circle(frame, (x+int(r*2/5), y-int(r/15)), int(r*3/10), (0, 0, 0), -1)
            #黒目左
            cv2.circle(frame, (x-int(r*2/5), y-int(r/15)), int(r*3/10), (0, 0, 0), -1)
            #白目大右
            cv2.ellipse(frame, ((x+int(r/3), y-int(r/6)), (int(r/3), int(r/4)), 135), (255, 255, 255), -1)
            #白目大左
            cv2.ellipse(frame, ((x-int(r/2), y-int(r/6)), (int(r/3), int(r/4)), 135), (255, 255, 255), -1)
            #白目小右
            cv2.ellipse(frame, ((x+int(r/2), y), (int(r/10), int(r/15)), 135), (255, 255, 255), -1)
            #白目小左
            cv2.ellipse(frame, ((x-int(r/3), y), (int(r/10), int(r/15)), 135), (255, 255, 255), -1)
            #口
            cv2.ellipse(frame, (x, y+r), (int(r/4), int(r/2)), 0, 245, 295, (19, 69, 139), 5)

    #ウィンドウにカメラの映像を表示 この時点でframeにはぴえんが描写されている
    cv2.imshow("frame", frame)

    #qキーを押したら終了する
    if cv2.waitKey(1)&0xff == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()

コードの説明はそのままコメントで残しました。
重要なのは中程のハフ変換による円形の検出部分と、検出した円の座標・半径をもとにぴえんを作成する部分です。
ぴえんは画像を貼り付けているわけではなく、全て円と線で描画しているので、どんな大きさにも対応できるようになっています。
文字列も描写できるので🥺をそのまま使えないかと思ったのですがダメでした。

やってみた結果

仮想環境をconda activateした上でpien.pyを実行すると、カメラからの映像がウィンドウで表示されるかと思います。
そこでカメラを丸いものに向けてみましょう。

001・pien.gif

ぴえんになりました🥺
しっかり大きさが違ってもそれに合わせて変換されていますね。
今回は円を検出しているので、円の中に何が入っているかは特に関係ありません。時計でもキャップでもメガネでもぴえんになります。
コードを丸くすればそれもぴえんになります。
ちなみに瞳もぴえんになりました。(🥺ω🥺)みたいな感じです。

OpenCVを使えば円だけでなく例えば人の顔も検出できます。
つまりカメラに移った顔を全て🥺にすることができるということです。
そこら辺はそのうち試してみたいと思います。

aki0141
中野のシステム会社で広報をしています。
https://maeni.avant-sl.com/
avant
システム構築・システムコンサルティングをはじめ、ARやドローン、AIなど最先端技術の研究開発を行っています。
https://avant-sl.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away