ヴェズルフェルニルの研究ノート

座右の銘「ただ一人犀の角のように歩め」的な研究活動ノート

Stable Diffusion Web UI|Ubuntu 22.04でのインストール

前記事でEasy Diffusionというものを紹介したが、同様のプログラムとしてStable Diffusion Web UIというのがある。

blog.ketus-ix.work

じつは、Stable Diffusionを利用して画像生成をやるなら、こちらが本命のプログラムだ。画像生成処理に適用できる数多くのパラメータが用意されており、それらを調整することで多種多様な画像を生成できる。インターネット上での使い方などの情報量が多く、モデル配布サイトでもこのStable Diffusion Web UI用のパラメータ設定値が記載されていることが多い。

お触り入門的にやるなら、Easy Diffusionでも良いと思うが、本気でStable Diffusionによる画像生成をやるなら、現状このAUTOMATIC1111版Stable Diffusion Web UIの一択だと言って良いほど広く使われている。

github.com

このStable Diffusion Web UIをUbuntu 22.04上にインストールして使い始めたので、自分の備忘録も兼ねて、その手順を書いておく。

NVIDIA GPUドライバのインストール

前記事では、CUDA ToolkitとcuDNNのインストール方法の説明は省略したが、本記事では書いておこう。

ただし、この2つは後述のAnacondaやMinicondaを使って作成したPython仮想環境の中にインストールすることもできる。システム側のCUDA,cuDNNとは分離された環境となるので、この方が融通性が高い(システム側のCUDA,cuDNNは別のソフトウェアの開発用に使っているので、弄るのは避けたかったという理由もある)。今回はこの方法を使った。

このような環境を作るのための条件として、システム側にNVIDIA GPU用ドライバがインストールされている必要がある。同ドライバがまだインストールされていない場合(nvidia-smiコマンドで確認できる)は、以下の操作によってインストールすることができる。

ubuntu-drivers devices
== /sys/devices/pci0000:00/0000:00:01.1/0000:01:00.0 ==
modalias : pci:v000010DEd0000249Csv00001043sd00001602bc03sc00i00
vendor   : NVIDIA Corporation
model    : GA104M [GeForce RTX 3080 Mobile / Max-Q 8GB/16GB]
driver   : nvidia-driver-545 - third-party non-free
driver   : nvidia-driver-525-open - distro non-free
driver   : nvidia-driver-470-server - distro non-free
driver   : nvidia-driver-535-server - distro non-free
driver   : nvidia-driver-535-open - distro non-free
driver   : nvidia-driver-525-server - distro non-free
driver   : nvidia-driver-520 - third-party non-free
driver   : nvidia-driver-470 - third-party non-free
driver   : nvidia-driver-535-server-open - distro non-free
driver   : nvidia-driver-545-open - third-party non-free recommended
driver   : xserver-xorg-video-nouveau - distro free builtin
  

GPUの種類にもよるが、大抵はrecommendedとして最新バージョンが推薦されるはずだ。CUDAやcuDNNを利用する場合は、この推薦されているバージョンの-openでない方を選択する。

つまり、上のような出力情報なら、nvidia-driver-545をインストールするべきだ。

sudo apt install nvidia-driver-545
reboot

nvidia-driverをインストールしたら、システムを再起動しておく。

Stable Diffusion Web UI用Python仮想環境の作成

Minicondaのインストール

Stable DiffusionはPythonで記述されたプログラムなので、稼働ベースとしてPython仮想環境を利用するケースが多い(システム側のPythonを使うのは避けた方が良い)。

Python仮想環境ツールにはいくつかの種類があるが、Stable Diffusionを使うときに広く利用されているのはAnacondaやMinicondaなどのconda系仮想環境のようだ。

ここでは、Minicondaを使うことにする。

curl https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -o Miniconda3-latest-Linux-x86_64.sh
chmod +x Miniconda3-latest-Linux-x86_64.sh
./Miniconda3-latest-Linux-x86_64.sh

なお、言語環境ツールとしてpyenvやasdfを利用している場合は、以下のコマンドによってMinicondaをインストールすることができる。

  • pyenv
pyenv install miniconda3-latest
pyenv global miniconda3-latest
asdf install python miniconda3-latest
asdf global python miniconda3-latest

Python仮想環境の作成

Stable Diffusion Web UI用の仮想環境を作成する。仮想環境の名前は任意で良いが、ここではsdwebuiとしておく。

conda deactivate
conda create --name sdwebui python=3.10
conda activate sdwebui

CUDAとcuDNNのインストール

作成した仮想環境の中にCUDAとcuDNNをインストールする。

conda install -c conda-forge cudatoolkit=11.8.0
pip install nvidia-cudnn-cu11==8.6.0.16

さらに、CUDAとcuDNNライブラリへのパスを通すために、以下のような設定を追加する。

mkdir -p $CONDA_PREFIX/etc/conda/activate.d
echo 'CUDNN_PATH=$(dirname $(python -c "import nvidia.cudnn;print(nvidia.cudnn.__file__)"))' > $CONDA_PREFIX/etc/conda/activate.d/env_vars.sh
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CONDA_PREFIX/lib:$CUDNN_PATH/lib' >> $CONDA_PREFIX/etc/conda/activate.d/env_vars.sh

上の操作が済んだら、この仮想環境を再起動する。

conda deactivate
conda activate sdwebui

Stable Diffusion Web UIのインストール

インストール

上記でcondaコマンドによって作成したPython仮想環境上にStable Diffusion Web UIをインストールするので、この仮想環境がアクティブ状態になっていることが、同プログラムのインストールおよび起動条件となる。もし仮想環境がアクティブ状態になっていない場合は、上で作成した仮想環境をconda activate sdwebuiコマンドによってアクティブ状態にしておく。

Stable Diffusion Web UIのインストールは、以下のように、ソースを取得した上でシェルスクリプトwebui.shを実行すれば開始できる。

git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git
cd stable-diffusion-webui
./webui.sh

インストール処理が完了すると、自動的にブラウザが起動して、その中に下のような画面が表示される(ベージURLは127.0.0.1:7860)。

補足情報

COMMANDLINE_ARGSの設定

GPUを利用した画像生成処理の高速化が図れるxFormersを有効にする場合、ファイルwebui-user.shを以下のように編集する。

vi webui-user.sh
-#export COMMANDLINE_ARGS=""
+export COMMANDLINE_ARGS="--xformers"

