oF_ofxARKitでPeopleOcclusion

openFrameworksでPeopleOcclusionを実装する際の手順を記載します。

こちらにソースコードおいてます。以下はその解説などになります。
https://github.com/shiyuugohirao/oF_PeopleOcclusion_example

はじめに

PeopleOcclusionというのはAppleが開発したARKitに備わっている機能です。
2次元の画像から人と認識される部分を取得できます。

ちゃんと着手するまで勘違いしていましたが、
PeopleOcclusionはあくまで2次元の処理であり、深度を取得したり推定したりする機能ではありません。

逆に言えば人間部分の推定に深度情報を必要としないので、
ディスプレイ・モニタに写った人や平面ポスターに印刷された人なんかでも認識は可能です。
(実際の人間に比べると精度は劣るような印象ですが。)

ちなみにPeopleOcclusionと呼んだり、PersonSegmentationと呼んだり、ほぼ同義のワードが飛び交うようです。

またちなみに、Unityでは、Unityが公式で開発しているらしいARFoundationというARKitをまとめたSDK(?)があって、そこから比較的容易に取得できます。
以前、北千住デザインさんのQiitaの記事を参考にしたら、いとも簡単に動かせたので驚きでした。

で、Unityでは調べりゃたくさん記事が出てくるのですが、openFrameworksではたぶんほぼ参考文献がありませんでした。
ZachLibermanさんのInstagramなどでは、ちらほらPeopleOcclusionらしき作例がアップされていたので、あきらめずに試行錯誤できました。

環境

手順

まずは、ofxARKitのサンプルを動かしてみます。
他のアドオンと違いちょいと設定が必要なので、ofxARKitを触ったことない方は、慣れるためにも、適当なサンプルをいくつか実機で実行してみることをおすすめします。
(たとえばexample-basicとかexample-face-trackingとか)

ProjectGeneratorを使ってプロジェクトファイルを作る際には、2bbbさんの記事もとても参考になります。

ofxARKitを使う際の設定項目は大きく4つ。

  • Targetの設定 ()
  • Signing&Capabilitiesの設定
  • ofxiOS-Info.plist でカメラ許可の設定
  • Shaders.metal の設定

以下その詳細な手順

  1. ProjectGenerator > import で適当なサンプルフォルダを選択し、 Updateでプロジェクトファイル(.xcodeproj)を生成します。

  2. 生成したxcodeprojを開きます。

  3. 左のProjectNavigatorからプロジェクト名を選択して、[General]タブからDeploymentInfo > TargetをiOS13以上にします。
    ※PeopleOcclusionなどiOS13以上でないと使えない機能を使う場合、Targetの設定もiOS13以上を設定しておかないとたしか警告が出てうぜえです。


  4. 続いて[Signing&Capabilities]タブでAppleDevelopperLicenseの設定を行います。
    ※ここについての詳細はいろいろとややこしいので、別の記事を参考にしてください。

  5. ProjectNavigatorから ofxiOS-Info.plistを開き、右クリック>AddRow>Privacy - Camera Usage Description を追加します。
    ※Valueをサボって空欄にしているとアプリ起動時にコンソールに以下のようなエラーが出てました。

    [access] This app has crashed because it attempted to access privacy-sensitive data without a usage description.  The app's Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.
    




  6. ProjectNavigatorから addons > ofxARKit > src > lib > Shaders.metal を開き、右側Inspectorsから Typeを MetalShaderSource、TargetMembershipにチェックを入れます。




その他注意点として、ProjectGeneratorで新規プロジェクトを作ったら、以下フォルダのsrcファイルも必要になります。

  • delegates
    • MyAppDelegate.h
    • MyAppDelegate.mm
  • viewcontrollers
    • MyAppViewController.h
    • MyAppViewController.mm
    • OFAppViewController.h
    • OFAppViewController.mm

基本はexampleのsrcフォルダにある各フォルダをコピペでいいと思います。僕は特に弄ったことはなかったと思います。

上記の手順を踏めば、実機でサンプルは問題なく動くはずです。
ビルド成功しても、起動直後に落ちる場合は、カメラの設定など怪しいです。
コンソールのエラーを見ると割とちゃんとエラー内容が書いてあるので、参考にしてみてください。

