Xacti社の360°Web会議カメラにAI機能を実装する#6

はじめに

これまで、第1回から第5回目まで、各機能について解説を行ないました。今回はまとめとして、実際の会議の様子をご紹介します。なお、諸事情により静止画での説明となります。動画も確認したいという場合は、OpenVINO.jpまでお問い合わせください。

Xacti社の360°Web会議カメラ CX-MT100

Xacti社 360°Web会議カメラ CX-MT100をテーブルの中心に配置し、上下パノラマモードで撮影するとこのような動画が撮影できます。

Web会議画面の構成

青色の枠はPerson detection、緑色の枠はFace detectionで検出した結果です。認識した領域を切り出す事で、Web会議画面を構成します。

Web会議画面その1

Web会議画面その1です。上部に参加者を、下部に全体の様子を表示しています。参加者それぞれを認識し、名前、所属などを表示します。

Web会議画面その2

Web会議画面その2です。4人の参加者を切り出しています。参加者それぞれを認識し、名前、所属などを表示します。

話者特定機能

ミーティング中の話者を特定する機能です。facial-landmark detectionを利用して、上唇と下唇(緑色の点)を検出します。mouthで表示されているのが上唇と下唇の差分を数値化したものです。

OCR機能

会議室にある、ホワイトボードに記載した文字を読み取る機能です。

ホワイトボードのズームをONにした画面です。

認識したテキスト領域を示すウィンドウ(右)と、検出した文字のウィンドウ(左)を表示しています。

上下パノラマモードに対してOCRを行なった例です。

認識したテキスト領域を示すウィンドウ(右)と、検出した文字のウィンドウ(左)を表示しています。

まとめ

今回で「Xacti社の360°Web会議カメラにAI機能を実装する」の短期連載が終了となります。OpenVINOを利用する事で、様々なシーンへのAI活用が可能ですので、ぜひ検討してみてください。検討や実装にあたって不明な点などがありましたら、お気軽にOpenVINO.jpまでお問い合わせ頂けると嬉しいです。