Stable Diffusion公式でもこの機能を有効することが推薦されており、確かにGPU搭載機では画像生成が速くなるので、NVIDIA GPU搭載機の場合はデフォルトでこの機能を有効にした方が良い。

GPU VRAMが4GBより小さい場合は、COMMAND_ARGS=の設定を下のようにすると、画像生成処理でVRAMメモリがより効率的に使われる。

COMMAND_LINE_ARGS="--xformers --medvram --opt-split-attention"

GPU VRAMが8GBより小さい場合は、同設定を下のように変更すると、画像生成処理でVRAMメモリがより効率的に使われる。

COMMAND_LINE_ARGS="--xformers --lowvram --opt-split-attention"

webui.shによるインストールの結果、PyTorch 2.0以降が追加された場合(webui.sh起動時の出力情報、またはpip listコマンドで確認できる)は、以下にように変更することで、--xformersと同等の画像生成処理の高速化が図れる。

-export COMMANDLINE_ARGS="--xformers"
+export COMMANDLINE_ARGS="--opt-sdp-attention --opt-sdp-no-mem-attention"

現在、小生のGPU搭載機ではこの設定を使っているが、この辺の設定はStable Diffusion Web UIのバージョンによって違ってくるので、あくまでこれは参考情報として見てほしい。

Cannot locate TCMalloc警告の解決

シェルスクリプトwebui.shを実行すると、Cannot locate TCMalloc (improves CPU memory usage)という警告メッセージが表示されるが、下のコマンドによってTCMalloc(GoogleC/C++用メモリアロケータ)をインストールすれば、これを回避できる。

sudo apt install --no-install-recommends google-perftools

仮想環境の自動起動

シェルスクリプトwebui.shによるStable Diffusion Web UIの起動時に、自動的に仮想環境を起動したいなら、以下をwebui-user.shの先頭に追加しておく。

#!/bin/bash
eval "$(conda shell.bash hook)"
conda activate sdwebui

Stable Diffusion Web UIの動作確認

Stable Diffusion Web UIの初歩的な使い方はEasy Diffusionと似ている。

説明文だけから画像を生成する場合は、[txt2img]タブ画面上のテキストボックスにプロンプト文を入力して、[Generate]ボタンを押す。モデルから画像を生成したい場合は、[Stable Diffusion checkpoint]メニューからモデルを選んで、同タブ画面上のテキストボックスにプロンプト文を入力してした上で、[Generate]ボタンを押すと、画像の生成が開始される。

モデルファイルをディレクトstable-diffusion-webui/models/Stable-diffusionへコピーして、Stable Diffusion Web UIを再起動するか、[Stable Diffusion checkpoint]メニュー横の更新ボタンを押せば、追加したモデルが選択できるようになる。

プロンプト用のテキストボックスが2つあるが、上側が生成したい画像の説明、下側が生成したい画像に対する否定的な説明を入力する。両方のプロンプト文を入力すると、より目的に合った画像が生成されやすくなるようだ。

前記事と同じように、適当に選んだモデルを使って、Stable Diffusion Web UIによる画像の生成をやってみた。お借りしたモデルとプロンプトはこちら。

civitai.com

civitai.com

【追記】〔2023-12-04〕

Intel MacにもStable Diffusion Web UIをインストールしてみた。インストールは問題なくできて(NVIDIA GPUドライバ、CUDA、cuDNNは当然インストールしていないが)、画像の生成もできることはできる。

ただし、やはり画像生成に時間がかかってしまう。上と同じ条件で画像を生成してみたが、1分40秒かかってしまった。NVIDIA GPU搭載機(VRAM 16GB)では2秒だから、この差は大きい。

小生はまだM1/M2 Macを持っていないんだけど、これらだと画像生成がもっと速くなるんだろうか。もし生成時間が1分以内になるのなら、M1/M2 Macでも画像生成を本格的にやれると思う。 やっぱり早くApple Silicon Macを手に入れないとダメだなぁ。

【参照サイト】

https://blog.csdn.net/weixin_41216652/article/details/131995014blog.csdn.net

pywkt.com

Easy DiffusionによるStable Diffusion画像生成ことはじめ

いま流行りの生成系AIについに手を出し始めた。生成系AIで一番やってみたかったのは画像・動画の生成なので、Stable Diffusionを使ってみることから始めた。

オープンソースのStable Diffusionを利用した画像生成プログラムがいくつか存在するが、その中からEasy Diffusionというものを選択して動かしみた。

easydiffusion.github.io

GPU搭載ノートPCとIntel Macの両方で試してみた。

ちなみに、前者のスペックは以下のとおり。

 CPU : AMD Ryzen 9 5900HX(コア数 8,スレッド数 16)
    動作周波数(標準/最大):3.3GHz/4.6GHz
 メモリ : 32GB
 GPU : NVIDIA GeForce RTX 3080 Max-Q VRAM 16GB

なお、NVIDIA GPU搭載機ではあらかじめCUDA ToolkitとcuDNNをインストールしておく必要があるが、これらについては説明を省略する。

Easy Diffusionのインストール

Easy Diffusionのインストールはすごく簡単だ。

ダウンロードしたzipファイルを解凍して、作成されたディレクトリの中でstart.shというシェルスクリプトを実行するだけだ。

cd easy-diffusion
./start.sh

このシェルスクリプトPython仮想環境、Pythonライブラリ、Stable Diffusion本体、モデルファイルなどすべてのコンポーネントのインストールをやってくれる。

Easy Diffusionの動作確認

上記のシェルスクリプトによるインストールが完了すると、自動的にブラウザが起動して、そこに下のようなEasy DiffusionのUI画面が表示される(ベージURLはlocalhost:9000)。

[Enter Prompt]テキストボックスに生成したい画像について説明する文言を入力して、[Make Image]ボタンを押せば画像の生成が開始される。

上述スペックのGPU搭載機だと、サイズ512x512 1枚のみの画像の生成に4秒位だが、Intel Mac(CPU:Core i9 2.9GHz 6コア/12スレッド,メモリ:32GB)だと4分位かかる。あらかじめ判っていたことだが、画像生成AIの利用にはGPUが必須だと言えるだろう。

Easy Diffusionのモデル適用方法

最近多くのサイトで観られるリアル系美女、コスプレ、アニメ調などのAI画像は元となるモデルファイルを利用して、それをStable Diffusionなどの画像生成AIに適用することで作成されている。

こういう画像生成AI用モデルを配布しているサイトがいくつかあるが、その中で一番有名なのがCivitaiだ。このサイトから適当に選んだモデルを入手して、Easy Diffusionを使って画像の作成をやってみた。