上記手順はProjectGeneratorでプロジェクトをUpdateするたびに必要になります。
なんてこともofxARKitのREADMEに書いてありました。丁寧だぜ。

PeopleOcclusionの実装

本題です。

要点は、

  • ARKitからSegmentationBufferを取得する。
  • 取得したSegmentationBufferを頑張って使いやす型に変換する。
    →今回はcv::Matに変換する方法を見つけたのでcv::Matを採用しました。

ARKitでは人物か否かをSegmentBufferというバッファに格納するようです。
ここまでできれば、openFrameworksで如何様に処理が可能です。

注意点として、取得できるSegmentationBufferは 256x192pxしかありません。
iPhoneXSの場合、取得したカメラ画像の解像度は 1125x2436pxなので、SegmentationBufferをマスクとしてカメラ画像を切り取るには調整が必要です。
cv::Matでは座標の向きも普段と異なったり。。

また、SegmentationBufferをスケールだけ合わせてマスクとして利用すると、もとが低解像度のためエッジがかくかくしてしまいます。
このためof_PeopleOcclusion_exampleではブラーをかけてエッジをなめらかにしてみたり、
ofxCv::ContourFinderで輪郭(Blob)を取得してみたり、工夫が必要になります。

ARKitからSegmentationBufferを取得する

oF_PeopleOcclusion_example をもとに説明していきます。

サンプルアプリの動作を説明をしておくと、

  • 取得したカメラ画像の描画
  • SegmentationBufferをもとに取得した輪郭線の描画
  • SegmentationBufferをもとに取得したステンシルバッファ(白黒マスク画像)の描画
  • ステンシルバッファでマスクしたカメラ画像(セグメンテーションされた画像)の描画

の4つをそれぞれ、画面左上、右上、左下、右下のタップでオンオフ切り替えるものです。



sessionの開始

ARKitを利用するためexample-basicなどと同様、まずofAppのコンストラクタでARKitのセッションを開始します。

このsession開始時に合わせて、どんなsessionを開始するのかを記述したconfigurationを設定します。
※これはexample-face-trackingのサンプルを参考にしました。

ofApp :: ofApp (ARSession * session){
    ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfiguration new];
    auto mode = ARFrameSemanticPersonSegmentationWithDepth;
    bool b = [ARWorldTrackingConfiguration supportsFrameSemantics:mode];
    if(b) configuration.frameSemantics = mode;
    else ofLogWarning()<<"Not support for "<<mode;
    [session runWithConfiguration:configuration];
    this->session = session;
}

ARWorldTrackingConfigurationの他にもARBodyTrackingConfigurationなど面白そうな設定もあるのですが、
今回のPeopleOcclusionについては、ARWorldTrackingConfigurationなど一部のタイプでしか利用できなかったはず(Apple公式リファレンスにそんな記述があったようななかったような)

用意したconfigurationに対してframeSemanticsというものを追加で設定してやります。
これもPeopleOcclusionをする際は、ARFrameSemanticPersonSegmentationARFrameSemanticPersonSegmentationWithDepthなどを指定する必要があります。(Apple公式リファレンス)

以上で、ofApp起動後にセッションが開始され、setup()のなかから、このセッションを引数としてprocessorを生成します。

    processor = ARProcessor::create(session);
    processor->setup();

で、このprocessorをupdate()することで情報を更新し、sessionから様々な情報を取得することができるようになります。

cvtSegmentationToPix()

update()から呼んでいるもので、ここで、要点となるsegmentationBufferの取得と変換を行っています。

auto buf = session.currentFrame.segmentationBuffer;

ここがポイントです。
ちなみにサンプルでは推論型を使っていますが、CVPixelBufferRefとなります。(公式リファレンス)

さらにちなみにここでsegmentationBufferではなく、estimatedDepthDataを取得すればおそらく2次元画像からデプス推定したバッファを取得できるはず、、!

取得した CVPixelBufferRef をcv::Matに変換します。
参考 : https://stackoverflow.com/questions/19358686/how-do-i-convert-from-a-cvpixelbufferref-to-an-opencv-cvmat/43465531