最後になりますが、今回の実装にあたって、yas-simさんのプログラム(https://github.com/yas-sim)が非常に参考になり助かりました。ありがとうございました。

Xacti社の360°Web会議カメラにAI機能を実装する#5

はじめに

前回、第4回目として「ミーティング中の話者を特定する機能」について説明しました。

今回は ホワイトボードのOCR機能について解説します。

OCR機能

会議室にある、ホワイトボードに記載した文字を読み取る機能です。

実際のソースは以下にありますので、ご確認ください。なお、OCR機能については、OpenVINOを利用した実装とGoogle Cloud Vision APIを利用した実装の両方に対応しています。

https://github.com/OpenVINO-jp/360camera-meeting-demo/blob/main/meeting_demo.py

https://github.com/OpenVINO-jp/360camera-meeting-demo/blob/main/text_detect_OpenVINO.py

https://github.com/OpenVINO-jp/360camera-meeting-demo/blob/main/text_detect_gcp.py

使用モデル

  • text-detection
    • /intel/text-detection-0003/FP16/text-detection-0003
  • handwritten-japanese-recognition
    • /intel/handwritten-japanese-recognition-0001/FP16/handwritten-japanese-recognition-0001

meeting_demo.py

main()

今回はmain()内に関係する部分はありません。

callback()

以下はcallback()内の呼び出し部分です。ここではキーを押したタイミングでopenVINO_detect(),gcp_detect() を呼び出す実装にしました。

実際には、ホワイトボードの隅など特定のエリアを手でポイントした時にOCRを実行する等のアイデアが考えられます。

    key = cv2.waitKey(1)

    if key == ord("t"):
        ## toggle 0 -> 1 -> 2 -> 0
        flgWindow_mode += 1
        if flgWindow_mode > 2:
            flgWindow_mode = 0

    elif key == ord("w"):
        if flgWiteboard_mode == True:
            flgWiteboard_mode = False
        else:
            flgWiteboard_mode = True

    elif key == ord("g"):
        ##Google CloudVisionAPI
        gcp_detect(img)
        
    elif key == ord("i"):
        ##intel OpenVINO
        openVINO_detect(img)

関数定義部分

## --- gcp OCR ---
def gcp_detect(target_image):
    cv2.imwrite(detect_temp_path,target_image)
    gcp_d.detect_text(detect_temp_path)
## --- gcp OCR ---

## --- OpenVINO OCR ---
def openVINO_detect(target_image):
    cv2.imwrite(detect_temp_path,target_image)
    openvino_d.detect_text(detect_temp_path)
## --- OpenVINO OCR ---

text_detect_OpenVINO.py

以下を参考させて頂きました。ありがとうございます。

https://github.com/yas-sim/openvino_open_model_zoo_toolkit

https://github.com/yas-sim/handwritten-japanese-ocr

text_detect_OpenVINO.pyは日本語認識に必要な処理を1つのファイルにマージした内容です。テキストの領域検出を行い、日本語認識を行っています。

気づき

今回、手書き日本語処理を行いましたが、以下の気づきがありました。

  • ホワイトボードマーカーは太字を推奨。細いと認識率が落ちます。
  • もちろん綺麗な字が望ましい
  • 部屋の明るさなどもかなり影響する
  • 読み込む画像に対しての前処理が重要
    • cv2.imread(path,cv2.IMREAD_GRAYSCALE) -> cv2.threshold
    • 自動検出(cv2.THRESH_OTSU)は期待どおりにならない
    • cv2.THRESH_BINARYの閾値を調整する必要がある
  • ホワイトボードを拡大した画像を入力にすると認識率が下がる場合がある
    • 認識させる画像と、 人が見る画像を変えるなどの工夫をする

まとめ

第5回目として、ホワイトボードのOCR機能について解説しました。気づきにも書きましたが、実際は様々な要素が関係してくるため、細かいチューニングが必要になってくると思います。ぜひ試してみてください。

余談となりますが、私自身、最近は様々なRPA製品を扱う機会も多く、OCR機能を試す場合があるのですが、OCR機能よりも前に、自分自身の文字の汚さを思い知らされる結果となり大変困っています。どなたか綺麗な字の書き方をご指導頂けると非常に嬉しいです。

Xacti社の360°Web会議カメラにAI機能を実装する#4

はじめに

前回、第3回目として「参加者の名前、所属などを表示する部分(reidentification)」を説明しました。

今回は OpenVINOを利用してミーティング中の話者を特定する機能について解説します。

話者の特定機能

実際のソースは以下にありますので、合わせてご確認ください。

https://github.com/OpenVINO-jp/360camera-meeting-demo/blob/main/meeting_demo.py

https://github.com/OpenVINO-jp/360camera-meeting-demo/blob/main/reidentification.py

使用モデル

  • facial-landmark detection
    • intel/facial-landmarks-35-adas-0002/FP16/facial-landmarks-35-adas-0002

reidentification.py

reidentificationを実行するタイミング(前回記事参照)で、同時にfacial-landmark detectionを実行します。

fncMouthValue()

facial-landmark detectionを利用すると、顔の部分に番号が振られるイメージです。

上唇の場所は10番目、下唇の場所は11番目で取得できます。

fncMouthValue()内で、10番目と11番目の差分を取得します。

meeting_demo.py

main()

今回はmain()内に関係する部分はありません。

callback()

fncMouthValue()で上唇・下唇の差分を数値化し、fncWhoisSpeaker()で話者特定処理を実行します。

fncWhoisSpeaker()

画像のみで話者特定を行う方法について、その考え方を図にしてみました。簡単に言うと「一定時間内に一番口をパクパク動かした人」を話者として特定(推定)するという考え方になります。

図の説明

  • 縦はミーティング参加者、横の番号はコマ番号です。
  • 顔のマークは、口を開けている状態、閉じている状態を表しています。
  • mの数値は、上唇下唇の差分例です。
    • 口を開いている場合、mの値が大きくなります。
    • 例:Tanakaさんの 2コマ目はm:53
  • dの数値は、コマ間の差分です。
    • 例:Tanakaさん 1コマ目(m:17)と2コマ目(m:53)の差分は36となります。

処理の流れ

  1. コマ1-コマ2間で一番大きいdの数値を持っている人を確認します。図ではTanakaさんがd:36で一番大きい値です。オレンジ色にマークします。
  2. 同じように、コマ2-コマ3間でdを確認します。図ではSatoさんがd:21で一番大きい値です。オレンジ色にマークします。
  3. コマ5-コマ6まで同じように確認します。
  4. コマ1からコマ6の間のオレンジマークの回数を確認します。Tanakaさんが3回、Suzukiさんが1回、Satoさんが2回、Takahashiさんが0回となりました。
  5. Tanakaさんを話者として推定し、大写し(左上エリア)にします。
  6. 以降、処理を繰り返します。

気づき

実際の会議の動画を使って開発・検証を行いましたが、以下の状況がありました。

  • 口が開きがちになる人
  • 喋るときに唇をそれほど動かさない人
  • 口付近に手を置きがちなクセの人
  • 会議が白熱すると複数人が同時に話す

あまり頻繁に大写しを切り替えると画面遷移が忙しくなってしまうため、タイムアウト時間を調整する必要があると思います。

まとめ

第4回目として、ミーティング中の話者を特定する機能について解説しました。

画像のみで話者を特定するのは結構厳しいかなあという感じでしたが、「一定時間内に一番口をパクパク動かした人」という考え方で、ある程度期待した結果を得る事が出来ました。

実際にはマスク着用という状況もあると思うので、指向性マイクを併用した話者特定を行うのが良いと思います。

次回はOCR機能を説明したいと思います。

Xacti社の360°Web会議カメラにAI機能を実装する#3

はじめに

前回、第2回目として「Web会議画面の構成」について概要を説明しました。

第3回目は「Web会議画面の構成」の続きとして、参加者の名前、所属などを表示するという部分(reidentification)になります。

処理概要

以下の流れで参加者の名前、所属を表示しています。

  1. 事前に参加者の情報(顔画像、名前、所属)を読み込んでDBを作成する
  2. person detect. / face detect で切り出した領域の画像をDBで確認
  3. 近しい人と判断した場合にDB内の情報を取得
  4. person detect. / face detect で切り出した領域の画像に情報(名前、所属)を記載
  5. 画面を構成する

Web会議画面の構成

実際のソースは以下にありますので、合わせてご確認ください。前回記事のソースに加えて、reidentification.pyが追加になっています。

https://github.com/OpenVINO-jp/360camera-meeting-demo/blob/main/meeting_demo.py

https://github.com/OpenVINO-jp/360camera-meeting-demo/blob/main/tile_resize.py

https://github.com/OpenVINO-jp/360camera-meeting-demo/blob/main/reidentification.py

使用モデル

  • Person Detection
    • intel/pedestrian-detection-adas-0002/FP16/pedestrian-detection-adas-0002
  • Face Detection
    • intel/face-detection-adas-0001/FP16/face-detection-adas-0001
  • Person reidentification
    • intel/person-reidentification-retail-0288/FP16/person-reidentification-retail-0288

meeting_demo.py

main()

オレンジ色の部分が前回記事からの追加分です。f_reid.preloadimage()で個人認識用に用意した画像を読み込み、DBを作成しています。

callback()

fnc_Reid()の処理で、検出した参加者の領域に対してreidentificationを実行します。DB内に近しい顔が読み込まれていた場合、同一人物と判定し、名前、所属を表示します。

reidentification.py

preloadimage()

参加者のデータは、meeting_member.ymlに以下のように定義しています。

member:
#
  -
    EmployeeID: "12345"
    FirstName:
    LastName: Sato
    Section: Sales Div.1
    Position: 2
#
  -
    EmployeeID: "23456"
    FirstName:
    LastName: Suzuki
    Section: Research
    Position: 1
#
  -
    EmployeeID: "34567"
    FirstName:
    LastName: Takahashi
    Section: Develop
    Position: 3
#
  -
    EmployeeID: "45678"
    FirstName:
    LastName: Tanaka
    Section: Sales Div.2
    Position: 0

#  -
#    EmployeeID: "abcde"
#    FirstName: test
#    LastName: test
#    Section: test div

meeting_memberに対応した顔データとして、\rsc\face配下に画像データを格納します。preloadimage()で顔データを読み出し、DBに格納します。なお、フォルダ配下のファイルは列挙するため、ファイル名は問いません。

顔データ画像を採取するオプションはプログラムに付けていませんが、以下の方法で増やす事ができます。

  1. meeting_demo.py – def main()内の、f_reid.PreloadImage() ## preload files for build db をコメントアウトする。
  2. reidentification.py – def fncReid()内の、 #cv2.imwrite(face_dir + str(feature_db[-1][‘time’]) + ‘.jpg’, feature_db[-1][‘img’]) のコメントを外す
  3. meeting_demo.py実行すると、rsc/face配下に顔データが保存されるので、手作業で該当するフォルダに配置する

tile_resize.py

前回記事と同様に、Person detection、または、Face detectionで検出した人物の領域を切り出して、会議用の画面を構成します。画面構成前に、既に名前と所属が記載された画像になっているので、あとは画面を構成するだけです。

まとめ

第3回目は「Web会議画面の構成」の続きとして、参加者の名前、所属などを表示するという部分(reidentification)を説明しました。

次回はミーティング中の話者を特定し大写しにする機能の予定です。

Xacti社の360°Web会議カメラにAI機能を実装する#2

はじめに

前回、第1回目として、Xacti社のWebカメラ紹介と、全体の概要を説明しました。

今回から各機能の概要について説明します。第2回目は「Web会議画面の構成」の機能となります。

Web会議画面の構成の概要(おさらい)

「Web会議画面の構成」って何だ?という事で、まずは前回のおさらいです。

Xacti社Webカメラの上下パノラマモードで撮影するとこのような動画が撮影できます。

ここからOpenVINOで人や顔を認識し、認識した領域を切り出す事で、Web会議画面を構成します。

Web会議画面その1です。上部に参加者を、下部に全体の様子を表示しています。

参加者それぞれを認識し、名前、所属などを表示します。

Web会議画面その2です。4人の参加者を切り出しています。

参加者それぞれを認識し、名前、所属などを表示します。

使用モデル

今回はPerson detection, Face detection の内容について説明します。Person reidentificationは次回を予定しています。

  • Person Detection(今回)
    • intel/pedestrian-detection-adas-0002/FP16/pedestrian-detection-adas-0002
  • Face Detection(今回)
    • intel/face-detection-adas-0001/FP16/face-detection-adas-0001
  • Person reidentification(次回)
    • intel/person-reidentification-retail-0288/FP16/person-reidentification-retail-0288

参考にさせて頂いたプログラム

Web会議画面の構成については、openvino-wrapperの「iewrap_object_detection_async.py」をベースに作成しましたので、まずはそちらを確認してみましょう。

https://github.com/yas-sim/openvino-wrapper

なお、処理の流れを示すためにPAD(Problem Analysis Diagram)図を利用しました。全てのステップを図示するのは大変なので主な部分のみ記載しています。

色付きの部分がポイントとなる部分です。

main()

Webカメラ、動画で撮影した内容を1コマずつ取り出し、OpenVINOで推論を行うという動作になります。モデルはmobilenet-ssdです。

main処理

callback()

推論が実行されるとcallbackが呼び出されます。何か検出した場合(ここでは60%以上の閾値)、検出した領域に対して四角とラベルを描画しています。

callback()

ここまでのまとめ

  1. 動画やWebカメラから1枚取り出す
  2. OpenVINOで推論
  3. 検出したものに枠をつける

Web会議画面の構成を確認してみましょう

openvino-wrapperの「iewrap_object_detection_async.py」をベースに、Person detectionとFace detectionを行い、検出した領域を切り出して結合する事で、Web会議画面を実現します。

実際のソースは以下にありますので、合わせてご確認ください。

https://github.com/OpenVINO-jp/360camera-meeting-demo/blob/main/meeting_demo.py

https://github.com/OpenVINO-jp/360camera-meeting-demo/blob/main/tile_resize.py

meeting_demo.py

main()

モデルをPerson detectionに変更した以外は、ほぼ同じ流れとなります。

main()

callback()

callback()

tile_resize.py

Person detection、または、Face detectionで検出した人物の領域を切り出して、会議用の画面を構成します。cv2.hconcatやcv2.vconcatでサイズが異なる画像を結合するとエラーになりますので注意が必要です。

まとめ

第2回目として「Web会議画面の構成」について概要を説明しました。まずは、openvino-wrapperの「iewrap_object_detection_async.py」を試すことが早道だと思います。ぜひご確認ください。

次回はPerson reidentificationを利用して、画面に映っている人を認識し、名前や所属を表示する機能を説明したいと思います。

Xacti社の360°Web会議カメラにAI機能を実装する#1

はじめに

Xacti社の360°Web会議カメラ CX-MT100を利用する機会があり、OpenVINOを利用してAI機能を追加する実験を行いました。

第1回目の内容はWebカメラの紹介と、全体の概要となります。

Xacti社の360°Web会議カメラ CX-MT100

製品公式ページは以下となります。

https://xacti-co.com/products/360camera/

Withコロナという事で、Web会議を利用する機会が増えていますね。拠点の会議室同士を繋いでWeb会議をする場合、大型モニタにWebカメラを設置し、正面から撮影するというパターンが多いと思います。

このカメラは上下パノラマモード、超広角モードという2種類のモードで撮影出来るWebカメラです。会議室の写し方次第で、Web会議の質が変わってくる可能性がありますね。

左上から、本体、台座、USBケーブル。左下の黒いのはレンズキャップです。

89.6 x 89.6 x 46.0mmという事で、結構コンパクトですね。

カメラを縦置きにすると、自動で超広角モードに切り替わります

実現機能の概要と使用モデル

OpenVINOを使って、以下のAI機能を実現したいと思います。
各機能の詳細については、次回以降に順次解説する予定です。

  • Web会議画面の構成(参加者の領域切り出し、属性の表示)
  • 話者の特定機能
  • ホワイトボードOCR機能

また、使用したモデルについては例として記載しています。他のモデルも確認すると適切なモデルが見つかる可能性がありますので試して頂ければと思います。

なお、Webカメラは中央に設置し、撮影モードは上下パノラマモードを利用しました。

Webカメラを会議室の中央に配置

パノラマモードで撮影するとこのような動画になります。

Web会議画面の構成

概要

上下パノラマモードで撮影するとこのような動画が撮影できます。

ここからOpenVINOで人や顔を認識し、認識した領域を切り出す事で、Web会議画面を構成します。

Web会議画面その1です。上部に参加者を、下部に全体の様子を表示しています。

参加者それぞれを認識し、名前、所属などを表示します。

Web会議画面その2です。4人の参加者を切り出しています。

参加者それぞれを認識し、名前、所属などを表示します。

使用モデル

  • Person Detection
    • intel/pedestrian-detection-adas-0002/FP16/pedestrian-detection-adas-0002
  • Face Detection
    • intel/face-detection-adas-0001/FP16/face-detection-adas-0001
  • Person reidentification
    • intel/person-reidentification-retail-0288/FP16/person-reidentification-retail-0288

話者の特定機能

概要

ミーティング中の話者を特定し大写しにします。指向性マイクがないことを想定し、Facial Landmarkの口の動き(画像の上唇:10番、下唇:11番)を利用し、話者特定を行ってみます。

Facial Landmarkの35箇所のポイント。上唇(10番)、下唇(11番)を利用

使用モデル

  • Person detection
    • intel/person-detection-retail-0013/FP16/person-detection-retail-0013
  • Face detection
    • intel/face-detection-retail-0005/FP16/face-detection-retail-0005
  • Reidentification
    • intel/person-reidentification-retail-0288/FP16/person-reidentification-retail-0288
  • Facial landmarks
    • intel/facial-landmarks-35-adas-0002/FP16/facial-landmarks-35-adas-0002

ホワイトボードOCR機能

概要

ホワイトボードに書いた文字を認識し、再利用しやすいように別ウィンドウで表示します。

使用モデル

  • intel/text-detection-0003/FP16/text-detection-0003
  • intel/handwritten-japanese-recognition-0001/FP16/handwritten-japanese-recognition-0001

参考にさせて頂いたプログラム

実装にあたって、openvino_open_model_zoo_toolkit、openvino-wrapperを借用させて頂きました。ありがとうございます。

https://github.com/yas-sim/openvino_open_model_zoo_toolkit
https://github.com/yas-sim/openvino-wrapper

まとめ

第1回目として、Webカメラの紹介と、全体の概要を説明いたしました。
次回から各機能の実装について説明したいと思います。

RaspberryPi+Neural Compute Stick2で、ネコ監視AIカメラ(LINE通知入り)を作ってみる

手前がキッチンです。

うちには猫が2匹います。キッチンに入れないように、猫ゲートを設置していますが、最近、どうやら突破している模様。

どのルートから侵入されているのか不明なので、猫カメラを作成してみましょう。

設置場所も限定されるので、Raspberry Pi(RasPi)で実装します。

RaspberryPi

OpenVINOの環境を構築済のRasPi 4とNeural Compute Stick 2(NCS2)を使いました。

OpenVINO構築については以下の記事をご参照ください。

LINE Notifyの設定

猫を検知した時にLINEで通知を行うため、LINE Notifyの設定を行います。

  • LINEで通知用グループを作成する
  • LINE Notifyでアクセストークンを発行する
  • プログラム

    openvino-wrapperを借用させて頂きました。ありがとうございます。

    https://github.com/yas-sim/openvino-wrapper

    LINE Notifyに画像を送るという部分を追記しています。

    import iewrap
    
    import time
    
    import cv2
    import numpy as np
    
    import requests,os # for LINE notify
    import base64
    
    imgBuf = {}
    label  = []
    
    send_time = time.time()
    
    def callback(infId, output):
        global imgBuf, label, send_time
    
        # Draw bounding boxes and labels onto the image
        output = output.reshape((100,7))
        img = imgBuf.pop(infId)
        img_h, img_w, _ = img.shape
    
        find_flag = False
        for obj in output:
            imgid, clsid, confidence, x1, y1, x2, y2 = obj
            #if confidence>0.4:              # Draw a bounding box and label when confidence>0.8
            if confidence>0.7 and clsid==8:
                x1 = int(x1 * img_w)
                y1 = int(y1 * img_h)
                x2 = int(x2 * img_w)
                y2 = int(y2 * img_h)
                cv2.rectangle(img, (x1, y1), (x2, y2), (0,255,255), thickness=4 )
                cv2.putText(img, label[int(clsid)][:-1], (x1, y1), cv2.FONT_HERSHEY_PLAIN, fontScale=4, color=(0,255,255), thickness=4)
                find_flag = True
    
        cv2.imshow('result', img)
        cv2.waitKey(1)
    
        # LINE_NOTIFY
        diff_time = time.time() - send_time
        if find_flag == True and diff_time > 2.0:        
            find_flag == False
            url = "https://notify-api.line.me/api/notify"
            token = "****************************************"
            headers = {"Authorization" : "Bearer "+ token}
    
            message = 'cat detected!'
            payload = {"message" :  message}
    
            _, buffer = cv2.imencode('.jpg',img)
            jpg_as_text = base64.b64encode(buffer)
            jpg_original = base64.b64decode(jpg_as_text)
            files = {"imageFile":jpg_original}
    
            post = requests.post(url ,headers = headers ,params=payload,files=files)
            print(post)
            send_time = time.time()
    
    def main():
        global imgBuf, label
        label = open('voc_labels.txt').readlines()
    
        cap = cv2.VideoCapture(0)
        cap.set(cv2.CAP_PROP_FRAME_WIDTH , 1280)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 960)
    
        ie = iewrap.ieWrapper('../models/public/mobilenet-ssd/FP16/mobilenet-ssd.xml', 'MYRIAD', 10)
        ie.setCallback(callback)
    
        while True:
            ret, img = cap.read()
            if ret==False:
                break
            refId = ie.asyncInfer(img)     # Inference
            imgBuf[refId]=img
            #time.sleep(1/30)
    
    if __name__ == '__main__':
        main()
    

    Webカメラの調整

    とりあえずゲートの正面にカメラを設置してみました。WebカメラはいつものLogicool c270です。

    猫を検知した際に、LINEに通知がきました。

    まとめ

    無事ネコ監視AIカメラを作成する事が出来ました。侵入ルートの特定はこれからですが、簡単にネコカメラが作れるのは便利ですね。

    このような仕組みを使う事で、例えば関係者以外が映ったらLINEで通知する等も簡単に出来ますね。いろいろなシーンでの活用を考えてみてください。

    Web会議のカメラをOpenVINOでカスタマイズする(RaspberryPi利用)

    コロナ禍の状況により、リモートワークが急速に普及しました。様々なWeb会議サービスがあり、使い分けをされていると思います。

    背景をぼかしたり、壁紙を変更したりという機能を活用されていると思いますが、今回はそれをOpenVINOで実現してみようという内容になります。

    なお、本記事はRaspberryPi 4Bを利用した内容になります。RaspberryPiでOpenVINOを実行する場合はNCS2が必須となりますので、予め準備をお願いします。

    全体の流れ

    Webカメラの入力(/dev/video0)をOpenVINOで処理を行った後、仮想カメラデバイス(v4l2loopback)に入れ、Web会議で利用するという流れになります。

    Raspberry Piセットアップ

    まずはOSを用意します。Raspberry Pi Imagerで作成しました。

    OSセットアップ

    vimのインストール,ufwの設定,ffmpegが入っている事を確認しました。

    Webカメラも接続しておきます。ここではLogicool c270を利用しています。

    v4l2loopback のインストール

    インストール

    sudo apt install v4l2loopback-dkms

    現在のデバイスを確認

    $ v4l2-ctl --list-devices
    bcm2835-codec-decode (platform:bcm2835-codec):
    	/dev/video10
    	/dev/video11
    	/dev/video12
    
    bcm2835-isp (platform:bcm2835-isp):
    	/dev/video13
    	/dev/video14
    	/dev/video15
    	/dev/video16
    
    UVC Camera (046d:0825) (usb-0000:01:00.0-1.1):
    	/dev/video0
    	/dev/video1

    モジュールのロード

    sudo modprobe v4l2loopback exclusive_caps=1

    必ずexclusive_caps=1の指定が必要です。

    デバイスの再確認

    $ v4l2-ctl --list-devices
    bcm2835-codec-decode (platform:bcm2835-codec):
    	/dev/video10
    	/dev/video11
    	/dev/video12
    
    bcm2835-isp (platform:bcm2835-isp):
    	/dev/video13
    	/dev/video14
    	/dev/video15
    	/dev/video16
    
    Dummy video device (0x0000) (platform:v4l2loopback-000):
    	/dev/video2
    
    UVC Camera (046d:0825) (usb-0000:01:00.0-1.1):
    	/dev/video0
    	/dev/video1

    ここではDummy video deviceとして、/dev/video2が追加されました。

    OpenVINO環境の構築

    OpenVINOが動作するように環境を構築しておきます。

    プログラム

    以下にソースを格納しました。

    https://github.com/OpenVINO-jp/WebMeetingAICamera_RaspberryPi

    実行の様子

    RaspberryPiにWebカメラを接続し、でプログラムを実行します。その状態で、Chromiumを起動し、Web会議を利用してみます。

    Web会議(ここではjitsi meetを利用)を起動すると、OpenVINOで処理を行った状態でカメラが入力されている事が確認できます。

    c270のピントを近接に調整しておきました

    OpenVINOで顔認識した領域以外にモザイクを掛け、Web会議で利用するという流れがご確認いただけると思います。

    この仕組みを利用すると、例えば、OpenVINOで姿勢推定を行い、腰以下が映り込んだ場合にカメラをオフにするという件も簡単に実装できます。他にもいろいろと応用できそうですね。ぜひご検討ください。

    ”プライバシーに配慮したAIカメラ”を、OpenVINOを使って無料で作ってみよう!

    このご時世、「お店や施設の混雑状況が分かると嬉しいですね。でもプライバシーにも配慮しないとね。」というAIカメラ製品・ソリューションがいろいろと出てきていますね。今回はそれをOpenVINOで無料でやってみようという試みです。

    実際に使う場合はいろいろと考慮する点がありますが、やっつけ的に実装していますので何かとご容赦ください。

    実行結果

    まずは実行結果からご覧ください。

    使用した動画

    https://github.com/intel-iot-devkit/sample-videos

    face-demographics-walking.mp4 を使いました。

    実行結果と比較するとわかりますが、無事、誰かわからないようになっていますね。

    考え方

    OpenVINOで人検出(person-detection)を行い、検出した人の位置を利用して、静止画に置き換えるという流れになります。

    参考までに、検出した人の上に静止画を載っけると、以下のような状態になります。位置をそのまま利用していることがわかりますね。

    検出したエリアをモザイク処理するという事でも良いですが、記号化することでよりプライバシーに配慮している。ということになるのでしょうか。

    使用した部品など

    ”OpenVINOを簡単に扱えるラッパー”をyas-simさんが公開されていますので、今回はそちらを利用させて頂きました。ありがとうございます!

    https://github.com/yas-sim/openvino-wrapper

    また、マスク処理について、様々なページを参考にさせて頂きました。ありがとうございます!

    全体のフォルダ構成

    intelフォルダ配下には、モデル(person-detection-retail-0013)を格納しています。

    ソース・使用画像

    さて、ようやく本題のプログラムになります。繰り返しになりますが、やっつけ的な部分があります。動作検証ということでご理解ください。

    image_compose.py

    ## fncImgCompose(front_img, back_img, size, pos)
    ##
    ## front_image ... charactor
    ## back_image  ... background
    ## size        ... size of charactor(x,y)
    ## pos         ... position of charactor(x,y)
    
    import cv2
    import numpy as np
    
    def fncMakeMask(figure):
    
        # HSV に変換する。
        hsv = cv2.cvtColor(figure, cv2.COLOR_BGR2HSV)
    
        # 2値化する。
        bin_img = cv2.inRange(hsv, (0, 10, 0), (255, 255, 255))
    
        # 輪郭抽出する。
        contours, _ = cv2.findContours(bin_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
        # 面積が最大の輪郭を取得する
        contour = max(contours, key=lambda x: cv2.contourArea(x))
    
        # マスク画像を作成する。
        mask = np.zeros_like(bin_img)
        cv2.drawContours(mask, [contour], -1, color=255, thickness=-1)
    
        return mask
    
    
    def fncImgCompose(front_img, back_img, size, pos):
        
        # front_image ... charactor
        # back_image  ... background
        # size  ... size of charactor(x,y)
        # pos   ... position of charactor(x,y)
    
        front_img = cv2.resize(front_img,size)
        mask = fncMakeMask(front_img)
    
        x, y = pos
        
        # 幅、高さは前景画像と背景画像の共通部分をとる
        w = min(front_img.shape[1], back_img.shape[1] - x)
        h = min(front_img.shape[0], back_img.shape[0] - y)
    
        # 合成する領域
        fg_roi = front_img[:h, :w]               # 前景画像のうち、合成する領域
        bg_roi = back_img[y : y + h, x : x + w]  # 背景画像のうち、合成する領域
    
        # 合成する。
        bg_roi[:] = np.where(mask[:h, :w, np.newaxis] == 0, bg_roi, fg_roi)
    
        return back_img

    person_detection_async.py

    import iewrap
    
    import time
    
    import cv2
    import numpy as np
    import image_compose as img_cmp
    
    imgBuf = {}
    
    def callback(infId, output):
        global imgBuf,im_back
    
        output = output.reshape((200,7))
        img = imgBuf.pop(infId)
        img_h, img_w, _ = img.shape
    
        im_figure = cv2.imread(r'rsc/figure_standing.jpg')
        
        for obj in output:
            imgid, clsid, confidence, x1, y1, x2, y2 = obj
            if confidence>0.5:              # Draw a bounding box and label when confidence>0.8
                x1 = int(x1 * img_w)
                y1 = int(y1 * img_h)
                x2 = int(x2 * img_w)
                y2 = int(y2 * img_h)
    
                #cv2.rectangle(im_back, (x1, y1), (x2, y2), (255,0,0), thickness=4 ) #blue
    
                im_back = img_cmp.fncImgCompose(im_figure, im_back, (x2-x1,y2-y1),(x1,y1))
    
        cv2.imshow('result',im_back)
        cv2.waitKey(1)
    
    
    def main():
        global imgBuf,im_back
    
        cap = cv2.VideoCapture(r'.\rsc\mov\face-demographics-walking.mp4')
        
        ie = iewrap.ieWrapper(r'.\intel\person-detection-retail-0013\FP16\person-detection-retail-0013.xml', 'CPU', 10)
        ie.setCallback(callback)
    
        while True:
            ret, img = cap.read()
            if ret==False:
                break
    
            img = cv2.resize(img,(1600,900))    
            im_back = cv2.imread(r'rsc/background.png')
    
            refId = ie.asyncInfer(img)     # Inference
            imgBuf[refId]=img
    
    if __name__ == '__main__':
        main()
    

    画像

    background.png
    figure_standing.jpg

    実行結果

    上記プログラムを実行すると、以下の結果が得られます。OpenVINOを使って人の位置を検出するという部分までは本当にお手軽に確認出来るので、あとは画像の料理次第ですね!ぜひお試しください。

    ご参考

    今回の環境はこちらです。渋谷の交差点のライブカメラなどではさすがに処理が増えてしまいますが、普段使いの場合は問題は無いと思います。

    • Windows 10 home (20H2)
    • Intel(R) Core(TM) i5-7260U CPU @ 2.20GHz
    • メモリ 4GB
    • OpenVINO 2021.1
    • person-detection-retail-0013\FP16\person-detection-retail-0013

    text_to_speech_demoの実行(macOS編)

    はじめに

    Open Model Zoo内のDemoに格納されている、text_to_speech_demo を使ってみましょう。

    環境

    今回はmacOSで実行してみます。(もちろん他OSでも同等です)

    MacBook Pro (13-inch, 2018, Four Thunderbolt 3 Ports)
    2.7 GHz クアッドコアIntel Core i7 メモリ16 GB
    macOS Big Sur 11.1
    Python 3.7.7
    openvino 2021.2.185

    モデルの確認

    models.lstを開いて、使用するモデルを確認します。4つのモデルが必要です。モデル未入手の場合は、モデルダウンローダーを使って入手してください。

    # This file can be used with the --list option of the model downloader.
    forward-tacotron-duration-prediction
    forward-tacotron-regression
    wavernn-rnn
    wavernn-upsampler

    ヘルプの確認

    % python3 text_to_speech_demo.py -h
    usage: text_to_speech_demo.py [-h] -m_duration MODEL_DURATION -m_forward
                                  MODEL_FORWARD -m_upsample MODEL_UPSAMPLE -m_rnn
                                  MODEL_RNN -i INPUT [-o OUT]
                                  [--upsampler_width UPSAMPLER_WIDTH] [-d DEVICE]
    
    Options:
      -h, --help            Show this help message and exit.
      -m_duration MODEL_DURATION, --model_duration MODEL_DURATION
                            Required. Path to ForwardTacotron`s duration
                            prediction part (*.xml format).
      -m_forward MODEL_FORWARD, --model_forward MODEL_FORWARD
                            Required. Path to ForwardTacotron`s mel-spectrogram
                            regression part (*.xml format).
      -m_upsample MODEL_UPSAMPLE, --model_upsample MODEL_UPSAMPLE
                            Required. Path to WaveRNN`s part for mel-spectrogram
                            upsampling by time axis (*.xml format).
      -m_rnn MODEL_RNN, --model_rnn MODEL_RNN
                            Required. Path to WaveRNN`s part for waveform
                            autoregression (*.xml format).
      -i INPUT, --input INPUT
                            Text file with text.
      -o OUT, --out OUT     Required. Path to an output .wav file
      --upsampler_width UPSAMPLER_WIDTH
                            Width for reshaping of the model_upsample. If -1 then
                            no reshape. Do not use with FP16 model.
      -d DEVICE, --device DEVICE
                            Optional. Specify the target device to infer on; CPU,
                            GPU, FPGA, HDDL, MYRIAD or HETERO is acceptable. The
                            sample will look for a suitable plugin for device
                            specified. Default value is CPU
    

    実行してみます

    テキストファイルを読み込ませると、movで出力されます。まずはVincent van Gogh (ゴッホ)さんの名言を喋らせてみましょう。

    Your life would be very empty if you had nothing to regret.
    % python3 text_to_speech_demo.py -m_duration ./models/forward-tacotron-duration-prediction/FP16/forward-tacotron-duration-prediction.xml -m_forward ./models/forward-tacotron-regression/FP16/forward-tacotron-regression.xml -m_upsample ./models/wavernn-upsampler/FP16/wavernn-upsampler.xml -m_rnn ./models/wavernn-rnn/FP16/wavernn-rnn.xml -i test.txt -o test.wav

    OK。喋りました。次は複数行の例として、Steve Jobsさんの名言を喋らせてみましょう。パラメータ等は同じなので省略します。

    Your time is limited, so don't waste it living someone else's life. Don't be trapped by dogma — which is living with the results of other people's thinking. Don't let the noise of others' opinions drown out your own inner voice. And most important, have the courage to follow your heart and intuition. They somehow already know what you truly want to become. Everything else is secondary.

    スムーズに喋ってますね。