civitai.com

上のモデル・ページ内の[ V1.5 - Pruned ]というのを選択してダウンロードしたファイルaniverse_v15Pruned.safetensors(約2.0GB)をディレクトeasy-diffusion/models/stable-diffusionへコピーして、Easy Diffusionを再起動するか、後述の[Model]メニュー横の更新ボタンを押すと、追加したモデルの選択が可能になる。モデルの変更は[Generative]タブ画面内の[Image Settings][Model] メニューによって切り替えることができる。

プロンプト文はモデルのページに掲載されているいくつかの例から選んだが、これを工夫することで、自分の目的に合った画像を生成することもできるようになるのかもしれない。画像生成AI用のプロンプト文が掲載されているサイトもたんさん存在している。

しかし、このように自分で作成した画像を晒してしまうと、観た人にその人の嗜好が想像できてしまうなぁ。

いま画像生成AIが大流行しているのは、こういうモデル配布やプロンプト掲載サイトの出現によって、誰でも高品質なAI画像を手軽に作成できるようになったことも影響しているのだろう。

画像生成AIを始めた目的はこの方面で稼ぐ方法を見つけられたらと思っているからだ。ディープラーニング開発の経験はあるので、本気でやればStable Diffusionなどの学習・生成ネットワークモデルを深く理解できる自信はある。その知見からモデルのカスタマイズまでできるようになれば、他の人とは違った画像を作成できるようになれるかもしれない。

動画・絵師クリエーターへの憧れもあったので(技能やセンスがないので諦めていたが)、AIの力を借りているとしても画像生成をやるのはすごく楽しい。これから、しばらく画像生成AIの研究に集中して取り組んでいき、最終的に自分のセンスが反映された画像や動画を作成できるようになりたい。

【参照サイト】

relax-tech.net

LimaによるDocker Desktop代替環境の構築

最近Node.js + ExpressやPython + FastAPIなどを使って、サーバー・プログラムを作ることが多くなってきた。

サーバー・プログラムを作るときは、Dockerを利用するかどうかでぜんぜん作業効率が違ってくる。

小生のメインPCはMacなので、いままでMac版Docker Desktopを使っていたが、Docker Desktopの商用利用には「一定規模以上の企業で利用する場合有料サブスクリプションが必要」という制限がある。

いまやサーバー・プログラム開発にはDockerは欠かせない存在なので、Docker Desktopに代わる別の方法を探していたらLimaというものを見つけた。

github.com

LimaはQEMUベースの仮想マシン・ツールで、Dockerに代わる仮想マシン環境として利用すると、Docker Desktopを利用しなくてもDockerコンテナを扱うことができるようになる。

本記事では、Limaを利用したDocker環境の構築方法を紹介しよう。ただし、いまのところMacでしかLimaを利用していないので、Mac限定の内容で書いておく。

LimaおよびDockerのインストール

% brew install lima

Dockerコンテナの作成や操作のためにdockerコマンドは利用するので、dockerバッケージはインストールしておく必要がある。

% brew install docker

docker-composeを利用する場合は、それもインストールする。

% brew install docker-compose

LimaによるDocker仮想マシンのインストール

下のコマンドによって、Dockerエンジンとなる仮想マシンをインストールできる。

% limactl create --name=default template://docker

これがDocker Desktopに含まれているdockerデーモンに代わるものとなる。

limactl createコマンドによってインストールした仮想マシンは停止状態となっている。

% limactl list
NAME       STATUS     SSH            VMTYPE    ARCH      CPUS    MEMORY    DISK      DIR
default    Stopped    127.0.0.1:0    qemu      x86_64    4       4GiB      100GiB    ~/.lima/default

この仮想マシンを起動するには、下のコマンドを実行すれば良い。

% limactl start
% limactl list
NAME       STATUS     SSH                VMTYPE    ARCH      CPUS    MEMORY    DISK      DIR
default    Running    127.0.0.1:60022    qemu      x86_64    4       4GiB      100GiB    ~/.lima/default

コマンドlimactl createではなくlimaclt start --name=default template://dockerを使うと、Docker仮想マシンのインストールと起動まで同時に行える。

Docker仮想マシンが起動状態だとCPUパワーを消費するので、Dockerコンテナを利用しないときは、limactl stopコマンドによって停止しておいた方が良いだろう。

あとは、dockerコマンドを使ってDockerイメージの生成やコンテナの起動などの操作が行える。

Lima Docker仮想マシンのリソース制限変更

Dockerコンテナの内容によっては、Docker仮想マシンの使用リソース制限を拡張しないとビルドできないときがある。

下の一連の操作によって、Docker仮想マシンのリソース制限値を変更することできる。

% limactl stop default
% limactl list
NAME       STATUS     SSH            VMTYPE    ARCH      CPUS    MEMORY    DISK      DIR
default    Stopped    127.0.0.1:0    qemu      x86_64    4       4GiB      100GiB    ~/.lima/default
% limactl delete default
% limactl create  --cpus=6 --memory=8 --disk=800 --name=default template://docker
% limactl list
NAME       STATUS     SSH            VMTYPE    ARCH      CPUS    MEMORY    DISK      DIR
default    Stopped    127.0.0.1:0    qemu      x86_64    6       8GiB      800GiB    ~/.lima/default
% limactl start default

Lima Docker仮想マシンとDocker Desktopの共存

LimaのDocker仮想マシンを利用するならDocker Desktopをアンイストールできるが、Docker Hub閲覧機能などを利用したくてこれを残したい場合もあるだろう。

Docker Desktopに含まれているdockerデーモンの起動状態は、下のコマンドによって知ることができる。

% docker context list
NAME                TYPE                DESCRIPTION                               DOCKER ENDPOINT                                      KUBERNETES ENDPOINT   ORCHESTRATOR
default             moby                Current DOCKER_HOST based configuration   unix:///var/run/docker.sock
desktop-linux       moby                Docker Desktop                            unix:///Users/LOGNAME/.docker/run/docker.sock
lima-default *      moby                                                          unix:///Users/LOGNAME/.lima/default/sock/docker.sock

Lima Docker仮想マシンが稼働している状態では上のようになっているが、Docker Desktopを起動すると、これは下のような状態に変わる。

