リモートワークの流行に伴い、
ウェブカメラの画像を加工する様々な方法
要するに、

この世に存在する
- PCに入力されたUVCデバイスの映像を加工した上で配信する
- カメラ側で加工してからUVCデバイスの映像としてPCに入力する
1のよくある例が、
2については市販のものだけで実現するのはおそらく難しいでしょう。ただし、
そして今回紹介するのは、
Linuxマシン上の映像をUVCデバイスとして出力するにはさらに2種類の方法に分かれます。
- v4l2loopbackなどを利用してソフトウェアで実現する
- UVC対応のHDMIキャプチャーボードを利用してハードウェアで実現する
1についてはウェブカメラとそれなりのスペックのPCさえあれば実現できます。ただ、
それに対して2は、
現在ではYouTuberに代表されるゲーム配信が広く普及しているため、
本記事ではTreasLin HSV323を利用します。ただし
HDMIキャプチャーデバイスはUbuntuでどのように見えるのか
HDMIキャプチャーデバイスには少なくとも、
まずはPCのHDMI出力とキャプチャーデバイスのHDMI入力をHDMIケーブルで接続した上で、

配信映像は外部ディスプレイ側の映像をまるっとそのまま配信できると取り回しが楽なので、
ちなみにHDMI出力を繋がなくてもUbuntu側から見れば、
普通のディスプレイデバイスなので、xrandr
コマンドでもディスプレイのプロパティを確認できます。
$ xrandr --props (中略) HDMI-A-1 connected 1920x1080+1920+0 (normal left inverted right x axis y axis) 708mm x 398mm EDID: 00ffffffffffff004477300001000000 0a160103807341780acf74a3574cb023 09484c21080081804540614095000101 010101010101023a801871382d40582c 4500c48e2100001e662150b051001b30 40703600c48e2100001e000000fc004d 537461722044656d6f0a2020000000fd 00324b1e5017000a20202020202001e0 020330f24d010304050790121314169f 2022260907071117508301000072030c 001000b84420c0840102030401410000 8c0ad08a20e02d10103e9600c48e2100 00188c0ad090204031200c405500c48e 21000018011d00bc52d01e20b8285540 c48e2100001e011d80d0721c1620102c 2580c48e2100009e000000000000006f _MUTTER_PRESENTATION_OUTPUT: 0 GAMMA_LUT_SIZE: 4096 range: (0, -1) DEGAMMA_LUT_SIZE: 4096 range: (0, -1) GAMMA_LUT: 0 range: (0, 65535) CTM: 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 DEGAMMA_LUT: 0 range: (0, 65535) TearFree: auto supported: off, on, auto vrr_capable: 0 range: (0, 1) max bpc: 8 range: (8, 16) underscan vborder: 0 range: (0, 128) underscan hborder: 0 range: (0, 128) underscan: off supported: off, on, auto scaling mode: None supported: None, Full, Center, Full aspect link-status: Good supported: Good, Bad CONNECTOR_ID: 80 supported: 80 non-desktop: 0 range: (0, 1) 1920x1080 60.00*+ 50.00 59.94 30.00 24.00 29.97 23.98 4096x2160 24.00 23.98 3840x2160 30.00 25.00 24.00 29.97 23.98 1680x1050 60.00 1280x1024 60.02 1440x900 59.90 1360x768 60.02 1280x800 60.00 1280x720 60.00 50.00 59.94 1024x768 60.00 800x600 60.32 720x576 50.00 720x480 60.00 59.94 640x480 60.00 59.94
キャプチャーデバイスとしてはUVCなので、lsusb
コマンドを実行するとそのデバイスが認識されていることもわかります。
$ lsusb Bus 002 Device 004: ID 1e4e:7103 Cubeternet MiraBox Video Capture Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 002: ID 8087:0a2b Intel Corp. Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 003 Device 002: ID 046d:c52b Logitech, Inc. Unifying Receiver Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
今回は一番上の
$ sudo lsusb -vs 002:004 Bus 002 Device 004: ID 1e4e:7103 Cubeternet MiraBox Video Capture Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 3.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 9 idVendor 0x1e4e Cubeternet idProduct 0x7103 bcdDevice 1.00 iManufacturer 6 MiraBox Video Capture iProduct 7 MiraBox Video Capture (後略)
さらにCheeseでウェブカメラとしての動作を確認したいところですが、
$ sudo apt install v4l-utils $ v4l2-ctl --list-devices MiraBox Video Capture : MiraBox (usb-0000:00:14.0-3): /dev/video0 /dev/video1
ビデオデバイスとしてはふたつ存在するようですが、
$ v4l2-ctl -d /dev/video0 --all Driver Info: Driver name : uvcvideo Card type : MiraBox Video Capture : MiraBox Bus info : usb-0000:00:14.0-3 Driver version : 5.4.30 Capabilities : 0x84a00001 Video Capture Metadata Capture Streaming Extended Pix Format Device Capabilities Device Caps : 0x04200001 Video Capture Streaming Extended Pix Format Priority: 2 Video input : 0 (Camera 1: ok) Format Video Capture: Width/Height : 1920/1080 Pixel Format : 'YUYV' (YUYV 4:2:2) Field : None Bytes per Line : 3840 Size Image : 4147200 Colorspace : sRGB Transfer Function : Default (maps to sRGB) YCbCr/HSV Encoding: Default (maps to ITU-R 601) Quantization : Default (maps to Limited Range) Flags : Crop Capability Video Capture: Bounds : Left 0, Top 0, Width 1920, Height 1080 Default : Left 0, Top 0, Width 1920, Height 1080 Pixel Aspect: 1/1 Selection Video Capture: crop_default, Left 0, Top 0, Width 1920, Height 1080, Flags: Selection Video Capture: crop_bounds, Left 0, Top 0, Width 1920, Height 1080, Flags: Streaming Parameters Video Capture: Capabilities : timeperframe Frames per second: 60.000 (60/1) Read buffers : 0
ちなみにCheeseでは認識しませんが、
$ sudo apt install guvcview