cv::Mat ofApp::getMatFromImageBuffer(CVImageBufferRef buffer) {
    cv::Mat mat ;
    CVPixelBufferLockBaseAddress(buffer, 0);
    void *address = CVPixelBufferGetBaseAddress(buffer);
    int width = (int) CVPixelBufferGetWidth(buffer);
    int height = (int) CVPixelBufferGetHeight(buffer);
    mat = cv::Mat(height, width, CV_8UC4, address, 0);
    //ofxCv::convertColor(mat, mat, CV_BGRA2BGR);
    //cv::cvtColor(mat, mat, CV_BGRA2RGBA);
    CVPixelBufferUnlockBaseAddress(buffer, 0);
    return mat;
}

ここまでで、openFrameworksでPeopleOcclusion(SegmentationBuffer)を取得することができました。

ここから先は、取得したデータをどう処理するかという話になります。
cv::Matの描画やマスクなどの処理については後日また改めて、書きたいと思います。

study:

openCV3/4のメモ

openCV3/4のメモ

要約

openCv4をopenframeworksで使うまでの手順。
プロジェクトの生成については、ほかサイトで見なかった簡単な方法をメモ。
めちゃ雑記です。

概要

oFでopenCV3とか4とか使ってみます。
この記事この記事にそって進めてみる。
opencv4でないといけないことは特にないです。ただただBackgroundSubtractorを試してみたかった。
後日また雑な記事かきます。テストの動画だけ貼っときます。なにかのための証拠。

環境とりあえずMac

openCVのinstall

まずはopenCV3 or 4のインストール。
※ 基本最新で上書きされるっぽい。3,4を共存させる方法もあるらしいが、自分は openCv4.1.0でこれといって不具合はないので、opencv4のみになっています。

brew tap homebrew/scienceは使えなくなったらしい。参考
そのため brew tap brewsci/science こちらのコマンドで環境アップデート。

  • opencv3の場合
    brew install openCV3で入れる。
  • opencv4の場合
    opencv4についてはこちらが詳しい。
    brew upgrade opencv でopenCV4(最新版 ex: 4.1.0)を入れる。
途中xcodeのコマンドラインをインストールしてね的なエラーが出たので、xcode-select --installをして、再度upgradeかけると、エラーなく無事完了した。  
過去に入れた気がするのにと思っていたけど、どうもOSをアップグレードすると再度入れる必要があるらしい。  

普通にすすめると、たいていは/usr/local/Cellar/opencv/が更新されるはず。

Xcodeで新規プロジェクト作成

色んなサイトでは以下の方法があげられていたが、パス間違える可能性があったり、記入が面倒だったりなので、個人的にはおすすめじゃない。

紹介されていたプロジェクト生成方法

open
  1. Project.xcconfigでOPENCV_PATHを設定 パスは適宜変えてください。
//OpenCV3
OPENCV_PATH = /usr/local/Cellar/opencv/3.4.1_2
//OpenCV4
OPENCV_PATH = /usr/local/Cellar/opencv/4.1.0_2  
  1. BuildSettingsのHeader Search PathsにOpenCVのインクルードパスを追加
    $(OPENCV_PATH)/include/opencv4
  2. Build SettingsのOther Linker Flagsに必要なdlybを追加
    ここが面倒、、

openCV4をインストールすると、libフォルダにdylib以外に.aファイルもありました。
これらおそらく中身は同じですが、動的ライブラリか、静的ライブラリかの違いがあります。  
こちらでは動的のほうがファイルサイズ小さく、使用メモリも少なくできるっぽい。
dylibを追加するのが面倒な場合は、
.aファイルをGeneralのLinked Frameworks and Librariesにドラッグドロップしても起動可能です。

(たぶんProject.xcconfigのOTHER_LDFLAGSこのあたりの設定でどうにかなるのだけど、、)

#include <opencv2/core.hpp>ここでリンク貼れてないよってエラー出たけど、単純にheader search pathに$(OPENCV_PATH)/includeを入れてないのが原因でした。

おすすめの生成方法

ProjectGeneratorでプロジェクトを作り、

  1. プロジェクトのSearchPaths > HeaderSearchPathsに/usr/local/Cellar/opencv/4.1.0_2/include/opencv4 を追加。(パスは適宜変更してください。)
  2. /usr/local/Cellar/opencv/4.1.0_2/libから必要なdylibを General>LinkedFrameworks and Libraries にドラッグドロップで追加