% docker context list
NAME                TYPE                DESCRIPTION                               DOCKER ENDPOINT                                      KUBERNETES ENDPOINT   ORCHESTRATOR
default             moby                Current DOCKER_HOST based configuration   unix:///var/run/docker.sock
desktop-linux *     moby                Docker Desktop                            unix:///Users/LOGNAME/.docker/run/docker.sock
lima-default        moby                                                          unix:///Users/LOGNAME/.lima/default/sock/docker.sock

dockerコマンドの実行時に使われるデーモンは、このdockerコンテキストによって管理されている。

下のコマンドを実行すると、dockerコマンドの実行時に使わるコンテキストはLima Docker仮想マシンになる。

% docker context use lima-default

これをDocker Desktop側のdockerデーモンに変える場合は、下のコマンドを実行する。

% docker context use desktop-linux

なお、Lima Docker仮想マシンを利用して作成したDockerイメージとDocker Desktopのdockerデーモンによって作成したイメージは別々に管理されている。前者のイメージをDocker Desktopで見ることはできないし、後者のイメージをlima-defaultコンテキスト有効時のdocker imagesコマンドで見ることもできない。

【参照リンク】

lima-vm.io

nopipi.hatenablog.com

stella_vslam | Dockerによるビルドと動作確認〔Mac編〕

前記事で行ったDockerによるstella_vslamのビルドを動作確認をMac上でもやってみた。

blog.ketus-ix.work

結論から先に書くと、PangolinViewer版stella_vslamはビルドはできるが動作させることはできなかった。

stella_vslamのドキュメントサイトにもMacはNGだと記載されている。

stella-cv.readthedocs.io

SocketViewer版stella_vslamはビルドも動作確認も問題なくできる。ただし、Dockerコンテナの起動方法がUbuntuの場合とは異なっている。

PangolinViewer版stella_vslamはNGだが、記録として、作業内容を書いておく。

PangolinViewer版stella_vslamのビルドと動作確認

Dockerイメージのビルド

前記事のコマンドによって、PangolinViewer版stella_vslam Dockerイメージのビルドは問題なくできる。

ただし、Docker Engineのメモリ・リソース制限をデフォルト値より大きくしておく必要がある。Docker Desktopの場合は、下の画面からその設定値を変更できる。

おおよそ14GB以上なら、本Dockerイメージをビルドできるようだ。

Dockerコンテナの起動

当然ながら、ビルド生成したDockerコンテナの起動は問題なくできる。本コンテナを起動するコマンドは前記事と同じ。

Dockerコンテナの動作確認

PangolinViewer版stella_vslamはX GUIを利用しているプログラムなので、MacにもX Window Systemが必要だ。MacX Window System XQuartzがインストールされていることが前提条件となる。

X GUI利用DockerコンテナをMac上で起動する方法が下のリンクにまとめられている。

blog.aoirint.com

このページに記載されているすべての方法を試したが、ダメだった。

コンテナ内のstella_vslamプログラムがホスト側Xディスプレイの存在を認識できても、ほとんんどのケースで下のようなエラーが出力されて停止してしまう。

libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
X11 Error: BadValue (integer parameter out of range for operation)
terminate called after throwing an instance of 'std::runtime_error'
  what():  Pangolin X11: Failed to create an OpenGL context

MacOpenGLリダイレクトを有効にする下のコマンドを実行済みの状態でもダメだ。

% defaults write org.macosforge.xquartz.X11 enable_iglx -bool true

もしかすると、stella_vslam側で使われているOpenGLMac側の同バージョンが関係しているのかもしれない。

上の参照ページに記載されている各方法を試した際のstella_vslamプログラムの挙動を観ていると、「socatを使う方法(UnixソケットをTCPにリレーする方法)」が上手くいく可能性が高そうな感触はあるんだけど。

DockerコンテナのXディスプレイ出力先をMacホストではなく仮想マシンなどの他のPCへリダイレクトすると動くかもしれないが、それではMac上で動いているとは言えないだろう。

また時間があったら、本問題にトライしてみようと思っている。

SocketViewer版stella_vslamのビルドと動作確認

Dockerイメージのビルド

前記事のコマンドによって、SocketViewer版stella_vslam Dockerイメージ(stella_vslam本体とsocket-viewer)のビルドは問題なくできる。

Dockerコンテナの起動

socket-viewer

% docker run --rm -it --name stella_vslam-viewer -p 3001:3001 stella_vslam-viewer
WebSocket: listening on *:3000
HTTP server: listening on *:3001

Macでsocket-viewerを起動する場合は、-p 3001:3001オプションを付加してコンテナを起動する。これは、DockerコンテナのTCPポートをホスト側へポートフォワードする設定だ。

ここで、Webブラウザからhttp://localhost:3001/へアクセスする。

そして、socket-viewerコンテナが起動している状態で下のコマンドを実行する。

% docker inspect stella_vslam-viewer | grep -m 1 \"IPAddress\" | sed 's/ //g' | sed 's/,//g'
"IPAddress":"172.17.0.2"

このコマンドによって、socket-viewerコンテナのIPアドレスを知ることができる。

stella_vslam本体

stella_vslam本体コンテナは以下のコマンドによって起動する(--net=hostオプションは不要)。

% docker run --rm -it --name stella_vslam-socket \
    --volume ~/VSLAM/Docker/stella_vslam/vocab:/vocab:ro \
    --volume ~/VSLAM/Docker/stella_vslam/dataset:/dataset:ro \
    stella_vslam-socket
root@f3eb6409feb7:/stella_vslam_examples/build# 

Dockerコンテナでの動作確認

stella_vslam本体コンテナ(stella_vslam-socket)が起動したら、下のコマンドを実行する。

  • コンテナ stella_vslam-socket
# ls /
bin   dataset  etc   lib    lib64  ...   ...   ...   stella_vslam           sys   usr   vocab
...   ...   ...   ...   ...  ...   ...   ...   ...   stella_vslam_examples  tmp   var
# echo -e "SocketPublisher:\n  server_uri: \"http://172.17.0.2:3000\"" >> /stella_vslam/example/aist/equirectangular.yaml
# cat /stella_vslam/example/aist/equirectangular.yaml
....    ....
....    ....
SocketPublisher:
  server_uri: "http://172.17.0.2:3000"

これは、stella_vslamのコンフィグレーションファイルにsocket-viewerコンテナ(stella_vslam-viewer)のURIIPアドレスとWebSocketサーバーのポート番号)設定値を追加している。

上の操作が済んだら、同コンテナ内でstella_vslamプログラムを起動すれば、Webブラウザのウィンドウにグラフィック描画画面が表示されるはずだ。

  • コンテナ stella_vslam-socket
