ビデオ会議でのwebカメラのオン・オフユースケース(姿勢推定編)

OpenVINOを実際に使用したユースケースを想定し、プログラムを作成しているシリーズ。

前回は顔認識を使用して、自分以外の顔が写り込む、または、退席した時(誰も居なくなった)場合に、ビデオ会議のカメラをオフにするという内容でした。今回も引き続きビデオ会議を取り上げてみます。

きっかけ・ゴール

テレビ会議が一気に普及し、自宅仕事が増えてる状況ですね。暑くなってきましたし、上だけフォーマルな人も増えているのは分かります。自分も今は短パンです。YouTubeで「Luke Ming Flanagan underwear speech」とか「Reporter Caught With No Pants Live on Air」とかで検索すると、ウッカリさんが面白ニュースとしていじられていますね。気持ちは分かりますよ。暑いですもん。

このようなウッカリさんの事故を防ぐためには、「ビデオ会議にはちゃんとした格好で出ましょう」みたいなルールを作るのも良いかもしれませんが、それではつまらないルールが増えていくばかり。失敗学でも言われているように個人に依存せず、システム的に防止する事が必要だなあ。と思っていたら、作っている方がいらっしゃいました。

https://www.hackster.io/nickbild/safe-meeting-b66324

記事を読んでいると、「Safe Meeting prevents embarrassing and unprofessional situations by stopping your video stream if certain attire that’s inappropriate for business is detected.」だそうです。”ビジネスに相応しくない”というところが気になりますね。いろんなパンツとかどうやって検出しているんでしょう。謎です。セクスウィなパンツや、逆に派手なスーツやドレスもちゃんと判定してくれるのでしょうか。

という訳で、今回のユースケースではもっと単純化して「姿勢推定で腰より下が映ったら、ビデオ会議側のカメラをオフにする」というゴールにしたいと思います。

環境について