上記の例だとメインディスプレイとサブディスプレイの間にLibreOffice Impressのウィンドウをまたがせている状態で、
OBSを使って映像を加工する
さて、
OBS
Ubuntu 20.
$ sudo snap install obs-studio
あとはSuper+Aで表示されるアプリケーション一覧から

OBS自体は非常に多機能です。Ubuntuの他のアプリケーションとは異なるUIなので、
とりあえず今回は
ウェブカメラと任意の画像を合成する
OBSでは複数の
まずは任意の画像を選択しましょう。

ここで

今回は8.
$ cp /usr/share/backgrounds/hardy_wallpaper_uhd.png ~/snap/obs-studio/common/

ただしこのままだと一部しか表示されないので、

次はウェブカメラを合成します。まずはあらかじめウェブカメラを接続しておいてください。画像のときと同様にソースから+ボタンを押して、

この時点でフレームレートや解像度を変更できますが、

思ったよりもカメラの映像が小さくなっています。これは画像側の解像度が大きく、

このままだと先ほどと同じように画像の解像度が大きすぎるので、

今度はカメラの画像が大きいですね。こちらはカメラの画像をクリックしたら表示される赤枠を使って手作業で調整します。

さて、

今回は
イメージマスクではマスク画像を用意して、
もちろん円形以外の複雑な形でもかまいません。GIMPや任意の画像ツールを作って好みの画像を作成してください。ここではImageMagickを使ってコマンドで画像を生成してしまいます。
$ sudo apt install imagemagick $ convert -size 1920x1080 xc:black -fill white \ -draw "circle 960,540 1260,940" \ ~/snap/obs-studio/common/circle.png
マスク画像のアスペクト比はウェブカメラのそれと合わせておいたほうが楽です。ここでは16:9にしています。ちなみに使っているカメラのスペックの都合上、


マスク部分は固定になってしまうので、
エフェクトフィルタはさまざまな効果を適用できますので、
合成した画像をUVCデバイスとして出力する
合成した画像をUVCデバイスとして出力します。これはOBSの文脈で言うとシーンの出力になります。そしてOBSにはシーンの出力方法として任意のディスプレイへ全画面出力する
シーンを右クリックして、

これでUVCデバイスとして現在のシーンが出力されているはずです。ためしにguvcviewで確認してみましょう。


これでうまく使えばZoomなどでも
ちなみにリモートミーティングにおける個人的にベストな解は