# At the /stella_vslam_examples/build directory
# pwd
/stella_vslam_examples/build
# ls /
bin   dataset  etc   lib    lib64  ...   ...   ...   stella_vslam           sys   usr   vocab
...   ...   ...   ...   ...  ...   ...   ...   ...   stella_vslam_examples  tmp   var
# ./run_video_slam \
    -v /vocab/orb_vocab.fbow \
    -m /dataset/aist_living_lab_1/video.mp4 \
    -c /stella_vslam/example/aist/equirectangular.yaml \
    --frame-skip 3 \
    --no-sleep \
    --map-db-out map.msg \
    --viewer socket_publisher

-cオプションで指定するコンフィグレーションファイルは、上記の操作で書き換えたものでなければならない。

stella_vslam | Dockerによるビルドと動作確認

以前の記事でUbuntu 20.04上でのstella_vslamのビルドと動作確認を行ったが、stella_vslam用のDockerfileが在るので、Dockerを使ったビルドと動作確認もやってみた。

blog.ketus-ix.work

stella_vslamのドキュメントサイトに記載されている内容とほとんど同じだが、自分の備忘録として記事に書いておく。

stella-cv.readthedocs.io

以降の作業は、Ubuntu 20.04上でDocker-CE 24.0を使って行った。

Dockerのインストール

Dockerが導入済みでない場合は、インストールしておくこと。

NVIDIA GPU搭載PCの場合は、nivida-dockerもインストールしておくと、DockerコンテナでGPUが利用されるので動作速度が向上する。

stella_vslamのGitHubリポジトリから取得したファイルの中に、Dockerをインストールできるシェルスクリプトが収納されている。

Ubuntu上にDockerが未インストールの場合は、これらのシェルスクリプトを利用すると良い。

$ git clone --recursive https://github.com/stella-cv/stella_vslam.git
$ cd stella_vslam/scripts/ubuntu
$ ./install_docker.sh
# GPUを利用する場合は、下のコマンドも実行する
$ ./install_nvidia_docker.sh

サンプルデータセットの取得

stella_vslamのDockerコンテナ内で動作確認に使用するサンプルデータセットをダウンロードしておく。

この操作用のシェルスクリプトがstella_vslamのリポジトリに含まれている。

$ git clone --recursive https://github.com/stella-cv/stella_vslam.git
$ cd stella_vslam/scripts/ubuntu
$ ./download_sampledata.sh

PangolinViewer版stella_vslamのビルドと動作確認

Dockerイメージのビルド

$ mkdir -p ~/VSLAM/Docker
$ cd ~/VSLAM/Docker
$ git clone --recursive https://github.com/stella-cv/stella_vslam.git
$ cd stella_vslam
$ docker build -t stella_vslam-desktop -f Dockerfile.desktop . --build-arg NUM_THREADS=`expr $(nproc) - 1`

Dockerコンテナの起動

# ログインユーザからのX11ディスプレイへのアクセスを許可
$ xhost +local:
# コンテナの起動
$ docker run -it --rm -e DISPLAY=$DISPLAY -v /tmp/.X11-unix/:/tmp/.X11-unix:ro \
    --volume ~/VSLAM/Docker/stella_vslam/vocab:/vocab:ro \
    --volume ~/VSLAM/Docker/stella_vslam/dataset:/dataset:ro \
    stella_vslam-desktop
root@0b8206d0372f:/stella_vslam_examples/build# 

GPUを利用する場合は、docker runコマンドに--gpus allオプションを付加してコンテナを起動する。

なお、stella_vslamのリポジトリに上の操作をすべて実行するシェルスクリプトが含まれている。

下のコマンドを実行すると、サンプルデータセットの取得、PangolinViewer版stella_vslam Dockerイメージのビルド、同コンテナの起動まで行える。

$ git clone --recursive https://github.com/stella-cv/stella_vslam.git
$ cd stella_vslam/scripts/ubuntu
$ ./download_sampledata.sh
$ ./build_stella_vslam_docker.sh

Dockerコンテナでの動作確認

  • コンテナ stella_vslam-desktop
# At the /stella_vslam_examples/build directory
# pwd
/stella_vslam_examples/build
# ls /
bin   dataset  etc   lib    lib64  ...   ...   ...   stella_vslam           sys   usr   vocab
...   ...   ...   ...   ...  ...   ...   ...   ...   stella_vslam_examples  tmp   var
# ./run_video_slam \
    -v /vocab/orb_vocab.fbow \
    -m /dataset/aist_living_lab_1/video.mp4 \
    -c /stella_vslam/example/aist/equirectangular.yaml \
    --frame-skip 3 \
    --no-sleep \
    --map-db-out map.msg

SocketViewer版stella_vslamのビルドと動作確認

Dockerイメージのビルド

stella_vslam本体

$ cd ~/VSLAM/Docker
$ git clone --recursive https://github.com/stella-cv/stella_vslam.git
$ cd stella_vslam
$ docker build -t stella_vslam-socket -f Dockerfile.socket . --build-arg NUM_THREADS=`expr $(nproc) - 1`

socket-viewer

$ cd ~/VSLAM/Docker
$ git clone --recursive https://github.com/stella-cv/socket_viewer.git
$ cd socket_viewer
$ docker build -t stella_vslam-viewer .

Dockerコンテナの起動

socket-viewer

$ docker run --rm -it --name stella_vslam-viewer --net=host stella_vslam-viewer
WebSocket: listening on *:3000
HTTP server: listening on *:3001

先にsocket-viewerを起動し、ここで、Webブラウザからhttp://localhost:3001/へアクセスする。

stella_vslam本体

$ docker run --rm -it --name stella_vslam-socket --net=host \
    --volume ~/VSLAM/Docker/stella_vslam/vocab:/vocab:ro \
    --volume ~/VSLAM/Docker/stella_vslam/dataset:/dataset:ro \
    stella_vslam-socket
root@0b8206d0372f:/stella_vslam_examples/build# 

SocketViewer版stella_vslamでは、上の両方のdocker runコマンドに--net=hostオプションを付加してコンテナを起動するようにする。

Dockerコンテナでの動作確認

  • コンテナ stella_vslam-socket
