AndroidとUnityでUSB接続のUVCカメラを使用する
AndroidとUnityでUSB接続のUVCカメラを使用して、ailia SDKと連携させる方法を解説します。
AndroidとUnityにおける外部カメラの扱い
Androidでは一般的にデバイスにカメラが内蔵されており、それを使用することが前提になっています。そのため、USB接続のUVCカメラについては扱いが不十分です。そのため、UnityのWebCamTextureからはUSB接続のUVCカメラを扱うことができません。
実際に、USB接続のUVCカメラを接続した場合、WebCamTextureからは列挙されないか、列挙はするものの、列挙されたものを選択すると、Android OSのCameraManager.javaの中のgetCameraCharacteristicsでinfo.setCameraId(Integer.parseInt(cameraId));が呼び出されて、UVCカメラのIDである/dev/video5をintに変換できずに例外が発生します。
UnityからUSB接続の外部カメラを扱うアセット
UnityからUSB接続の外部カメラを扱うアセットとして、UVC4UnityAndroidが開発されています。

UVC4UnityAndroid
このアセットは、Android OSのCameraManagerを使用せず、直接、USBを制御することで、外部カメラを扱うことを可能にしています。
車輪の再発見みたいな?人と技術のすきまにserenegiant.com
そのため、UnityのWebCamTextureでは扱えない、USB接続の外部カメラを扱うことが可能となります。
UVC4UnityAndroidの使用方法
NuGetのインストール
NuGetのUnity Packageをインストールします。
インストール後、ウィンドウメニューのNuGetから、Manage NuGet Packagesを選択し、System.Text.Jsonをインストールします。
UVC4UnityAndroidのインストール
UVC4UnityAndroidのUnityPackageをインストールします。
UVC4UnityAndroidの実行
下記にサンプルシーンがあり、実行可能です。
UVC4UnityAndroid/Assets/UVC4UnityAndroidPlugin/Samples/Scenes/UVC2DScene.unity
なお、PC上では、DllNotFoundExceptionが発生します。Androidのデバイスで実行する必要があります。

UVC2DSceneを実行
UVC4UnityAndroidのシーンへの取り込み
UVC4UnityAndroidは、下記のprefabをシーンに取り込むことで実装可能です。
UVC4UnityAndroid/Assets/UVC4UnityAndroidPlugin/Prefabs/UVCDrawer.prefab

Prefabの取り込み
UVCDrawerはRenderTargetsに指定したRawImageに対してレンダリングを行います。

RenderTargetにRawImageを指定
そのため、RawImage.textureからGetPixels32することで、画像を取得可能です。
なお、RawImage.textureはそのままではReadできないため、一度、RenderTextureにBlitする必要があります。
Texture2D duplicateTexture(Texture2D source)
{
RenderTexture renderTex = RenderTexture.GetTemporary(
source.width,
source.height,
0,
RenderTextureFormat.Default,
RenderTextureReadWrite.Linear);
Graphics.Blit(source, renderTex);
RenderTexture previous = RenderTexture.active;
RenderTexture.active = renderTex;
Texture2D readableText = new Texture2D(source.width, source.height);
readableText.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0);
readableText.Apply();
RenderTexture.active = previous;
RenderTexture.ReleaseTemporary(renderTex);
return readableText;
}
UVC4UnityAndroidのビルド時の注意点
ILCPPを有効にしてGraphics APIがAutoだとVulkanが使用されます。Auto Graphics APIを無効にして、明示的にOpenGLを指定する必要があります。