どのヘッダ呼び出すときにどのlibが必要になるのか、どこを見ればいいんだろう。。。今の所勘で追加しています。。。
このやり方が簡単安定な気がする。Debug/Releaseで変更の必要ない?
紹介されていたプロジェクト生成方法だと必要かもだけど。


画像は適当に追加したのでごちゃっとしています。どうやら.aの静的ライブラリよりは、.dylibなど動的ライブラリのほうが実行ファイルが軽く、メモリの消費を抑えられるとかどうとか。。。

ofxCvとの連携と利用

oFでopenCVを扱う際に、関数群を使いやすくまとめてくれているofxCvを使うとめっちゃ便利。

ProjectGeneratorでofxCvのみ追加してプロジェクト生成。
あとは、上の1.2.を同様に。
なんかもしかしたら、もうちょうっと設定必要だったかも。わすれてもうた。


おまけめも

ofxOpenCvDnnSegmentation など

やはりどこにでも先人がいるもので、馬場先生のofxOpenCvDnnSegmentationがあった。openCVのdnnライブラリをいろいろまとめてらっしゃる。

配布されていたopencv2.aでうまくいかなかったので、自分でメイクしてみる。参考

が、原因はどうもそこではなかった。ので、makeの手順は隠す。

makeの手順
  1. python build_framework.py osxを実行するが、python3ではうまくいかないみたい。
    自分の場合は python2 build_framework.py osc とするとうまくいった。
    python -Vでバージョンを確認したり、which python, which python2でpythonの2.7以上が使われているか確認するとよさそう。
    参考1 参考2

エラー(returned non-zero exit status 65)について
** BUILD FAILED **

The following build commands failed:
    CompileC /Users/hiraoshugo/openCV/opencv-4.1.0/platforms/osx/osx/build/build-x86_64-macosx/modules/world/OpenCV.build/Release/opencv_world.build/Objects-normal/x86_64/opencl_kernels_video.o /Users/hiraoshugo/openCV/opencv-4.1.0/platforms/osx/osx/build/build-x86_64-macosx/modules/world/opencl_kernels_video.cpp normal x86_64 c++ com.apple.compilers.llvm.clang.1_0.compiler
(1 failure)
============================================================
ERROR: Command '['xcodebuild', 'MACOSX_DEPLOYMENT_TARGET=10.12', 'ARCHS=x86_64', '-sdk', 'macosx', '-configuration', 'Release', '-parallelizeTargets', '-jobs', '4', '-target', 'ALL_BUILD', 'build']' returned non-zero exit status 65

こんなエラーでた。どうやらcmakeのバージョン(3.10.2)がダメらしい。参考
てわけで、cmakeのupgrade

cmake --version
// cmake version 3.10.2
brew upgrade cmake
// .....
cmake --version
// cmake version 3.15.2
python2 build_framework.py osx
// .....

  1. python build_framework.py –contrib <opencv_contribへのパス> osx

そんなこんな。。

結論、こちらのように#include "opencv2/imgproc/imgproc_c.h"をofxCvのWrappers.hに追加した。

modelデータは以下から直接落とした。
http://dl.caffe.berkeleyvision.org/fcn8s-heavy-pascal.caffemodel


最近いろんな出会いがあって楽しい。特に音楽やってる人とよく出会う。
春よりも春らしい。

明日は学生CGコンテスト25周年のパーティーにいってきます。
夏がもうすぐ終わるからね。季節の変わり目。春の訪れ。
秋はいずこへ。

openframeworksでカメラが使えなくなった

openframeworksでカメラが使えなくなった。
ofAVFoundationGrabber.mmの
[self.captureSession addInput:captureInput];
でエラーが出る。
QuickTimeなどではちゃんとカメラが動作するので、oFかXcodeの設定かなと踏んでいた。

open

結論としては、Macのシステム環境設定でセキュリティとプライバシーのカメラの設定で、oFのアプリのチェックが外れていた。
何がきっかけで外れたのか、何を思ったか昔の私がチェック外したのか。。

エラー内容は以下みたいな。

An uncaught exception was raised
~~
Terminating app due to uncaught exception &#039;NSInvalidArgumentException&#039;
~~
libc++abi.dylib: terminating with uncaught exception of type NSException