# At the /stella_vslam_examples/build directory
# pwd
/stella_vslam_examples/build
# ls /
bin   dataset  etc   lib    lib64  ...   ...   ...   stella_vslam           sys   usr   vocab
...   ...   ...   ...   ...  ...   ...   ...   ...   stella_vslam_examples  tmp   var
# ./run_video_slam \
    -v /vocab/orb_vocab.fbow \
    -m /dataset/aist_living_lab_1/video.mp4 \
    -c /stella_vslam/example/aist/equirectangular.yaml \
    --frame-skip 3 \
    --no-sleep \
    --map-db-out map.msg \
    --viewer socket_publisher

stella_vslamプログラムが起動すると、Webブラウザのウィンドウに下のようなグラフィック描画画面が表示される。

Dockerを使えばプラットホーム環境に影響を与えることなく、プログラムのビルドを行えるのが良い。一度Dockerコンテナを作成してしまうと、動作確認だけが目的ならこちらの方が楽だろう。

ただし、小生は現在stella_vslamの動作解析や改造が主たる作業なので、いまはDockerを積極的に利用していない。元ソースや改造完成版ソースでのビルド確認、特定のデータセットでの動作確認などではDockerを利用している。また、上のsocket-viewerサーバーを稼働させるときもDockerを使っている。小生のメインPCはMacParallels Desktopを利用しているが、適時これとDockerを使い分けている。サーバー系の開発では、仮想マシンやDockerコンテナを利用すると作業効率が上がる。

【ROS】libuvc_camera | フォーマット指定でのカメラ映像取得

前記事でlibuvc_cameraパッケージを利用してROS上でのUVCカメラの映像取得を行ったが、そこでは、カメラに対する映像フォーマットなどのパラメータ指定はしていなかった。

blog.ketus-ix.work

前記事の操作によって取得されるカメラ映像の解像度サイズは640x480ピクセルになっている。また、カメラ映像取得動作中に、rostopic hz /image_rawコマンドによってフレームレートを調べてみると、下のように15fps程度の転送速度しか出ていないことが判る。

$ rostopic hz /image_raw
subscribed to [/image_raw]
average rate: 15.036
    min: 0.059s max: 0.070s std dev: 0.00279s window: 14
average rate: 14.959
    min: 0.059s max: 0.070s std dev: 0.00224s window: 29
average rate: 14.967
    min: 0.059s max: 0.070s std dev: 0.00211s window: 44
average rate: 14.958
    min: 0.059s max: 0.070s std dev: 0.00199s window: 59
average rate: 14.950
    min: 0.059s max: 0.070s std dev: 0.00193s window: 74
....    ....
....    ....

この結果は、libuvc_cameraによるデフォルトのカメラ映像設定パラメータがこれらの値に固定されているからだと思われる。

そこで、libuvc_cameraによるROS上でのフォーマットパラメータしてカメラ映像を取得することを試みてみた。

UVCカメラ映像フォーマットの調査

対象のUVCカメラが対応している映像フォーマット情報を調べる必要がある。

まずは、lsusbコマンドによって、対象カメラのidProductidVendorの値(ID 046d:081bの箇所)を特定する。

$ lsusb
Bus 001 Device 003: ID 046d:081b Logitech, Inc. Webcam C310
Bus 001 Device 002: ID 203a:fffc  
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 003: ID 203a:fff9  
Bus 004 Device 002: ID 203a:fff9  
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

その後、デバイスファイル/dev/video*の存在を確認する。

$ ls /dev/video*
/dev/video0  /dev/video1  /dev/video2  /dev/video3  /dev/video4  /dev/video5

そして、すべてのデバイスファイルに対してudevadm info --name=/dev/videoX --attribute-walkコマンドを順番に実行する。

$ udevadm info --name=/dev/video4 --attribute-walk

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:1d.7/usb1/1-11/1-11:1.0/video4linux/video4':
    KERNEL=="video4"
    SUBSYSTEM=="video4linux"
    DRIVER==""
    ATTR{dev_debug}=="0"
    ATTR{index}=="0"
    ATTR{name}=="UVC Camera (046d:081b)"

  looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb1/1-11/1-11:1.0':
    KERNELS=="1-11:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="uvcvideo"
    ATTRS{authorized}=="1"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceClass}=="0e"
    ATTRS{bInterfaceNumber}=="00"
    ATTRS{bInterfaceProtocol}=="00"
    ATTRS{bInterfaceSubClass}=="01"
    ATTRS{bNumEndpoints}=="01"
    ATTRS{iad_bFirstInterface}=="00"
    ATTRS{iad_bFunctionClass}=="0e"
    ATTRS{iad_bFunctionProtocol}=="00"
    ATTRS{iad_bFunctionSubClass}=="03"
    ATTRS{iad_bInterfaceCount}=="02"
    ATTRS{supports_autosuspend}=="1"

  looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb1/1-11':
    KERNELS=="1-11"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{authorized}=="1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bDeviceClass}=="ef"
    ATTRS{bDeviceProtocol}=="01"
    ATTRS{bDeviceSubClass}=="02"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{bMaxPower}=="500mA"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bNumInterfaces}==" 4"
    ATTRS{bcdDevice}=="0012"
    ATTRS{bmAttributes}=="80"
    ATTRS{busnum}=="1"
    ATTRS{configuration}==""
    ATTRS{devnum}=="3"
    ATTRS{devpath}=="11"
    ATTRS{idProduct}=="081b"
    ATTRS{idVendor}=="046d"
    ATTRS{ltm_capable}=="no"
    ATTRS{maxchild}=="0"
    ATTRS{quirks}=="0x2"
    ATTRS{removable}=="unknown"
    ATTRS{rx_lanes}=="1"
    ATTRS{serial}=="F941C3A0"
    ATTRS{speed}=="480"
    ATTRS{tx_lanes}=="1"
    ATTRS{urbnum}=="5068"
    ATTRS{version}==" 2.00"

  looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb1':
    KERNELS=="usb1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{authorized}=="1"
    ATTRS{authorized_default}=="1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bDeviceClass}=="09"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{bMaxPower}=="0mA"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bcdDevice}=="0504"
    ATTRS{bmAttributes}=="e0"
    ATTRS{busnum}=="1"
    ATTRS{configuration}==""
    ATTRS{devnum}=="1"
    ATTRS{devpath}=="0"
    ATTRS{idProduct}=="0002"
    ATTRS{idVendor}=="1d6b"
    ATTRS{interface_authorized_default}=="1"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="Linux 5.4.0-150-generic ehci_hcd"
    ATTRS{maxchild}=="15"
    ATTRS{product}=="EHCI Host Controller"
    ATTRS{quirks}=="0x0"
    ATTRS{removable}=="unknown"
    ATTRS{rx_lanes}=="1"
    ATTRS{serial}=="0000:00:1d.7"
    ATTRS{speed}=="480"
    ATTRS{tx_lanes}=="1"
    ATTRS{urbnum}=="67"
    ATTRS{version}==" 2.00"

  looking at parent device '/devices/pci0000:00/0000:00:1d.7':
    KERNELS=="0000:00:1d.7"
    SUBSYSTEMS=="pci"
    DRIVERS=="ehci-pci"
    ATTRS{ari_enabled}=="0"
    ATTRS{broken_parity_status}=="0"
    ATTRS{class}=="0x0c0320"
    ATTRS{companion}==""
    ATTRS{consistent_dma_mask_bits}=="32"
    ATTRS{d3cold_allowed}=="0"
    ATTRS{device}=="0x265c"
    ATTRS{dma_mask_bits}=="32"
    ATTRS{driver_override}=="(null)"
    ATTRS{enable}=="1"
    ATTRS{irq}=="19"
    ATTRS{local_cpulist}=="0-3"
    ATTRS{local_cpus}=="0000000f"
    ATTRS{msi_bus}=="1"
    ATTRS{numa_node}=="-1"
    ATTRS{revision}=="0x02"
    ATTRS{subsystem_device}=="0x0400"
    ATTRS{subsystem_vendor}=="0x1ab8"
    ATTRS{uframe_periodic_max}=="100"
    ATTRS{vendor}=="0x8086"

  looking at parent device '/devices/pci0000:00':
    KERNELS=="pci0000:00"
    SUBSYSTEMS==""
    DRIVERS==""
  