Player Settings
UVC4UnityAndroidの動作
UVCUnityAndroidはUVCManager.csとUVCDrawer.cs、NativePluginから構成されます。
UVCManager.csでは、MonoBehaviourのStartでCameraのPermissionを取得し、PERMISSION_GRANTの場合はInitPluginを呼び出します。InitPluginではAndroidJavaClassを取得し、NativeのinitUVCDeviceDestectorを呼び出します。その後、UVCの状態が変化するとOnDeviceChangedが呼び出され、StartPreviewでUVCの再生が開始します。
UVCManager.csのGetAttachedDevices APIで接続されているデバイスの一覧を取得可能です。
UVCDrawer.csでは、Textureを生成し、RenderTargetsのRawImageに設定します。
UNITY_EDITORでの例外の抑制
既存コードでは、PC上での実行時にAndroidUtils.csのAwakeで例外が発生するため、#if UNITY_ANDROIDを#if UNITY_ANDROID && !UNITY_EDITORにすると回避可能です。合わせて、UVCManager.csのStart()でも、#if !UNITY_ANDROID ||UNITY_EDITORでyield breakするように、OnDestroy()でも#if !UNITY_ANDROID ||UNITY_EDITORでreturnするようにします。
ailia SDKとの連携
サンプルプロジェクト
UVC4UnityAndroidをailia SDKと連携してyoloxを推論するサンプルを下記に公開しています。
ailia SDKのインストール
git cloneした後、上記の手順に従って、NuGet、UVC4UnityAndroidのUnityPackageをインポートしてください。また、ailia SDKのUnityPackageをPluginsフォルダだけインポートしてください。

インポート後のフォルダ構成
ビルド済みサンプル
事前ビルドしたAPKファイルは下記にアップロードしています。
サンプルのAPKをUSB経由でインストールし、USBを抜き、UVCカメラのUSBをデバイスに接続、アプリを起動してください。初回起動時は承認が求められます。
うまくカメラの映像が出ない時は、一度、アプリを落として、UVCカメラのUSBを抜き差ししてください。UVCカメラを認識すると、自動的にアプリが立ち上がり、カメラ映像が表示されます。

Androidに外部のUSBカメラを接続した例
Arm Maliへの対応
公式にリリースされているUnityPackageの0.2.1を使用した場合、Arm MaliでOpenGLのシェーダエラーが発生する場合があります。その場合、githubの最新のコミットから0.2.2のバイナリをダウンロードし、Pluginフォルダの内容を置き換えることで、問題が解消する場合があります。

Androidフォルダのバイナリを0.2.1から0.2.2に置き換え
特定デバイスの除外
UVCクラスはdeviceClass = 239、deviceSubClass = 2を持っています。しかし、WEBカメラ以外のUVCデバイスも同じdeviceClassであるため、WEBカメラと一緒に、Bluetoothなどが接続されている場合に、WEBカメラの映像が取得できない場合があります。
その場合、ベンダーIDとプロダクトIDを使用して、特定のデバイスを除外することで、WEBカメラの接続が可能です。具体的に、UVCDrawer.csのOnUVCAttachEventで、vidとpidを確認し、resultにfalseを代入します。
public bool OnUVCAttachEvent(UVCManager manager, UVCDevice device)
{
#if (!NDEBUG && DEBUG && ENABLE_LOG)
Console.WriteLine($"{TAG}OnUVCAttachEvent:{device}");
#endif
// XXX 今の実装では基本的に全てのUVC機器を受け入れる
// ただしTHETA SとTHETA VとTHETA Z1は映像を取得できないインターフェースがあるのでオミットする
// CanDrawと同様にUVC機器フィルターをインスペクタで設定できるようにする
var result = !device.IsRicoh || device.IsTHETA;
result &= UVCFilter.Match(device, UVCFilters);
ConnectedDeviceName = ""+device.name+"\nClass:"+device.deviceClass+" "+device.deviceSubClass+"\nVid:"+device.vid+" Pid:"+device.pid+"\n";
if (device.vid == 3725 && device.pid == 31073){
result = false;
}
return result;
}
まとめ
UVC4UnityAndroidを使用することで、Androidデバイス上で外部カメラを扱うことが可能になります。また、ailia SDKと連携することで、外部カメラの映像に対してAI推論が可能になります。
アイリア株式会社はAIを実用化する会社として、クロスプラットフォームでGPUを使用した高速な推論を行うことができるailia SDKを開発しています。アイリア株式会社ではコンサルティングからモデル作成、SDKの提供、AIを利用したアプリ・システム開発、サポートまで、 AIに関するトータルソリューションを提供していますのでお気軽にお問い合わせください。
ailia Tech BLOG