ちょっと話は違うけど、以下を読んで、ふとプライバシーの設定のことを思い出した。
https://github.com/openframeworks/openFrameworks/issues/6193

コンソールのエラーログにもセキュリティ的な話がなく、
再起動しても、新しくoFの環境作ってVidoGrabberExampleをビルドしても、同様のエラーが出ていたので、悩みました。
気づいてみれば簡単なことなのに、、残念な経験は案外忘れているんですね。


iOSアプリの設定で変数など管理

iOSアプリを作ったときに、
アプリを入れたあとで、コンテンツの中身を書き換えたい場合。

たとえば、
OSCを使うためIPアドレスをアプリに設定したい。
アプリの向きを変えたい。
デバッグモードのトグルで切り替えたい。
などなど。

上みたいな設定ができると、作ったアプリにちょっと愛着わいてモチベ上がる。

サイネージのお仕事でiPadなどの端末からコンテンツを操作するということが
最近ふえたので、そのときにしておくと親切なTipsです。

openFrameworksでiOSを開発する際にはofxSettingsが便利でした。
https://github.com/prossel/ofxSettings

 


詳細な設定は文末の参考リンクにまるなげ。

設定の大体の流れは、
1. srcなど右クリックでSettings.bundleファイルを追加する。
2. Root.plistに表示したい項目を追加。
3. Keyの値を利用して、端末の設定画面で入力した値をアプリ起動時などに変数へ格納する。(ofxSettingsではSettings::get~()で取得)
4. 取得はせず設定画面に表示したいだけの場合はKeyの値を利用してSettings::set~()で。
5. ビルド時の情報を表示させたい場合は、BuildPhases

 

APP_VERSION=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" $PRODUCT_SETTINGS_PATH)
/usr/libexec/PlistBuddy -c "Set :PreferenceSpecifiers:9:DefaultValue ${APP_VERSION}" "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Settings.bundle/Root.plist"

date=$(date "+ @ %Y.%m.%d %H:%M")
BUILD_NUMBER=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" $PRODUCT_SETTINGS_PATH)$date
/usr/libexec/PlistBuddy -c "Set :PreferenceSpecifiers:10:DefaultValue ${BUILD_NUMBER}" "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Settings.bundle/Root.plist"

RunScriptで上のような記述をします。
1行目:APP_VERSIONという変数にxcodeで指定しているアプリのバージョンを代入
2行目:plistのitem9DefaultValueをAPP_VERSIONに書き換え
みたいな感じでしょうか。
何項目め、みたいな指定しかできないのかな。ちょっと調べてみたけどなさそう?

xcodeからAddRowとかして追加するとなんか表示変になっていたりすることがあるので、plistファイルを他のエディタで開いてxmlとして直接編集した方が無難かも。
xcodeで編集できる方がitemのナンバーとかわかりやすいけど。

'date=$(date "+ @ %Y.%m.%d %H:%M")' などを追加して
ビルド時の日時なども記載しておくとデバッグなどでは便利かも
http://goozenlab.com/blog/2015/02/06/versionning/


参考
https://dev.classmethod.jp/smartphone/iphone/settings-bundle-acknowledgements/
https://qiita.com/akatsuki174/items/392cb3be619fabfa4608

 

IPアドレスを取得する_oF_osx(C++)

openFrameworksなどでアプリを動かしているPCのIPアドレスを取得したい。

Mac OSXの話。
参考(というかほぼまるまる):
http://www.geekpage.jp/programming/linux-network/get-ipaddr.php

oFなどでofMain.hをincludeしていれば
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
のインクルードでOK

ネットに繋がっていない場合は
255.127.0.0
とか返ってきた。(要検証)

ネットに繋がっていない状態でも何かしらそれっぽいIPアドレスが返ってきたので、
[*] check good IP のところで、最後の値を見て、感でぽい処理を追加しただけ。

OSCを使うとき、IPアドレスで確認して接続+立ち上げするようにすれば、
とっても親切で徳が高い。

ちなみにiOSでも上のコードで取得できた!シンプルでよき。

WindowsではWinsockを使うとできそう。
個人的にはいまのところ需要ないので、またこんど。
https://clown.hatenablog.jp/entry/20081225/p1