上の出力情報中のATTRS{idProduct}=="081b"ATTRS{idVendor}=="046d"から、この/dev/video4が対象カメラのデバイスファイルであることが判る。

バイスファイルが特定できたら、v4l2-ctl --list-formats-ext -d /dev/videoXコマンドによって対象カメラの対応フォーマット情報を知ることができる。

$ v4l2-ctl --list-formats-ext -d /dev/video4
ioctl: VIDIOC_ENUM_FMT
    Index       : 0
    Type        : Video Capture
    Pixel Format: 'YUYV'
    Name        : YUYV 4:2:2
        Size: Discrete 640x480
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 160x120
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 176x144
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 320x176
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 320x240
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 352x288
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 432x240
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 544x288
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 640x360
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 752x416
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 800x448
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 800x600
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 864x480
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 960x544
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 960x720
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 1024x576
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 1184x656
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 1280x720
            Interval: Discrete 0.133s (7.500 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 1280x960
            Interval: Discrete 0.133s (7.500 fps)
            Interval: Discrete 0.200s (5.000 fps)

    Index       : 1
    Type        : Video Capture
    Pixel Format: 'MJPG' (compressed)
    Name        : Motion-JPEG
        Size: Discrete 640x480
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 160x120
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 176x144
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 320x176
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 320x240
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 352x288
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 432x240
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 544x288
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 640x360
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 752x416
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 800x448
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 800x600
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 864x480
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 960x544
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 960x720
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 1024x576
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 1184x656
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 1280x720
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 1280x960
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.067s (15.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
  

映像フォーマット指定でのUVCカメラ映像取得

ROSワークスペースを利用して、UVCカメラ映像取得処理をバッケージ化してしまおう。

$ cd ~/catkin_ws/src
$ catkin create pkg my_camera --catkin-deps libuvc_camera
$ mkdir my_camera/launch
$ vi my_camera/launch/uvc_camera.launch

以下のようなXML形式ファイルを作成し、この中でカメラの映像取得パラメータを指定する。

  • ~/catkin_ws/src/my_camera/launch/uvc_camera.launch
<?xml version="1.0"?>
<launch>
  <node pkg="libuvc_camera" type="camera_node" name="my_camera">
    <param name="width" value="1280"/>
    <param name="height" value="720"/>
    <param name="frame_rate" value="30"/>
    <param name="video_mode" value="mjpeg"/>
  </node>
  <node name="image_view" pkg="image_view" type="image_view" >
    <remap from="image" to="/image_raw"/>
  </node>
</launch>
  • width : 出力映像イメージの横幅ピクセルサイズ
  • height : 出力映像イメージの縦幅ピクセルサイズ
  • frame_rate : 出力映像イメージのフレームレート
  • video_mode : 出力映像イメージのフォーマット

これらの値は前述のカメラの対応フォーマット出力情報のいずれかのモードの値と一致していなければならない。

上の操作が済んだら、下のコマンドを実行すればバッケージを作成できる。

$ catkin build

パッケージが作成できたら、下のコマンドを実行すれば、そのプログラムを起動できる。

$ source ~/catkin_ws/devel/setup.bash
$ roslaunch my_camera uvc_camera.launch

本プログラムが起動すると、下のような1280x720サイズのカメラ映像ウィンドウが表示される。

本プログラムの動作中に、再度rostopic hz /image_rawコマンドによってフレームレートを調べると、今度は30fps程度の転送速度が出ていることが確認できる。

$ rostopic hz /image_raw
subscribed to [/image_raw]
average rate: 30.283
    min: 0.025s max: 0.043s std dev: 0.00374s window: 28
average rate: 30.015
    min: 0.025s max: 0.043s std dev: 0.00288s window: 58
average rate: 29.927
    min: 0.025s max: 0.043s std dev: 0.00272s window: 88
average rate: 29.881
    min: 0.025s max: 0.043s std dev: 0.00263s window: 118
average rate: 29.880
    min: 0.025s max: 0.043s std dev: 0.00250s window: 148
....    ....
....    ....

【参照サイト】

qiita.com

msadowski.github.io

【ROS】libuvc_cameraによるUVCカメラ映像取得

ROSの研究に本格的に取り組み始めたが、その主目的はカメラ映像や自己位置推定の動画をモバイルデバイスへ配信する環境を作ることだ。

この目的への取っかかりとして、およびROSの動作を理解するために、最初にROS上でのUVCカメラの映像取得を試みてみた。

ググって調べてみると、UVCカメラ用のROSパッケージはlibuvc_cameraとusb_camの2つの種類があるようだ。

$ apt search ros-melodic
....    ....

ros-melodic-libuvc-camera/bionic,now 0.0.10-1bionic.20221025.192649 amd64
  USB Video Class camera driver

....    ....

ros-melodic-usb-cam/bionic 0.3.7-1bionic.20230322.235857 amd64
  A ROS Driver for V4L USB Cameras

....    ....

libuvc_cameraはカメラの映像フォーマットの変更に対応しているが、usb_camの方は対応していないらしい。ただし、上の最終更新日から判るが、よりメンテナンスが行われているのはusb_camのようだ。

取りあえず、libuvc_cameraの方を使ってROS上でのUVCカメラの映像取得をやってみた。

wiki.ros.org

libuvc_cameraパッケージのインストール

$ sudo apt install ros-melodic-libuvc-camera

UVCカメラ映像取得のROSコマンド

ros-melodic-libuvc-cameraパッケージをインストールした後、3つのターミナル画面を開いて、それぞれで以下のコマンドを順番に実行する。

  • ターミナル 1
$ roscore
  • ターミナル 2
$ rosrun libuvc_camera camera_node
  • ターミナル 3
$ rosrun image_view image_view image:=/image_raw

ただし、ターミナル 2 のコマンドを実行すると、下のようなエラーが表示される。

$ rosrun libuvc_camera camera_node
[ INFO] [1693820844.531653508]: Opening camera with vendor=0x0, product=0x0, serial="", index=0
[ERROR] [1693820844.532629997]: Permission denied opening /dev/bus/usb/001/004

このエラーは、デフォルト状態ではUVCカメラ・デバイスに対する書き込み権限がないために起きている。

UVCカメラのアクセス権限設定

上記の障害を回避するには、まず以下のコマンドによって対象カメラ・デバイスがどれなのかを調べる。

$ ls -l /dev/bus/usb/00*
/dev/bus/usb/001:
total 0
crw-rw-r-- 1 root root 189, 0  9月  6 10:36 001
crw-rw-r-- 1 root root 189, 1  9月  6 10:36 002
crw-rw-r-- 1 root root 189, 3  9月  6 10:58 004

/dev/bus/usb/002:
total 0
crw-rw-r-- 1 root root 189, 128  9月  6 10:36 001

/dev/bus/usb/003:
total 0
crw-rw-r-- 1 root root 189, 256  9月  6 10:36 001

/dev/bus/usb/004:
total 0
crw-rw-r-- 1 root root 189, 384  9月  6 10:36 001
crw-rw-r-- 1 root root 189, 385  9月  6 10:36 002
crw-rw-r-- 1 root root 189, 387  9月  6 10:58 004
$ lsusb
Bus 001 Device 004: ID 046d:081b Logitech, Inc. Webcam C310
Bus 001 Device 002: ID 203a:fffc  
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 004: ID 203a:fff9  
Bus 004 Device 002: ID 203a:fff9  
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

上の2つのコマンドの出力情報から、対象カメラ・デバイスLogitech, Inc. Webcam C310であることが判る。

そこで、下のコマンドを実行して、対象カメラのデバイスファイルに対する書き込み権限を与えてやれば、この障害を回避することができる。

$ sudo chmod a+w /dev/bus/usb/001/004
$ ls -l /dev/bus/usb/001/004
crw-rw-rw- 1 root root 189, 3  9月  6 10:58 004

ただし、対象カメラを一旦切断して再度接続すると、そのデバイスファイルのアクセス権限は元に戻ってしまうので、また本障害に遭遇することになる。

恒常的にこの障害を回避するには、下のようなudevルール・ファイルを作成しておけば良い。

$ sudo vi /etc/udev/rules.d/99-uvc.rules
SUBSYSTEMS=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="081b", MODE="0666"

上の記述内のATTRS{idVendor}==ATTRS{idProduct}==に設定する値は、lsusbコマンドによって表示される対象デバイスID 046d:081bから決める。

このファイルを作成した後、対象カメラを一旦切断して再度接続してやれば、udevルールが適用されてカメラ・デバイスへの書き込み権限が設定される。

UVCカメラ映像取得ROSコマンドの再実行

この状態で、ターミナル 2のコマンドを再度起動すると、今度は正常に実行される。

  • ターミナル 2
$ rosrun libuvc_camera camera_node
[ INFO] [1693964283.867968187]: Opening camera with vendor=0x0, product=0x0, serial="", index=0
unsupported descriptor subtype VS_COLORFORMAT
unsupported descriptor subtype VS_COLORFORMAT
attempt to claim already-claimed interface 1
[ WARN] [1693964284.586118108]: Unable to set scanning_mode to 0
[ WARN] [1693964284.597984745]: Unable to set exposure_absolute to 1
[ WARN] [1693964284.600210747]: Unable to set auto_focus to 1
[ WARN] [1693964284.602504735]: Unable to set focus_absolute to 0
[ WARN] [1693964284.607419215]: Unable to set iris_absolute to 0
[ WARN] [1693964284.610973004]: Unable to set pantilt to 0, 0
Controls callback. class: 17, event: 0, selector: 4, attr: 0, data_len: 4
Controls callback. class: 18, event: 0, selector: 4, attr: 0, data_len: 2
Controls callback. class: 18, event: 0, selector: 10, attr: 0, data_len: 2
Controls callback. class: 17, event: 0, selector: 4, attr: 0, data_len: 4
Controls callback. class: 18, event: 0, selector: 4, attr: 0, data_len: 2
Controls callback. class: 18, event: 0, selector: 10, attr: 0, data_len: 2
[ INFO] [1693964284.913010078]: using default calibration URL
[ INFO] [1693964284.913113367]: camera calibration URL: file:///home/LOGINUSER/.ros/camera_info/camera.yaml
[ INFO] [1693964284.913218996]: Unable to open camera calibration file [/home/LOGINUSER/.ros/camera_info/camera.yaml]
[ WARN] [1693964284.913246013]: Camera calibration file /home/LOGINUSER/.ros/camera_info/camera.yaml not found.
Controls callback. class: 18, event: 0, selector: 10, attr: 0, data_len: 2
Controls callback. class: 18, event: 0, selector: 4, attr: 0, data_len: 2
Controls callback. class: 18, event: 0, selector: 10, attr: 0, data_len: 2
Controls callback. class: 17, event: 0, selector: 4, attr: 0, data_len: 4
Controls callback. class: 17, event: 0, selector: 4, attr: 0, data_len: 4
....    ....
....    ....

そして、ターミナル 3のコマンドを実行すると、カメラの映像が取得表示される。

  • ターミナル 3
$ rosrun image_view image_view image:=/image_raw
[ INFO] [1693965375.488105036]: Initializing nodelet with 4 worker threads.
[ INFO] [1693965375.601250199]: Using transport "raw"

【参照サイト】

qiita.com