本ユースケースの実行環境はWindows10(以降、Win10)です。
  • Windows 10
  • Logicool c270 x 2台
  • ELECOM U3H-A408SBK
  • Jitsiはクラウドサービスを利用(https://meet.jit.si)
  • モデル:human-pose-estimation-001
  • 言語 :c++, powershell, bat
  • webカメラは2台使います。1台はビデオ会議用、1台は顔認識用です。今回はc270を使いました。webカメラも価格が高騰しているようですね。Win10で使えればお手元のカメラで問題無いと思います。

    Webカメラ2台、キーボード、マウスをWin10に挿すと、ハードにもよりますが、バスパワーが不足する状況になるかもしれません。そこで、セルフパワーのUSBハブの出番です。未だお持ちでない方はぜひ購入ください。USB3.0対応の方が良いですね。(Amazonの手先ではありません)

    今回利用したビデオ会議システムはオープンソースのjitsi(https://meet.jit.si)です。jitsiはもっと普及しても良いと思うOSSです。なお、理論上は他のビデオ会議でも本記事は使用可能です。

    姿勢推定について

    姿勢推定はOpenVINOに含まれている、human_pose_estimation_demo(c++)を流用しました。モデルはhuman-pose-estimation-001となります。まず、OpenVINOのドキュメントを確認しました。

    https://docs.openvinotoolkit.org/latest/_models_intel_human_pose_estimation_0001_description_human_pose_estimation_0001.html

    This is a multi-person 2D pose estimation network (based on the OpenPose approach) with tuned MobileNet v1 as a feature extractor. For every person in an image, the network detects a human pose: a body skeleton consisting of keypoints and connections between them. The pose may contain up to 18 keypoints: ears, eyes, nose, neck, shoulders, elbows, wrists, hips, knees, and ankles.

    とあります。キーポイントとして18箇所を判定するんですね。腰は何番だろうと思ったら、8番と11番でした。つまり、姿勢推定の結果、8番と11番に値が存在すると、腰が写っちゃっているという事になりますね。

    WebカメラのOnOffについて

    上記のとおり、姿勢推定の結果、腰が写った場合(8番と11番に値がある)にWebカメラをオフにすると良さそうだ。という事が分かりました。

    ”カメラをオフ”を手動で行う方法は、[コンピュータの管理]-[デバイスマネージャー]-[イメージングデバイス]から対象のカメラを右クリックして「デバイスを無効にする」という手順になります。これをDevConかPowerShellのどちらかで行います。

    DevCon

    https://docs.microsoft.com/ja-jp/windows-hardware/drivers/devtest/devcon-exampleshttps://docs.microsoft.com/ja-jp/windows-hardware/drivers/devtest/devcon-examples?fbclid=IwAR3tbimojRY0lercRto08y6QfQPQLMKoPAc52Y2tua1w3KA4TsVj8aJYWxo#ddk_example_30_disable_devices_by_an_id_pattern_tools

    PowerShell

    https://docs.microsoft.com/en-us/powershell/module/pnpdevice/enable-pnpdevice?view=win10-ps

    ここで注意なのは、どちらも管理者権限で実行する必要があるという事です。管理者権限で呼び出す方法は以下のページが参考になりそうですが、ここでは面倒だったので時間優先でUACを無効にしてダイアログが出るのを回避しました。正式に物を作る際は綺麗なお作法でお願いします。

    https://qiita.com/zetamatta/items/d41552c383605b24a8c2

    実行のようす

    最後に

    前回はRasPi4/Python/顔認証で、今回はWin10/C++/姿勢推定で、ビデオ会議のカメラの制御を実装しました。実現したい事やエンジニアが使える言語に応じて、モデルや言語を変えて貰えば良いと思います。OpenVINOでいろいろ挑戦してみてください。

    ビデオ会議でのwebカメラのオン・オフユースケース(顔認識編)

    OpenVINOを実際に使用したユースケースを想定し、プログラムを作成しているシリーズ。今回はビデオ会議を取り上げてみます。

    みなさんご存知の通り、新型コロナの影響でビデオ会議の導入・利用が一気に進みました。また、ビジネス利用だけで無く、”宅飲み”など、普段使いのツールとして利用されている方も多いと思います。

    ビデオ会議あるあるとして、家族が写り込んだり、離席した場合に部屋を映したく無いという状況があると思います。みなさんどうされていますか?この解決手段を考えてみます。まずはYouTubeの動画をご覧ください。

    環境について

    本ユースケースの実行環境はRaspberryPi 4(以降、RasPi)です。
  • RaspberryPi 4
  • intel Neural Compute Stick 2
  • Logicool c270 x 2台
  • ELECOM U3H-A408SBK
  • Jitsi(on ubuntu 18.04)
  • モデル:face-detection-retail-0004
  • 言語 :python
  • 宝島社 もっとひょっこりはんをさがせ!
  • RasPiは安くて便利な環境です。私が講師を担当していた小学5、6年生対象のプログラミング・ロボット講座でもRasPiを配布し、みんな楽しく使っていました。(小学生がLinux使う世の中なんて、いい意味で想定外ですよ)

    RasPi4、USBハブ、intel Neural Compute Stick2

    webカメラは2台使います。1台はビデオ会議用、1台は顔認識用です。今回はc270を使いました。webカメラも価格が高騰しているようですね。RasPiで使えればお手元のカメラで問題無いと思います。

    RasPiでOpenVINOを使うには、Intel Neural Compute Stick 2(以降、NCS2) が必須です。Amazonで1万円程度で購入出来ますので、未だお持ちでない方はぜひ購入ください。

    Webカメラ2台とNCS2、キーボード、マウスをRasPiに挿すと、バスパワーが不足するという状況になります。ssh,VNCで接続してもキーボード・マウスだけが回避出来るので心もと無いです。そこで、セルフパワーのUSBハブの出番です。未だお持ちでない方はぜひ購入ください。USB3.0対応の方が良いですね。(Amazonの手先ではありません)

    今回利用したビデオ会議システムはオープンソースのjitsi(https://jitsi.org)です。ubutu server 18.04 上に構築済のローカルjitsiを利用しました。jitsiはもっと普及しても良いと思うOSSです。なお、理論上は他のビデオ会議でも本記事は使用可能です。

    RasPiのモデル利用について

    実際の顔認識用のデモアプリは流用するとして、ここでは実行時に注意する点についてご案内します。以下のようにモデル利用時にエラーが出る場合、まずはモデルを疑ってください。忘れていると1日くらい損します。

    [ INFO ] 2020-06-05 11:14:48,240 Loading models [ INFO ] 2020-06-05 11:14:48,241 Loading the model from '/home/pi/openvino/models/face-detection-retail-0004/FP16/face-detection-retail-0004.xml' face_recognition_demo.py:177: DeprecationWarning: Reading network using constructor is deprecated. Please, use IECore.read_network() method instead model = IENetwork(model_description_path, model_weights_path) Traceback (most recent call last): File "face_recognition_demo.py", line 446, in main() File "face_recognition_demo.py", line 441, in main visualizer = Visualizer(args) File "face_recognition_demo.py", line 240, in __init__ self.frame_processor = FrameProcessor(args) File "face_recognition_demo.py", line 131, in __init__ face_detector_net = self.load_model(args.m_fd) File "face_recognition_demo.py", line 177, in load_model model = IENetwork(model_description_path, model_weights_path) File "ie_api.pyx", line 1099, in openvino.inference_engine.ie_api.IENetwork.__cinit__ RuntimeError: fc7_mbox_priorbox/naked_not_unsqueezed has zero dimension that is not allowable

    このようなエラーが出る場合は、2019R3のモデルをダウンロードして使ってみてください。(他のエラーパターンもあるので基本的には2019R3で良いかもしれません) https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/

    なお、本ユースケースでは、face-detection-retail-0004を利用しました。

    WebカメラのOnOffについて

    基本的に、顔認識用カメラ側でnot(自分の顔認識がされた)場合に、web会議側のカメラをオフにする動作となります。以下のページが参考になりました。ありがとうございます。

    https://www.raspberrypi.org/forums/viewtopic.php?t=242059

    https://artfinex.co.jp/wp/wp-content/uploads/2019/03/afx_RaspberryPiRaspbianUSB_Reset_UHF.pdf

    最後に

    ビデオ会議ではいろんな事故がありますが、割と下半身をぽんぽんすーにしている人も多いのがびっくりです。今後は、下半身を検出してカメラをオフにする仕組みを作りたいと思います。

    高負荷環境でのベンチマーク

    一般的にOpenVINOやその他のAI toolkitを一般用途で使用する場合は、24時間365日運用が前提だと思います
    また、処理は常に高負荷がかかった状態だと思います
    このような状況を想像して、CPU,GPU,NCS2を使用した場合の変化を実験してみました

    実験環境を用意します
    今回はOpenVINOが走るマシンと3つのSSHを接続し、1つ目はOpenVINOのベンチマークソフト、2つ目はCPUのクロック確認、3つ目はCPU負荷用のベンチマークソフト実行を行いました
    ウィンドウは下記のようになります

    まずは何も負荷をかけずに、CPU,GPU,NCS2(MYRIAD)を指定したベンチマークを実行します
    実行時のオプションは下記の通り

    inference_engine_cpp_samples_build/intel64/Release/benchmark_app -i test_images -m ~/openvino_models/intel/vehicle-detection-adas-0002/FP16/vehicle-detection-adas-0002.xml
    (test_imagesにはcar.pngのみを入れています)

    このコマンドにそれぞれ-d CPU, -d GPU, -d MYRIADを指定して、ベンチマークを取得します

    今回のHW環境ですが、
    CPUスペックは、Intel(R) Atom(TM) Processor E3950 @ 1.60GHz
    OSはubuntu18.04を使用し、Xwindowなどの画面出力は行っていません

    負荷なし、CPUでの実行(11.02FPS)
    負荷なし、GPUでの実行(36.57FPS)
    負荷なし、NCS2での実行(25.01FPS)
    高負荷時、CPUでの実行(5.45FPS)
    高負荷時、GPUでの実行(31.10FPS)
    高負荷時、NCS2での実行(25.16FPS)

    下記は無負荷、高負荷時のFPSを表にしたものです

    無負荷高負荷増減率
    CPU11.02FPS5.45FPS49%
    GPU36.57FPS31.10FPS85%
    NCS225.01FPS25.16FPS101%

    CPUに負荷がかかっている場合は、半分以下のFPSとなります
    アプリケーションのプライオリティにも関係しますが、高負荷時に推論を実行する場合はこのような問題が発生します
    一方、GPUでの実行は85%となっています。これはキャッシュへのアクセスなどがCPU内で行われていますので、このような減少率になっていると思いますが、細かな点は別の機会に書くことにします
    最後に、NCS2(MYRIAD)での実行は、増減がありませんでした
    NCS2の場合は、外部HWに処理を流しますので、使用メモリが少ない場合は有利に働く可能性が大きいです

    組み込み機器にOpenVINOなどを組みこむ場合は、CPUの負荷の見積もりなどを考え、うまくGPU,NCS2に処理を流してあげることにより、低価格でシステムが実現できるのではないでしょうか

    工場ラインの文字読み取りユースケース

    ここでは、OpenVINOを実際に使用したユースケースを想定し、プログラムを作成してみます

    工場内のラインでよくあるケースは商品に貼られたり、印刷されるシールの日付や文字の読み取りです
    単純な文字認識だと、OpenVINOに含まれるText Detection C++ Demoによって文字認識が行えます
    そのため同じ場所に印字されるものであれば文字読み取りの位置決めなどは必要なくなるのですが、円形の商品(缶のようなもの)であれば、日付データの角度を意識しないといけません
    これらを想定してユースケースを考えます

    上記が日付データのサンプルとします
    左右についている黒丸、白丸は角度補正用のアライメントマークとなります
    プログラムの流れとしては、それぞれのアライメントマークを入力画像から探し、2点間の角度を求め、入力画像の角度補正を行います
    ではまずアライメントマークを入力画像から探す方法を考えましょう

    アライメントマークの検出

    日付データの印刷が比較的自由な場合は、日付の両端にアライメントマークが付けられることがあります
    これは角度補正が必要になる対象物(ワークと言う)がある場合、角度に関わらないマークを印刷しておくことによって、そのマークを画像上で検出し、画像を角度補正します

    今回の場合は、白丸、黒丸の二つをアライメントマークとして使用し、これらを検出することにより角度を検出します

    アライメントマークの検出には

    アライメントマークの検出には、正規化相関(パターンマッチング)と言う比較的オーソドックスな画像処理を使います
    正規化相関は高速で同じサイズ・角度の対象物を画像上から検出することが得意なアルゴリズムです
    この正規化相関はOpenVINOにも含まれるOpenCVにAPIがあるのでそれを使用します

    BlackMark
    WhiteMark
    //アライメントマークの読み込み
    white_img = imread("/home/upsquared/WhiteMark.png", cv::IMREAD_COLOR);
    //アライメントマークの色変換
    cv::cvtColor( white_img, white_img, cv::COLOR_BGR2GRAY );
    
    //アライメントマークの読み込み
    black_img = imread("/home/upsquared/BlackMark.png", cv::IMREAD_COLOR);
    //アライメントマークの色変換
    cv::cvtColor( black_img, black_img, cv::COLOR_BGR2GRAY ); 
    
    //入力画像の色変換
    cv::cvtColor( image, image, cv::COLOR_BGR2GRAY );
    
    //テンプレートマッチング
    cv::matchTemplate(image, white_img, matching_res, CV_TM_CCOEFF_NORMED);
    cv::minMaxLoc( matching_res, NULL, &maxVal, NULL, &white_max_pt);
    
    //テンプレートマッチング
    cv::matchTemplate(image, black_img, matching_res, CV_TM_CCOEFF_NORMED);
    cv::minMaxLoc( matching_res, NULL, &maxVal, NULL, &black_max_pt); 

    上記のプログラムがアライメントマークを検出する部分となります
    アライメントマークが検出されれば角度補正となります

    角度補正

    アライメントマークが検出された後は、二点間の角度を使用して、画像を変換します

    二点から角度を計算するには

    atan2(y2-y1,x2-x1)*180/M_PI, 1.0); 

    を計算すれば回転角が計算できます

    この回転角から画像を補正するためにはOpenCVのアフィン変換ライブラリを使用します

    cv::Mat mat = cv::getRotationMatrix2D(ctr, atan2(y2-y1,x2-x1)*180/M_PI, 1.0);
    cv::warpAffine(image, temp_image, mat, image.size(), CV_INTER_LINEAR, cv::BORDER_TRANSPARENT); 

    回転角の計算と補正を行っているのが上記のプログラムとなります

    対象画像を切り出す

    対象物の位置、角度を検出し、画像の補正ができれば、次は対象となる画像を切り出します
    この作業は対象画像を小さくし、高速化のために必要です

    cv::getRectSubPix(temp_image, cv::Size(300, 100), ctr, output_image);
    cv::cvtColor( output_image, output_image, cv::COLOR_GRAY2BGR );

    現状、画像サイズは300x100pxとしてありますが、これは対象画像登録時に設定しても良いですし、アライメントマークの距離から自動的に抜き出しても構いません

    cv::getRectSubPix関数内の引数はそれぞれ画像ファイル、サイズ、中心位置、出力画像となります
    中心位置はcv::Point2dで指定しています

    OpenVINOに含まれるtext detection demoはRGB画像で無いと処理できないため、cv::cvtColorで色変換を行っています

    Text detection C++ demoとつなぐ

    ここまできたらText detection C++ demoの画像ファイル入力部分を探して、つなぎ合わせるとリアルタイムの文字認識ソフトが出来ます

    上記の動画は実際に日付データを回転させて文字認識を行っています

    続く…