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

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

stella_vslamのUbuntu 20.04でのビルド

本ブログの最初の記事でstella_vslam = OpenVSLAMのビルドについて書いたが、あれから1年経って、現在のstella_vslamの状況がどうなっているのか知りたくなった。

github.com

stella_vslamは産業技術総合研究所のOpenVSLAMのコミュニティフォークだが、いまではこちらの方が活動が活発で、OpenVSLAMと言えば、現在ではstella_vslamのことを指すと言っても良い。stella_vslamはオリジナルのOpenVSLAMに追加されている機能があったり変更されている部分も多く、いまも更新が続いている。自己位置推定(SLAM)を始めるなら、このstella_vslamの研究から取りかかるのがベストな選択だと言える。

以前の記事ではUbuntu 18.04でビルドを行ったが、stella_vslamドキュメントサイトの情報が更新されており、いまの最新版ではUbuntu 20.04でのビルド手順が記載されている。それで、stella_vslamのビルドと動作確認をもう一度やりなおしてみることにした。

stella-cv.readthedocs.io

以降はstella_vslamドキュメントサイトに記載されている内容とほとんど同じだが、一部変更や追加部分もある。

stella_vslamのビルド依存パッケージの導入

共通の依存パッケージ

$ sudo apt install -y build-essential pkg-config cmake git wget curl unzip

g2oの依存パッケージ

$ sudo apt install -y libatlas-base-dev libsuitesparse-dev

OpenCVの依存パッケージ

$ sudo apt install -y libgtk-3-dev ffmpeg libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev libtbb-dev

Eigenの依存パッケージ

$ sudo apt install -y gfortran

backward-cppの依存パッケージ

$ sudo apt install -y binutils-dev

その他の依存パッケージ

$ sudo apt install -y libyaml-cpp-dev libgflags-dev sqlite3 libsqlite3-dev

PangolinViewerの依存パッケージ

$ sudo apt install -y libglew-dev

stella_vslamとリンクされるライブラリのビルドとインストール

Eigen

$ mkdir -p ~/VSLAM/Depended_Builds
$ cd ~/VSLAM/Depended_Builds
$ wget -q https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.tar.bz2
$ tar xjf eigen-3.3.7.tar.bz2
$ cd eigen-3.3.7
$ mkdir build && cd build
$ cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr/local \
    ..
$ make -j
$ sudo make install

OpenCV

$ cd ~/VSLAM/Depended_Builds
$ wget -q https://github.com/opencv/opencv/archive/4.6.0.zip
$ unzip -q 4.6.0.zip
# Download aruco module (optional)
$ wget -q https://github.com/opencv/opencv_contrib/archive/refs/tags/4.6.0.zip -O opencv_contrib-4.6.0.zip
$ unzip -q opencv_contrib-4.6.0.zip
$ mkdir opencv_extra && cd opencv_extra
$ ln -s ../opencv_contrib-4.6.0/modules/aruco .
$ cd ../opencv-4.6.0
$ mkdir build && cd build
$ cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr/local \
    -DBUILD_DOCS=OFF \
    -DBUILD_EXAMPLES=OFF \
    -DBUILD_JASPER=OFF \
    -DBUILD_OPENEXR=OFF \
    -DBUILD_PERF_TESTS=OFF \
    -DBUILD_TESTS=OFF \
    -DBUILD_PROTOBUF=OFF \
    -DBUILD_opencv_apps=OFF \
    -DBUILD_opencv_dnn=OFF \
    -DBUILD_opencv_ml=OFF \
    -DBUILD_opencv_python_bindings_generator=OFF \
    -DENABLE_CXX11=ON \
    -DENABLE_FAST_MATH=ON \
    -DWITH_EIGEN=ON \
    -DWITH_FFMPEG=ON \
    -DWITH_TBB=ON \
    -DWITH_OPENMP=ON \
    -DOPENCV_EXTRA_MODULES_PATH=../../opencv_extra \
    ..
$ make -j4
$ sudo make install
$ sudo ldconfig

stella_vslamドキュメントサイトではOpenCV 4.5.5を利用しているが、これを4.6.0に変えた。

また、コマンドsudo ldconfigを追加した。これを実行しておかないと、サンプルプログラムの起動時に下のようなエラーになる場合がある。

$ ./run_kitti_slam -h
./run_kitti_slam: error while loading shared libraries: libopencv_highgui.so.405: cannot open shared object file: No such file or directory

FBoW

$ cd ~/VSLAM/Depended_Builds
$ git clone https://github.com/stella-cv/FBoW.git
$ cd FBoW
$ mkdir build && cd build
$ cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr/local \
    ..
$ make -j4
$ sudo make install

g2o

$ cd ~/VSLAM/Depended_Builds
$ git clone https://github.com/RainerKuemmerle/g2o.git
$ cd g2o
$ git checkout 20230223_git
$ mkdir build && cd build
$ cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr/local \
    -DBUILD_SHARED_LIBS=ON \
    -DBUILD_UNITTESTS=OFF \
    -DG2O_USE_CHOLMOD=OFF \
    -DG2O_USE_CSPARSE=ON \
    -DG2O_USE_OPENGL=OFF \
    -DG2O_USE_OPENMP=OFF \
    -DG2O_BUILD_APPS=OFF \
    -DG2O_BUILD_EXAMPLES=OFF \
    -DG2O_BUILD_LINKED_APPS=OFF \
    ..
$ make -j4
$ sudo make install

backward-cpp

$ cd  ~/VSLAM/Depended_Builds
$ git clone https://github.com/bombela/backward-cpp.git
$ cd backward-cpp
$ git checkout 5ffb2c879ebdbea3bdb8477c671e32b1c984beaa
$ mkdir build && cd build
$ cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr/local \
    ..
$ make -j4
$ sudo make install

PangolinViewer

$ cd ~/VSLAM/Depended_Builds
$ git clone https://github.com/stevenlovegrove/Pangolin.git
$ cd Pangolin
$ git checkout eab3d3449a33a042b1ee7225e1b8b593b1b21e3e
$ mkdir build && cd build
$ cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr/local \
    -DBUILD_EXAMPLES=OFF \
    -DBUILD_PANGOLIN_DEPTHSENSE=OFF \
    -DBUILD_PANGOLIN_FFMPEG=OFF \
    -DBUILD_PANGOLIN_LIBDC1394=OFF \
    -DBUILD_PANGOLIN_LIBJPEG=OFF \
    -DBUILD_PANGOLIN_LIBOPENEXR=OFF \
    -DBUILD_PANGOLIN_LIBPNG=OFF \
    -DBUILD_PANGOLIN_LIBTIFF=OFF \
    -DBUILD_PANGOLIN_LIBUVC=OFF \
    -DBUILD_PANGOLIN_LZ4=OFF \
    -DBUILD_PANGOLIN_OPENNI=OFF \
    -DBUILD_PANGOLIN_OPENNI2=OFF \
    -DBUILD_PANGOLIN_PLEORA=OFF \
    -DBUILD_PANGOLIN_PYTHON=OFF \
    -DBUILD_PANGOLIN_TELICAM=OFF \
    -DBUILD_PANGOLIN_UVC_MEDIAFOUNDATION=OFF \
    -DBUILD_PANGOLIN_V4L=OFF \
    -DBUILD_PANGOLIN_ZSTD=OFF \
    ..
$ make -j4
$ sudo make install

stella_vslamのビルド

stella_vslam本体

$ mkdir -p ~/VSLAM/Builds
$ cd ~/VSLAM/Builds
$ git clone --recursive https://github.com/stella-cv/stella_vslam.git
$ cd stella_vslam
$ mkdir build && cd build
$ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
$ make -j4
$ sudo make install

PangolinViewer対応部

$ cd ~/VSLAM/Builds
$ git clone -b 0.0.1 --recursive https://github.com/stella-cv/pangolin_viewer.git
$ cd pangolin_viewer
$ mkdir build && cd build
$ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
$ make -j4
$ sudo make install

SocketViewer対応部〔使用する場合のみビルド〕

$ cd ~/VSLAM/Builds
$ git clone https://github.com/shinsumicco/socket.io-client-cpp.git
$ cd socket.io-client-cpp
$ git submodule init
$ git submodule update
$ mkdir build && cd build
$ cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr/local \
    -DBUILD_UNIT_TESTS=OFF \
    ..
$ make -j4
$ sudo make install
$ sudo apt install -y libprotobuf-dev protobuf-compiler
$ cd ~/VSLAM/Builds
$ git clone -b 0.0.1 --recursive https://github.com/stella-cv/socket_publisher.git
$ cd socket_publisher
$ mkdir build && cd build
$ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
$ make -j4
$ sudo make install

サンプルプログラム

$ cd ~/VSLAM/Builds
$ git clone -b 0.0.1 --recursive https://github.com/stella-cv/stella_vslam_examples.git
$ cd stella_vslam_examples
$ mkdir build && cd build
$ cmake \
    -DCMAKE_BUILD_TYPE=RelWithDebInfo \
    -DUSE_STACK_TRACE_LOGGER=ON \
    ..
$ make -j

stella_vslamの動作確認

サンプルデータセットの入手

下のサイトにstella_vslam用のサンプルデータセットが置いてあるので、ここから入手できる。

stella-cv.readthedocs.io

上に置いてあるのは、元は産総研(AIST)のOpenVSLAMサイトに在ったものではないだろうか。産総研の許可を得てstella_vslam側へ移したのだろう。

以前の記事を書いたときは上のリンクサイトは存在していなくて、産総研のオリジナルのデータセットを入手する方法が判らなかった。

公開データセットの入手

公開データセットを利用してstella_vslamの動作確認を行うこともできる。各データセットの配布元は以下のサイトになる。

KITTI Odometry Dataset

www.cvlibs.net

EuRoC MAV dataset

http://robotics.ethz.ch/~asl-datasets/ijrr_euroc_mav_dataset/

projects.asl.ethz.ch

TUM RGBD Dataset

https://vision.in.tum.de/rgbd/dataset/freiburg3/rgbd_dataset_freiburg3_calibration_rgb_depth.tgz

vision.in.tum.de

以前の記事では、これらの中からKITTI Odometry Datasetを利用したが、このデータセットKITTIのサイトでアカウント登録をしないとダウンロードできない。

サンプルデータセットによる動作確認

stella-cv.readthedocs.io

# at the build directory of stella_vslam_examples
$ pwd
~/VSLAM/Builds/stella_vslam_examples/build
$ ls ../..
pangolin_viewer  socket_publisher  socket_viewer  stella_vslam  stella_vslam_examples

# ORB vocabulary ファイルのダウンロード
$ curl -sL "https://github.com/stella-cv/FBoW_orb_vocab/raw/main/orb_vocab.fbow" -o orb_vocab.fbow

# dataset ディレクトリの作成
$ mkdir ../dataset

# 1つ目のサンプルデータセットのダウンロード
$ FILE_ID="1d8kADKWBptEqTF7jEVhKatBEdN7g0ikY"
$ curl -sc /tmp/cookie "https://drive.google.com/uc?export=download&id=${FILE_ID}" > /dev/null
$ CODE="$(awk '/_warning_/ {print $NF}' /tmp/cookie)"
$ curl -sLb /tmp/cookie "https://drive.google.com/uc?export=download&confirm=${CODE}&id=${FILE_ID}" -o ../dataset/aist_living_lab_1.zip
$ unzip ../dataset/aist_living_lab_1.zip -d ../dataset

# 2つ目のサンプルデータセットのダウンロード
$ FILE_ID="1TVf2D2QvMZPHsFoTb7HNxbXclPoFMGLX"
$ curl -sc /tmp/cookie "https://drive.google.com/uc?export=download&id=${FILE_ID}" > /dev/null
$ CODE="$(awk '/_warning_/ {print $NF}' /tmp/cookie)"
$ curl -sLb /tmp/cookie "https://drive.google.com/uc?export=download&confirm=${CODE}&id=${FILE_ID}" -o ../dataset/aist_living_lab_2.zip
$ unzip ../dataset/aist_living_lab_2.zip -d ../dataset

# tracking and mapping実行指定でvslamを起動
$ ./run_video_slam \
    -v ./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
# [Terminate] ボタン押下でビューア終了
# カレントディレクトリに map.msg が生成されている

# localization実行指定でvslamを起動
$ ./run_video_slam \
    --disable-mapping \
    -v ./orb_vocab.fbow \
    -m ../dataset/aist_living_lab_2/video.mp4 \
    -c ../../stella_vslam/example/aist/equirectangular.yaml \
    --frame-skip 3 \
    --no-sleep \
    --map-db-in map.msg
# localization with temporal mapping based odometry実行指定でvslamを起動
$ ./run_video_slam \
    --temporal-mapping \
    -v ./orb_vocab.fbow \
    -m ../dataset/aist_living_lab_2/video.mp4 \
    -c ../../stella_vslam/example/aist/equirectangular.yaml \
    --frame-skip 3 \
    --no-sleep \
    --map-db-in map.msg

下がサンプルデータセットを使ってstella_vslamの動作確認を行っている様子。

www.youtube.com

公開データセットによる動作確認

stella-cv.readthedocs.io

KITTI Odometry Dataset

# at the build directory of stella_vslam_examples
$ pwd
~/VSLAM/Builds/stella_vslam_examples/build
$ ls ../..
pangolin_viewer  socket_publisher  socket_viewer  stella_vslam  stella_vslam_examples

# KITTI Odometry dataset (grayscale, 22 GB) のダウンロード
$ wget -q URL_HTTPS_KITTI_DATASET/data_odometry_gray.zip -P ../dataset
$ unzip -q data_odometry_gray.zip -d ../dataset

# monocular SLAM with sequence 00
$ ./run_kitti_slam \
    -v ./orb_vocab.fbow \
    -d ../dataset/dataset/sequences/00/ \
    -c ../../stella_vslam/example/kitti/KITTI_mono_00-02.yaml
# stereo SLAM with sequence 05
$ ./run_kitti_slam \
    -v ./orb_vocab.fbow \
    -d ../dataset/dataset/sequences/05/ \
    -c ../../stella_vslam/example/kitti/KITTI_stereo_04-12.yaml

EuRoC MAV Dataset

# at the build directory of stella_vslam_example
$ pwd
~/VSLAM/Builds/stella_vslam_examples/build
$ ls ../..
pangolin_viewer  socket_publisher  socket_viewer  stella_vslam  stella_vslam_examples

# EuRoC MAV dataset のダウンロード
$ wget -q \
    http://robotics.ethz.ch/~asl-datasets/ijrr_euroc_mav_dataset/machine_hall/MH_03_medium/MH_03_medium.zip \
    -P ../dataset
$ unzip -q ../dataset/MH_03_medium.zip -d ../dataset

# monocular SLAM with any EuRoC sequence
$ ./run_euroc_slam \
    -v ./orb_vocab.fbow \
    -d ../dataset/mav0/ \
    -c ../../stella_vslam/example/euroc/EuRoC_mono.yaml
# stereo SLAM with any EuRoC sequence
$ ./run_euroc_slam \
    -v ./orb_vocab.fbow \
    -d ../dataset/mav0/ \
    -c ../../stella_vslam/example/euroc/EuRoC_stereo.yaml

TUM RGBD Dataset

# at the build directory of stella_vslam_examples
$ pwd
~/VSLAM/Builds/stella_vslam_examples/build
$ ls ../..
pangolin_viewer  socket_publisher  socket_viewer  stella_vslam  stella_vslam_examples

# TUM RGBD dataset のダウンロード
$ wget -q \
    https://vision.in.tum.de/rgbd/dataset/freiburg3/rgbd_dataset_freiburg3_calibration_rgb_depth.tgz \
    -P ../dataset
$ tar xzf ../dataset/rgbd_dataset_freiburg3_calibration_rgb_depth.tgz.zip \
    -C ../dataset

# TUM RGBD dataset の前処理
$ cd ../dataset/rgbd_dataset_freiburg3_calibration_rgb_depth
$ wget -q \
    https://svncvpr.in.tum.de/cvpr-ros-pkg/trunk/rgbd_benchmark/rgbd_benchmark_tools/src/rgbd_benchmark_tools/associate.py
$ python associate.py rgb.txt depth.txt
$ cd ../../build

# Tracking and Mapping

# monocular SLAM with rgbd_dataset_freiburg3_calibration_rgb_depth
$ ./run_tum_rgbd_slam \
    -v ./orb_vocab.fbow \
    -d ../dataset/rgbd_dataset_freiburg3_calibration_rgb_depth/ \
    -c ../../stella_vslam/example/tum_rgbd/TUM_RGBD_mono_3.yaml \
    --no-sleep \
    --auto-term \
    --map-db-out fr3_slam_mono.msg

# RGBD SLAM with rgbd_dataset_freiburg3_calibration_rgb_depth
$ ./run_tum_rgbd_slam \
    -v ./orb_vocab.fbow \
    -d ../dataset/rgbd_dataset_freiburg3_calibration_rgb_depth/ \
    -c ../../stella_vslam/example/tum_rgbd/TUM_RGBD_rgbd_3.yaml \
    --no-sleep \
    --auto-term \
    --map-db-out fr3_slam_rgbd.msg

# Localization

# monocular localization with rgbd_dataset_freiburg3_calibration_rgb_depth
$ ./run_tum_rgbd_slam --disable-mapping \
    -v ./orb_vocab.fbow \
    -d ../dataset/rgbd_dataset_freiburg3_calibration_rgb_depth/ \
    -c ../../stella_vslam/example/tum_rgbd/TUM_RGBD_mono_3.yaml \
    --no-sleep \
    --auto-term \
    --map-db-in fr3_slam_mono.msg

# RGBD SLAM with rgbd_dataset_freiburg3_calibration_rgb_depth
$ ./run_tum_rgbd_slam --disable-mapping \
    -v ./orb_vocab.fbow \
    -d ../dataset/rgbd_dataset_freiburg3_calibration_rgb_depth/ \
    -c ../../stella_vslam/example/tum_rgbd/TUM_RGBD_rgbd_3.yaml \
    --no-sleep \
    --auto-term \
    --map-db-in fr3_slam_rgbd.msg

# Localization with temporal mapping based odometry

# monocular localization with rgbd_dataset_freiburg3_calibration_rgb_depth
$ ./run_tum_rgbd_slam --temporal-mapping \
    -v ./orb_vocab.fbow \
    -d ../dataset/rgbd_dataset_freiburg3_calibration_rgb_depth/ \
    -c ../../stella_vslam/example/tum_rgbd/TUM_RGBD_mono_3.yaml \
    --no-sleep \
    --auto-term \
    --map-db-in fr3_slam_mono.msg

# RGBD SLAM with rgbd_dataset_freiburg3_calibration_rgb_depth
$ ./run_tum_rgbd_slam --temporal-mapping \
    -v ./orb_vocab.fbow \
    -d ../dataset/rgbd_dataset_freiburg3_calibration_rgb_depth/ \
    -c ../../stella_vslam/example/tum_rgbd/TUM_RGBD_rgbd_3.yaml \
    --no-sleep \
    --auto-term \
    --map-db-in fr3_slam_rgbd.msg

公開データセットを使ってstella_vslamの動作確認を行っている様子。

www.youtube.com

www.youtube.com

www.youtube.com

SocketViewerによる動作確認

$ git clone --recursive https://github.com/stella-cv/socket_viewer.git
$ cd socket_viewer
$ ls
app.js  Dockerfile  LICENSE  package.json  public  README.md  views
$ nodenv install 12.22.12
$ nodenv local 12.22.12
$ node -v
v12.22.12
$ npm install
....    ....
added 96 packages from 61 contributors and audited 96 packages in 4.292s

8 packages are looking for funding
  run `npm fund` for details

found 1 critical severity vulnerability
  run `npm audit fix` to fix them, or `npm audit` for details
$ ls
app.js  Dockerfile  LICENSE  node_modules  package.json  package-lock.json  public  README.md  views
$ node app.js
WebSocket: listening on *:3000
HTTP server: listening on *:3001
  

※上記は、Node.js環境としてnodenvを用いることを前提としている。

# at the build directory of stella_vslam_examples
$ pwd
~/VSLAM/builds/stella_vslam_examples/build
$ ls ../..
pangolin_viewer  socket_publisher  socket_viewer  stella_vslam  stella_vslam_examples

$ ./run_kitti_slam \
    -v ./orb_vocab.fbow \
    -d ../dataset/dataset/sequences/00/ \
    -c ../../stella_vslam/example/kitti/KITTI_mono_00-02.yaml \
    --viewer socket_publisher

ここで、ブラウザを起動してhttp://localhost:3001/へアクセスすると下のような画面になる。

前回stella_vslamを扱ったときは、パラメータを調整していくつかの動画への適応具合を観たり、ソースコードを眺めてプログラム実装の概要を理解することなどを行った。この程度の浅めの研究で終わったが、今回実務仕事として本格的に自己位置推定に取り組むことになった。

これから、stella_vslamの動作原理、プログラムソース実装、深い利用方法、改造方法の調査などを行っていく。また、stella_vslam以外にもSLAM実装は存在しているので、他のプログラムの調査研究も始めるつもりだ。

(まだ記事を書いていないが)いままで360度映像がメインの研究テーマだったが、これと並行して、自己位置推定の研究にものめり込んでいくことになるだろう。

【Python】Open3Dの試しインストール

OpenCVやML/DLで物体認識をやっているときに、認識した物体の形状をポリゴンや3D点群データとして扱うことがある。そのためPoint Cloud LibraryやOpen3Dの存在は知っていたが、あるきっかけで、Open3Dについてもっと深く知りたいという欲求が生まれたので、最近Open3Dを研究対象テーマに加えた。

github.com

本格的な研究開発を始める前の取りかかりとして、Open3Dのインストールと動作確認をやってみた。

Open3Dのインストール

まずは、Open3D用のPython仮想環境を作った。

% mkdir open3d_test
% cd open3d_test
% pyenv local 3.7
% poetry init
....    ....
Compatible Python versions [^3.11]:  >=3.7,<3.11
% poetry install
% poetry shell
% python -V
Python 3.10.9

私のPython環境はanyenv + pyenv + Poetryだが、pyenvによって3.6〜3.11のPythonを使い分けている。Open3Dのサイトで対象のPythonバージョンを調べてみると3.7〜3.10だったので、poetryで作る仮想環境のPythonバージョンは上のようにした。

そして、その仮想環境にOpen3Dをインストールした。

% poetry add open3d

初回のインストール時は少し時間がかかる。Open3Dは多くのパッケージに依存しているようだ。Open3Dと一緒に追加されたパッケージを確認してみると、下のようになっていた。

% pip list
Package              Version
-------------------- --------
ansi2html            1.8.0
attrs                23.1.0
certifi              2023.5.7
charset-normalizer   3.2.0
click                8.1.4
ConfigArgParse       1.5.5
dash                 2.11.1
dash-core-components 2.0.0
dash-html-components 2.0.0
dash-table           5.0.0
fastjsonschema       2.17.1
Flask                2.2.5
idna                 3.4
itsdangerous         2.1.2
Jinja2               3.1.2
jsonschema           4.17.3
jupyter_core         4.12.0
MarkupSafe           2.1.3
nbformat             5.7.0
nest-asyncio         1.5.6
numpy                1.21.6
open3d               0.17.0
packaging            23.1
pip                  23.1.2
plotly               5.15.0
pyrsistent           0.19.3
requests             2.31.0
retrying             1.3.4
setuptools           67.8.0
six                  1.16.0
tenacity             8.2.2
traitlets            5.9.0
typing_extensions    4.7.1
urllib3              2.0.3
Werkzeug             2.2.3
wheel                0.40.0

続いて、Open3Dの動作環境の確認を行った。

% python -c "import open3d as o3d"
....    ....
ModuleNotFoundError: No module named 'sklearn'
$ poetry add scikit-learn
Configuration file exists at /Users/yuhri/Library/Preferences/pypoetry, reusing this directory.

[tool.poetry]
Consider moving TOML configuration files to /Users/yuhri/Library/Application Support/pypoetry, as support for the legacy directory will be removed in an upcoming release.
Using version ^1.3.0 for scikit-learn

Updating dependencies
Resolving dependencies... (0.2s)

The current project's Python requirement (>=3.7,<3.11) is not compatible with some of the required packages Python requirement:
  - scikit-learn requires Python >=3.8, so it will not be satisfied for Python >=3.7,<3.8

Because no versions of scikit-learn match >1.3.0,<2.0.0
 and scikit-learn (1.3.0) requires Python >=3.8, scikit-learn is forbidden.
So, because open3d-test depends on scikit-learn (^1.3.0), version solving failed.

  • Check your dependencies Python requirement: The Python requirement can be specified via the `python` or `markers` properties

    For scikit-learn, a possible solution would be to set the `python` property to ">=3.8,<3.11"

    https://python-poetry.org/docs/dependency-specification/#python-restricted-dependencies,
    https://python-poetry.org/docs/dependency-specification/#using-environment-markers

% vi pyproject.toml
....    ....
[tool.poetry.dependencies]
- python = ">=3.7,<3.11"
+ python = ">=3.8,<3.11"
$ poetry add scikit-learn

最初にモジュールsklearnが足りないと言ってくるが、これはscikit-learnのことなので、それをインストールしようとすると、上のような警告が表示される。現時点で最新版のscikit-learnPython 3.8〜3.10でしか使えないらしい。

それで、pyproject.toml内の依存Pythonバージョン定義を上のように書き換えて、scikit-learnをインストールした。

さらに続けて、Open3Dの依存パッケージを追加していった。

% python -c "import open3d as o3d"
....    ....
ModuleNotFoundError: No module named 'yaml'
% poetry add pyyaml
$ python -c "import open3d as o3d"
....    ....
ModuleNotFoundError: No module named 'addict'
% poetry add addict
% python -c "import open3d as o3d"
....    ....
ModuleNotFoundError: No module named 'PIL'
% poetry add pillow
% python -c "import open3d as o3d"
....    ....
ModuleNotFoundError: No module named 'pandas'
% poetry add pandas
% python -c "import open3d as o3d"
....    ....
ModuleNotFoundError: No module named 'tqdm'
% poetry add tqdm
% python -c "import open3d as o3d"

コマンドpython -c "import open3d as o3d"で警告が表示されなければ、依存パッケージはすべて追加できて動作環境が整ったことになるようだ。Open3Dは上記のパッケージにも依存しているらしいが、それならインストール時に一緒に追加してくれれば良いのに思うのだが。

Open3Dの動作確認

これでやっと動作環境が整ったようだ。最後に、GitHubからOpen3Dのソースを取得して、その中のPythonサンプルプログラムを動かしてみた。

% git clone https://github.com/isl-org/Open3D.git
% python Open3D/examples/python/visualization/demo_scene.py

上の画像をマウスでドラッグすると3次元方向に動かせる。こういうのを見ると、やっぱり3Dは面白いなぁと思う。

じつは、コンピュータグラフィックスにすごく興味が湧いてきて、いまUnityも使い始めている。Open3Dの研究を始めたのは、これをiOSAndroidで動かしてみたいと思ったからだ。

Open3D-iOSというパッケージが存在しており、すでにiOSではOpen3Dが使えるらしい。それなら、これのAndroid版を作ってみたい。さらに、UnityでもOpen3Dを使えるようにしたい。iOSAndroid両方でUnity上でOpen3Dが使えるようにすることをこの研究の最終目的としている。

【参照リンク】

self-development.info

libuvcをMacでビルドしてみる

仕事上の事情から、いまUVCカメラ(USB接続のいわゆるWebカメラ)の仕様と制御方法について研究している。その一環として、libusbとlibuvcというライブラリにフォーカスして調査を行っている。

普段使っているMacでlibuvcをビルドして動かすことをやってみた。

libuvcのビルド

プラットフォームはmacOS Ventura、ビルド環境はHomebrewを使っている。

最初にlibuvcのビルドに必要な依存パッケージをインストールした。

% brew install cmake pkg-config
% brew install libusb jpeg-turbo

実際の操作順は逆で、最初にlibuvcのソースを取得して、それをビルドしながら上のパッケージが必要なことが判ったのだが。

続いて、libuvcのソースを取得した。

% git clone https://github.com/libuvc/libuvc.git

そして、ビルドを行う。

% cd libuvc
% mkdir build
% cd build
% cmake ..
-- libusb-1.0 found using pkgconfig
-- Found JPEG: /usr/local/lib/libjpeg.dylib (found version "80")
-- Found JPEG library using standard module
CMake Warning (dev) at /usr/local/Cellar/cmake/3.26.4/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:438 (message):
  The package name passed to `find_package_handle_standard_args` (JPEG) does
  not match the name of the calling package (JpegPkg).  This can lead to
  problems in calling code that expects `find_package` result variables
  (e.g., `_FOUND`) to follow a certain pattern.
Call Stack (most recent call first):
  cmake/FindJpegPkg.cmake:58 (find_package_handle_standard_args)
  CMakeLists.txt:45 (find_package)
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Found JPEG: /usr/local/lib/libjpeg.dylib
-- Building libuvc with JPEG support.
-- Configuring done (0.7s)
-- Generating done (0.1s)
-- Build files have been written to: /Users/LOGIN_USER/Builds/libuvc/build
% make
[  4%] Building C object CMakeFiles/uvc.dir/src/ctrl.c.o
[  9%] Building C object CMakeFiles/uvc.dir/src/ctrl-gen.c.o
[ 13%] Building C object CMakeFiles/uvc.dir/src/device.c.o
[ 18%] Building C object CMakeFiles/uvc.dir/src/diag.c.o
[ 22%] Building C object CMakeFiles/uvc.dir/src/frame.c.o
[ 27%] Building C object CMakeFiles/uvc.dir/src/init.c.o
[ 31%] Building C object CMakeFiles/uvc.dir/src/stream.c.o
[ 36%] Building C object CMakeFiles/uvc.dir/src/misc.c.o
[ 40%] Building C object CMakeFiles/uvc.dir/src/frame-mjpeg.c.o
[ 45%] Linking C shared library libuvc.dylib
[ 45%] Built target uvc
[ 50%] Building C object CMakeFiles/uvc_static.dir/src/ctrl.c.o
[ 54%] Building C object CMakeFiles/uvc_static.dir/src/ctrl-gen.c.o
[ 59%] Building C object CMakeFiles/uvc_static.dir/src/device.c.o
[ 63%] Building C object CMakeFiles/uvc_static.dir/src/diag.c.o
[ 68%] Building C object CMakeFiles/uvc_static.dir/src/frame.c.o
[ 72%] Building C object CMakeFiles/uvc_static.dir/src/init.c.o
[ 77%] Building C object CMakeFiles/uvc_static.dir/src/stream.c.o
[ 81%] Building C object CMakeFiles/uvc_static.dir/src/misc.c.o
[ 86%] Building C object CMakeFiles/uvc_static.dir/src/frame-mjpeg.c.o
[ 90%] Linking C static library libuvc.a
[ 90%] Built target uvc_static
[ 95%] Building C object CMakeFiles/example.dir/src/example.c.o
[100%] Linking C executable example
[100%] Built target example

libuvcの動作確認

ビルドしたlibuvcの動作確認として、UVCカメラを接続した状態で以下のコマンドを実行してみた。

% ./example
UVC initialized
Device found
uvc_open: Access denied (-3)
UVC exited

どうもrootユーザでやらないとダメみたいなので、sudo付きで実行してみたら下のような出力になって、これで動いているようだ。

% sudo ./example
Password:
UVC initialized
Device found
Device opened
DEVICE CONFIGURATION (1d6c:0103/AN20200825001) ---
Status: idle
VideoControl:
    bcdUVC: 0x0100
VideoStreaming(1):
    bEndpointAddress: 131
    Formats:
    MJPEGFormat(1)
          bits per pixel: 0
          GUID: 4d4a5047000000000000000000000000 (MJPG)
          default frame: 1
          aspect ratio: 0x0
          interlace flags: 00
          copy protect: 00
            FrameDescriptor(1)
              capabilities: 00
              size: 1920x1080
              bit rate: 18432000-55296000
              max frame size: 4147200
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(2)
              capabilities: 00
              size: 2560x1440
              bit rate: 18432000-55296000
              max frame size: 7372800
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(3)
              capabilities: 00
              size: 320x240
              bit rate: 18432000-55296000
              max frame size: 153600
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(4)
              capabilities: 00
              size: 640x360
              bit rate: 18432000-55296000
              max frame size: 460800
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(5)
              capabilities: 00
              size: 800x600
              bit rate: 18432000-55296000
              max frame size: 960000
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(6)
              capabilities: 00
              size: 960x720
              bit rate: 18432000-55296000
              max frame size: 1382400
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(7)
              capabilities: 00
              size: 1024x576
              bit rate: 18432000-55296000
              max frame size: 1179648
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(8)
              capabilities: 00
              size: 640x480
              bit rate: 18432000-55296000
              max frame size: 614400
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(9)
              capabilities: 00
              size: 1280x720
              bit rate: 18432000-55296000
              max frame size: 1843200
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(10)
              capabilities: 00
              size: 1920x1080
              bit rate: 18432000-55296000
              max frame size: 4147200
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(11)
              capabilities: 00
              size: 2560x1440
              bit rate: 18432000-55296000
              max frame size: 7372800
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(12)
              capabilities: 00
              size: 1920x1080
              bit rate: 18432000-55296000
              max frame size: 4147200
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
    FrameFormat(2)
          bits per pixel: 0
          GUID: 4832363400001000800000aa00389b71 (H264)
          default frame: 1
          aspect ratio: 0x0
          interlace flags: 00
          copy protect: 00
            FrameDescriptor(1)
              capabilities: 00
              size: 1920x1080
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(2)
              capabilities: 00
              size: 2560x1440
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(3)
              capabilities: 00
              size: 320x240
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(4)
              capabilities: 00
              size: 640x360
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(5)
              capabilities: 00
              size: 800x600
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(6)
              capabilities: 00
              size: 960x720
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(7)
              capabilities: 00
              size: 1024x576
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(8)
              capabilities: 00
              size: 640x480
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(9)
              capabilities: 00
              size: 1280x720
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(10)
              capabilities: 00
              size: 1920x1080
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(11)
              capabilities: 00
              size: 2560x1440
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(12)
              capabilities: 00
              size: 1920x1080
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
    UncompressedFormat(3)
          bits per pixel: 16
          GUID: 5955593200001000800000aa00389b71 (YUY2)
          default frame: 1
          aspect ratio: 0x0
          interlace flags: 00
          copy protect: 00
            FrameDescriptor(1)
              capabilities: 00
              size: 640x480
              bit rate: 18432000-55296000
              max frame size: 614400
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(2)
              capabilities: 00
              size: 1280x720
              bit rate: 18432000-55296000
              max frame size: 1843200
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
END DEVICE CONFIGURATION

First format: (MJPG) 1920x1080 30fps
bmHint: 0001
bFormatIndex: 1
bFrameIndex: 1
dwFrameInterval: 333333
wKeyFrameRate: 0
wPFrameRate: 0
wCompQuality: 0
wCompWindowSize: 0
wDelay: 0
dwMaxVideoFrameSize: 4147200
dwMaxPayloadTransferSize: 3060
bInterfaceNumber: 1
Streaming...
Enabling auto exposure ...
 ... enabled auto exposure
callback! frame_format = 7, width = 1920, height = 1080, length = 197981, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 219087, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 242720, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 263191, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 293221, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 341212, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 356177, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 352805, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 350672, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 350672, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 331834, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 330931, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 330550, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 329433, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 329433, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 308818, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 309529, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 310410, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 311284, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 311284, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 310782, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 310160, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 310327, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 309760, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 310405, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 310493, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 311158, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 310334, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 309190, ptr = 0x3039
callback! frame_format = 7, width = 1920, height = 1080, length = 308535, ptr = 0x3039

examplesrc/example.cというソースからビルドされる実行ファイルだが、src/test.cというサンプルプログラム・ソースもあって、こちらはOpenCVを利用してカメラ映像の表示を行っている。

以下のコマンドを実行すると、このsrc/test.cも一緒にビルドできる。

% brew install opencv@3
% cmake .. -DBUILD_TEST=true -DOpenCV_DIR=/usr/local/opt/opencv@3/share/OpenCV
% make

uvc_testというのがsrc/test.cからビルドされた実行ファイルだが、これを起動すると以下のようなメッセージが出力されてプログラムが停止してしまう。

% sudo ./uvc_test
UVC initialized
Device found
Device opened
DEVICE CONFIGURATION (1d6c:0103/AN20200825001) ---
Status: idle
VideoControl:
    bcdUVC: 0x0100
VideoStreaming(1):
    bEndpointAddress: 131
    Formats:
    MJPEGFormat(1)
          bits per pixel: 0
          GUID: 4d4a5047000000000000000000000000 (MJPG)
          default frame: 1
          aspect ratio: 0x0
          interlace flags: 00
          copy protect: 00
            FrameDescriptor(1)
              capabilities: 00
              size: 1920x1080
              bit rate: 18432000-55296000
              max frame size: 4147200
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(2)
              capabilities: 00
              size: 2560x1440
              bit rate: 18432000-55296000
              max frame size: 7372800
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(3)
              capabilities: 00
              size: 320x240
              bit rate: 18432000-55296000
              max frame size: 153600
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(4)
              capabilities: 00
              size: 640x360
              bit rate: 18432000-55296000
              max frame size: 460800
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(5)
              capabilities: 00
              size: 800x600
              bit rate: 18432000-55296000
              max frame size: 960000
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(6)
              capabilities: 00
              size: 960x720
              bit rate: 18432000-55296000
              max frame size: 1382400
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(7)
              capabilities: 00
              size: 1024x576
              bit rate: 18432000-55296000
              max frame size: 1179648
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(8)
              capabilities: 00
              size: 640x480
              bit rate: 18432000-55296000
              max frame size: 614400
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(9)
              capabilities: 00
              size: 1280x720
              bit rate: 18432000-55296000
              max frame size: 1843200
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(10)
              capabilities: 00
              size: 1920x1080
              bit rate: 18432000-55296000
              max frame size: 4147200
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(11)
              capabilities: 00
              size: 2560x1440
              bit rate: 18432000-55296000
              max frame size: 7372800
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(12)
              capabilities: 00
              size: 1920x1080
              bit rate: 18432000-55296000
              max frame size: 4147200
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
    FrameFormat(2)
          bits per pixel: 0
          GUID: 4832363400001000800000aa00389b71 (H264)
          default frame: 1
          aspect ratio: 0x0
          interlace flags: 00
          copy protect: 00
            FrameDescriptor(1)
              capabilities: 00
              size: 1920x1080
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(2)
              capabilities: 00
              size: 2560x1440
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(3)
              capabilities: 00
              size: 320x240
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(4)
              capabilities: 00
              size: 640x360
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(5)
              capabilities: 00
              size: 800x600
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(6)
              capabilities: 00
              size: 960x720
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(7)
              capabilities: 00
              size: 1024x576
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(8)
              capabilities: 00
              size: 640x480
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(9)
              capabilities: 00
              size: 1280x720
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(10)
              capabilities: 00
              size: 1920x1080
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(11)
              capabilities: 00
              size: 2560x1440
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(12)
              capabilities: 00
              size: 1920x1080
              bit rate: 18432000-55296000
              max frame size: 0
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
    UncompressedFormat(3)
          bits per pixel: 16
          GUID: 5955593200001000800000aa00389b71 (YUY2)
          default frame: 1
          aspect ratio: 0x0
          interlace flags: 00
          copy protect: 00
            FrameDescriptor(1)
              capabilities: 00
              size: 640x480
              bit rate: 18432000-55296000
              max frame size: 614400
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
            FrameDescriptor(2)
              capabilities: 00
              size: 1280x720
              bit rate: 18432000-55296000
              max frame size: 1843200
              default interval: 1/30
              interval[0]: 1/30
              interval[1]: 1/25
END DEVICE CONFIGURATION
bmHint: 0001
bFormatIndex: 3
bFrameIndex: 1
dwFrameInterval: 333333
wKeyFrameRate: 0
wPFrameRate: 0
wCompQuality: 0
wCompWindowSize: 0
wDelay: 0
dwMaxVideoFrameSize: 614400
dwMaxPayloadTransferSize: 3060
bInterfaceNumber: 1
Streaming for 10 seconds...
set_ae_mode: Pipe (-9)
set_exp_abs: Pipe (-9)
callback! length = 3048, ptr = 12345
2023-07-10 10:40:13.082 uvc_test[62190:4733991] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'NSWindow drag regions should only be invalidated on the Main Thread!'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007ff816f7043b __exceptionPreprocess + 242
    1   libobjc.A.dylib                     0x00007ff816abfe25 objc_exception_throw + 48
    2   CoreFoundation                      0x00007ff816f985d6 _CFBundleGetValueForInfoKey + 0
    3   AppKit                              0x00007ff81a03f161 -[NSWindow(NSWindow_Theme) _postWindowNeedsToResetDragMarginsUnlessPostingDisabled] + 307
    4   AppKit                              0x00007ff81a02bf4f -[NSWindow _initContent:styleMask:backing:defer:contentView:] + 1247
    5   AppKit                              0x00007ff81a02ba69 -[NSWindow initWithContentRect:styleMask:backing:defer:] + 42
    6   AppKit                              0x00007ff81a2f9ea2 -[NSWindow initWithContentRect:styleMask:backing:defer:screen:] + 50
    7   libopencv_highgui.3.4.16.dylib      0x0000000107384261 cvNamedWindow + 344
    8   uvc_test                            0x00000001072b7ac0 cb + 192
    9   libuvc.0.0.7.dylib                  0x000000010736b59f _uvc_user_caller + 127
    10  libsystem_pthread.dylib             0x00007ff816e1d259 _pthread_start + 125
    11  libsystem_pthread.dylib             0x00007ff816e18c7b thread_start + 15
)
libc++abi: terminating with uncaught exception of type NSException
zsh: abort      sudo ./uvc_test

この例外エラーは、メインスレッドの外からUIを叩こうとすると起きるものらしい。

src/test.cのソース内に以下のような記述があって、cvShowImageというOpenCVの関数を呼び出したときに起きているようだ。

void cb(uvc_frame_t *frame, void *ptr) {
  ....    ....

  printf("callback! length = %u, ptr = %d\n", frame->data_bytes, (int) ptr);

  ....    ....
  ....    ....

  cvImg = cvCreateImageHeader(
      cvSize(bgr->width, bgr->height),
      IPL_DEPTH_8U,
      3);

  cvSetData(cvImg, bgr->data, bgr->width * 3); 

  cvNamedWindow("Test", CV_WINDOW_AUTOSIZE);
  cvShowImage("Test", cvImg);
  cvWaitKey(10);

  cvReleaseImageHeader(&cvImg);

  uvc_free_frame(bgr);
}

int main(int argc, char **argv) {
  ....    ....
  ....    ....

  res = uvc_init(&ctx, NULL);

  if (res < 0) {
    uvc_perror(res, "uvc_init");
    return res;
  }

  puts("UVC initialized");

  ....    ....
  ....    ....
  ....    ....
  ....    ....

        res = uvc_start_streaming(devh, &ctrl, cb, 12345, 0);

        if (res < 0) {
          uvc_perror(res, "start_streaming");
        } else {
          puts("Streaming for 10 seconds...");
          ....    ....
          }
          sleep(10);
          uvc_stop_streaming(devh);
          puts("Done streaming.");
        }

  ....    ....
  ....    ....

  uvc_exit(ctx);
  puts("UVC exited");

  return 0;
}

Ubuntuでもlibuvcのビルドをやってみたが、Ubuntuではuvc_testは問題なく動作してカメラ映像が表示されることが確認できている。つまり、上記の現象はmacOS固有の障害ということになる。

SwiftだとDispatchQueue.main.syncという関数があって、これを使ってメインスレッド側でUI処理を行うようにすれば解決できるらしい。src/test.cC言語記述でpthreadを使っているが、この場合、同じ方法をどうやって実現すれば良いのか判らなかった。

じつは、上記と同じ内容の作業を大分前にHigh Sierra上で実施済みだったのだが、今回MacのOSをVenturaにアップグレードしたので、それで本作業をもう一度やりなおして記事にした。

ちなみに、この研究の目的は、UVCカメラの映像取得・制御をネットワーク経由でできる環境を作ることだ。このような環境をLinuxMacWindowsのすべてで(欲を言えば、AndroidiOSでも)実現することを最終目標として取り組んでいる。

Microsoft Azureで仮想マシンを作成してみる [2]

前記事に続いて、Azureで作成した仮想マシンへリモート接続する環境を構築していく。

SSHによる仮想マシンへの接続

最初にAzureで作成した仮想マシンIPアドレスを知る必要があるが、その方法は前記事に書いた。

当然ながら、以降の操作を行うには、先にAzureポータルサイト仮想マシンを起動しておく必要がある。

なお、本記事では、仮想マシン・テンプレートとしてUbuntu Server 20.04を選択したことを前提として説明していく。

仮想マシンSSH経由で接続するには、下のコマンドを使う。

$ ssh -i ~/.ssh/id_rsa azureuser@VM_IP_ADDRESS

Azureポータルサイトでの仮想マシン作成時に、ssh-keygenコマンドによって生成された~/.ssh/id_rsa.pubの内容を公開キーとして指定したなら、デフォルトでは秘密キーは~/.ssh/id_rsaに格納されているはずだ。上のコマンドでは、このファイルを指定してSSHクライアントにより仮想マシンへの接続を試みている。

SSHクライアントで仮想マシンへ接続すると、以下のようなメッセージが表示されてログインできる。

Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.15.0-1041-azure x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon Jul  2 03:01:48 UTC 2023

  System load:  0.08              Processes:             138
  Usage of /:   5.2% of 28.89GB   Users logged in:       0
  Memory usage: 4%                IPv4 address for eth0: 10.0.0.4
  Swap usage:   0%

Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status



The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

To run a command as administrator (user "root"), use "sudo ".
See "man sudo_root" for details.

ssh-keygenコマンドによるSSHキー組の作成時にパスフレーズを設定した場合は、それをパスワードとして入力することを求められるので、正しいパスフレーズを入力すれば仮想マシンにログインできる。

仮想マシンへの接続ログイン時にパスフレーズ入力を省略したい場合は、ローカル側で以下のコマンドを実行すれば良い。

$ eval `ssh-agent`
$ ssh-add ~/.ssh/id_rda

Macの場合、ssh-addコマンドを下のように変える。

% ssh-add --apple-use-keychain ~/.ssh/id_rda

毎回ssh-keygenコマンドに上記のオプションを指定するのが面倒なら、以下のような内容の~/.ssh/configを作成しておくと良い。

```bash:~/.ssh/config Host VM_HOST_NAME HostName VM_IP_ADDRESS Port 22 User azureuser UseKeychain yes IdentityFile ~/.ssh/id_rsa IdentitiesOnly yes TCPKeepAlive yes ServerAliveInterval 60 ServerAliveCountMax 5

  
このファイルを作成しておけば、下のコマンドによって仮想マシンへ接続できるようになる。
  

$ ssh VM_HOST_NAME

  
# リモートデスクトップによる仮想マシンへの接続

リモートデスクトップを使ってAzureの仮想マシンへ接続したい場合は、仮想マシン側のRDP用受信ポートを開放しておく必要がある。  
  
Azureポータルサイトのホーム画面 > [Virtual Macines] > 目的の仮想マシン > [ネットワーク]の画面でそれができる。この画面の[ 受信ポートの規則を追加する ]を押すと、下のような画面になる。  

[f:id:Vedfolnir:20230702115409p:plain]

この画面の **[サービス]** メニューから **[RDP]** を選んで、[ 追加 ]を押せば、仮想マシンへRDP用受信ポートを追加できる。  
  
Ubuntu ServerなどのCLIベースの仮想マシン・テンプレートを選択した場合は、仮想マシン上にGUIデスクトップは存在しないので、それを先にインストールしておく必要がある。  

Linux用のGUIデスクトップはいくつか種類があるが、UbuntuデフォルトのGNOMEは描画処理が重くて、リモートデスクトップでの利用には適していないと思う。GNOMEの代わりにXfceやMATEを利用することを薦める。あえてGNOMEを利用したい場合は、下のリンクを参照してほしい。  

[https://kogelog.com/2020/05/12/20200512-01/:embed:cite]

XfceあるいはMATEを利用する場合は、以下のコマンドをSSH接続中の仮想マシン上で実行することでインストールできる。  

- Xfce

<pre style="background-color:#1f1f1f;"><code style="color: #ffffff;">$ sudo apt update
$ sudo apt install -y xubuntu-desktop
$ sudo apt install -y xfce4 xfce4-goodies
</code></pre>

- MATE

<pre style="background-color:#1f1f1f;"><code style="color: #ffffff;">$ sudo apt update
$ sudo apt install -y ubuntu-mate-desktop
</code></pre>

初めて仮想マシンへGUIデスクトップをインストールした場合は、下のようなディスプレイマネージャの選択を求める画面が表示されるが、この画面ではどちらを選んでも問題ない。  

[f:id:Vedfolnir:20230702125501p:plain]

リモートデスクトップを使ってAzureの仮想マシンへ接続したい場合は、仮想マシン側にRDPサーバーをインストールして稼働状態にしておく必要がある。以下のコマンドによってそれを行える。  
  
<pre style="background-color:#1f1f1f"><code class="language-bash" style="color: #ffffff">$ sudo apt install -y  xrdp
$ sudo systemctl enable xrdp
$ sudo adduser xrdp ssl-cert
$ echo "xfce4-session" > ~/.xsession
$ sudo service xrdp restart
</code></pre>
  
上記は、GUIデスクトップとしてXfceを利用する場合で、MATEの場合は`echo`コマンドを下のように変える。  
  
<pre style="background-color:#1f1f1f"><code class="language-bash" style="color: #ffffff">$ echo "mate-session" > ~/.xsession
</code></pre>
  
RDP経由で仮想マシンへ接続する場合、SSH認証情報は利用できないので、通常の方法でログインするしかない。そのため、RDP接続用に最低でも一つのユーザーの通常ログイン用パスワードを設定する必要がある。以下のコマンドによって、仮想マシン上のユーザーのパスワードを設定しておく。  
  
<pre style="background-color:#1f1f1f"><code class="language-bash" style="color: #ffffff">$ sudo passwd azureuser
</code></pre>
  
以上の操作が済めば、仮想マシン側でのRDP経由接続の受け入れ準備が整う。

あとは、ローカル側からリモートデスクトップ・クライアントを使って仮想マシンへ接続することになる。UbuntuならRemmina、MacならMicrosoft Remote Desktopが有名どころだろう。  
  
RDPクライントから仮想マシンへ接続する場合は、その前に必ずローカル側で下のコマンドを実行しておく。  
  

$ ssh -L 3389:localhost:3389 azureuser@VM_HOST_NAME

  
このコマンドを実行すると、仮想マシンへSSH接続できるが、同時にローカル側でポート3389への通信をリモート(仮想マシン)側のポート3389へ転送する状態になる。この状態でRDPクライントから`localhost:3389`へ接続すれば、仮想マシンへRDP経由で接続できる。  
  
Microsoft Remote Desktopなら、下のような内容のリモート接続設定を作成して、それを使ってAzure仮想マシンへ接続する。  

[f:id:Vedfolnir:20230702220945p:plain]

RDPクライントで仮想マシンへ接続しようとすると、毎回下のような警告が表示されるが、この画面では [Continue] を押せば、仮想マシンへの接続が継続される。  

[f:id:Vedfolnir:20230702230314p:plain]

仮想マシンへ接続されると、下のようなログイン画面が表示されるので、上記で設定したユーザーのパスワードを入力すればログインできる。  

[f:id:Vedfolnir:20230702231336p:plain]

[f:id:Vedfolnir:20230702233824p:plain]

# X2Goによる仮想マシンへの接続

MicrosoftのAzureヘルプ情報サイトでは、xrdp/RDPよりもX2Goというリモートデスクトップの方が描画性能が高いので、X2Goを使うことが推薦されている。  

[https://learn.microsoft.com/ja-jp/azure/lab-services/how-to-enable-remote-desktop-linux:embed:cite]

実際に使ってみると、たしかにX2Goの方が描画が速いので、私もいまはX2Goを使っている。  
  
Ubuntuベースの仮想マシンにX2Goサーバーをインストールするには、下のコマンドを実行すれば良い。    
  

<pre style="background-color:#1f1f1f"><code class="language-bash" style="color: #ffffff">$ sudo apt install -y x2goserver x2goserver-xsession
</code></pre>
  
ローカル側にX2Goクライアントをインストールするには、Ubuntuなら下のコマンドによってできる。  
  

$ sudo apt install -y x2goclient

  
Macなら、下のサイトからインストーラをダウンロードできる。  

[https://wiki.x2go.org/doku.php/download:start:embed:cite]

なお、Macでx2goclientを使う場合は、先に<a href="https://www.xquartz.org/" target="_blank">XQuartz</a>をインストールしておく必要がある。

[f:id:Vedfolnir:20230703080829j:plain]

x2goclientのAzure仮想マシン用セッション設定は、下のような内容になる(**[Session name]** は任意の名前、**[Host]** には仮想マシンのIPアドレスを入力)。  

[f:id:Vedfolnir:20230703070653j:plain]

なお、仮想マシンへのリモートデスクトップ接続にX2Goだけを利用する場合、仮想マシン側の受信ポートは SSH (22) だけが使用されるので、RDP (3389) は削除しておいた方が良い。

# 補足情報

以下のサイトに、GNOME/xrdp、MATE/X2Go、Xfce/X2Goを一括でインストールできるシェルスクリプトが掲載されている。
このシェルスクリプトを利用すると、一度のコマンド実行でこれらの組み合わせをUbuntuベースのAzure仮想マシンへインストールできる。  

[https://github.com/Azure/LabServices/blob/main/TemplateManagement/PowerShell/LinuxGraphicalDesktopSetup/GNOME_MATE/ReadMe.md:embed:cite]

[https://github.com/Azure/LabServices/blob/main/TemplateManagement/PowerShell/LinuxGraphicalDesktopSetup/XFCE_Xubuntu/ReadMe.md:embed:cite]
  
  
**【参照リンク】**

[https://learn.microsoft.com/ja-jp/azure/virtual-machines/linux-vm-connect?tabs=Linux:embed:cite]

[https://www.hiroom2.com/ubuntu-2004-xrdp-xfce-ja/:embed:cite]

[https://www.hiroom2.com/ubuntu-2004-xrdp-mate-ja/:embed:cite]

[https://www.digitalocean.com/community/tutorials/how-to-set-up-a-remote-desktop-with-x2go-on-ubuntu-20-04:embed:cite]

[blog:g:4207112889945342980:banner]

Microsoft Azureで仮想マシンを作成してみる [1]

ある人に勧められたのがきっかけで、Microsoft Azureクラウドコンピューティング・サービスを使ってみた。

その経験を2つに分けて、本記事ではAzureで仮想マシンを作成するまでを、2回目の記事ではその仮想マシンをリモートで使える状態にするまでの作業過程を書く。

Azureクラウドコンピューティングの概要

Azureのクラウドコンピューティング・サービスを利用するには、先にMicrosoftアカウントを作成しておく必要があるが、こちらの説明は省略する。

本記事を書いている時点で、Azureにアカウント登録すると30日間有効な$200分の無料枠が提供される。先にこの無料枠を前課金分として取得しておかないと、新しい仮想マシンを作成することはできない。無料枠を取得すれば、その分の前課金範囲内であれば無償でAzureのクラウドコンピーティングを利用することができる。

Azureには色々な用途別に環境が設定済みの仮想マシン・テンプレートが用意されている。例えば「data science」で検索すると、下のように多くのテンプレートが存在する。

この中から選んで仮想マシンを作成すれば、基本的な開発・稼働環境構築作業の手間を省ける。また、OSだけを選んで仮想マシンを作成し、そこへ一から環境を構築していくこともできる。今回はこの方法を選ぶことにした。

Azureでの仮想マシン作成

無料枠を取得すると、サブスクリプションが作成されて、その分が前課金としてチャージされる。その状態では、Azureのホーム画面は下のようになる。

この画面から [リソースの作成] を選ぶと、下のような画面に変わる。

この画面のいずれかの仮想マシン種別の [作成] を選ぶと、仮想マシンの設定画面が表示される(または、前述の仮想マシン・テンプレート検索結果画面から一つを選んだ上で、その画面内の [作成] を押しても、下の仮想マシンの設定画面へ移ることができる)。

上が仮想マシンの設定開始画面だが、まず最初にリージョンを決めないといけない。リージョンとは仮想マシンが設置される場所で、リージョンによって選択可能なマシンサイズ(CPU種別やメモリ、ストレージサイズなどのマシン構成の種類)とそれらの料金が異なることがある。地理的に遠くのリージョンはアクセス速度が遅くなるので、取りあえず、無難な選択として一番近い [(Asia Pacific) Japan East]を選んでおいた。

次に決めるべき設定項目はマシンサイズだ。同種のマシンサイズでもリージョンによって料金が異なる場合があるので、あらかじめ各リージョンのマシンサイズの料金を調べておいて、その中から一番安価なものを選んでも良いだろう。ちなみに、Azureのマシンサイズ種類の詳細情報は下のサイトで確認することができる。

learn.microsoft.com

下のようにAzureのマシンサイズには多くの種類が存在するが、当然ながら高性能なものほど料金は高くなる。

これらの中から、サブスクリプション無料チャージ分$200に収まるものとして今回は「D4lds_v5」というものを選んでみた。

続いて、SSH公開キーの設定方法を決めないといけない。[新しいキーの組の生成] を選ぶと、Azureがキーの組を生成してくれて、公開キーを後で取得できるようだが、今回は自分で生成したキーを使うことにした。その場合は、自分で ssh-keygen コマンドによってSSHキーの組を作成し、[SSHキーのソース | 既存の公開キーを使用] を選んだ上で [SSH公開キー] 欄に公開キーの内容をコピべすれば良い。

上記の設定が済んだら、最後に [仮想マシンの名前] 欄に適当な名前を入力して、[ 次: ディスク > ] を押すと、[ディスク] の設定画面に移る。

ディスクの設定項目は特に変更する必要はないが、一つだけ [OSディスク | VMと共に削除] という項目には注意しなければならない。これをオフにすると、仮想マシンの停止後もディスクの実体が残ってしまうからだ(ここで言うディスクとは一時ストレージのことで、これは通常は仮想マシンの起動時に生成され停止時に削除される)。その場合、ディスクが存在するかぎり料金が発生することになる。これを避けるために、この項目は有効にしておいた方が良い。

これを言い換えると、[VMと共に削除] をオンした場合、毎回仮想マシンを起動した後で一時ディスクへデータなどをアップロードした上で利用し、使用後は必ず仮想マシンを停止するという使い方をしなければならないことを意味している。Azureのようなクラウドコンピューティング仮想マシンは通常はこのような使い方をすることになる。 [VMと共に削除] 設定が無効な仮想マシンを起動したままだと、その間ずっと仮想マシンと一時ディスクの両方の料金が発生してしまう。

ディスクの設定に続いて、次は [ネットワーク] の設定画面になるが、これらの項目は特に変更する必要はないだろう。

ただし、[受信ポートを選択][SSH (22)] が有効なっていることは確認しておいた方が良い。この設定項目は、SSHの他に [HTTP (80)][HTTPS (443)][RDP (3389)] も選べるようになっている。リモートディスクトップを使いたい場合は [RDP (3389)] をオンにすれば良い(仮想マシンを生成した後で受信ポート設定を変更追加することもできる)。

続いて、[管理] というが画面が表示されるが、これも特に変更する必要はないだろう。

ただし、[無料のBasicプランを有効にする] がオンになっていることは確認するべきだ。これがオフだと、既存のサブスクリプション無料分は使われずに、別に課金が発生してしまうからだ。

さらに続いて、[監視] というが画面が表示されるが、これも特に変更すべき設定項目はない。

またさらに続いて、[詳細]という画面が表示されるが、これも変更する必要はないだろう。

ただし、[パフォーマンス (NVMe) | NVMeを使用してリモートディスク ストレージ パフォーマンスを高める] は無効になっていることは確認するべきだ。これがオンだと、NVMeが一時ストレージとして使われ、追加料金が発生してしまうので。

またさらに続いて、[タグ] という画面が表示されるが、この画面に記載されている機能を利用するなら設定すれば良いだけで、特に必要がなれば変更しなくても良いだろう。

最後に、 [確認および作成] という画面にここまでの仮想マシンの設定内容が表示される。

この画面の内容を確認して [ 作成 ] を押すと、仮想マシンの作成(デプロイ)が始まる。仮想マシンの作成が成功すると、下のような画面が表示される。

この画面の [ リソースに移動 ] を押すと、作成された仮想マシンの概要情報が表示される。

この画面は、ホーム画面から [Virtual Machines] を選んで、作成済みの仮想マシンを選択することでも見ることができる。

次の記事に書く、仮想マシンをリモートで使用できる状態にする作業で使うことになるので、上の画面の [パブリックIPアドレス] の値を記憶しておく。

メーカー不明中華製IPカメラを調べる

ずいぶん長い間ご無沙汰してしまって、ずっと本ブログの更新ができないでいた。 個人的に仕事と生活の両方で大変な状況が続き、こちらに時間を割けない状態が続いていた。やっと仕事も生活も落ち着いて安定した暮らしがおくれるなったので、これからまた本ブログの更新を続けていく。

ちなみに、以前は本業で別の仕事しながら、副業でIT業をやっていた。いまはIT専業で働いている。 仕事と趣味活動の両方で新しい分野の研究も始めたので、これからブログ記事に書けるネタは増えていくだろう。


さて、本題の今回の記事の内容だが、本記事ではONVIFという仕様を取り上げる。 ja.wikipedia.org とある事情から、中華製IPカメラ(いわゆる監視カメラ)を借りられたので、こいつがどんな仕様なのか調べることになった。

WiFi Smart Camera」という名前がつけられたメーカー不明の奴だが、どうも中国の小メーカーが製造したボードが搭載されているようだ。

WiFi Smart Camera(メーカー不明中華製IPカメラ)

iCSeeという名前の純正アプリがGoogle PlayApp Storeに在って、これをAndrid/iOSスマホへインストールして使うことを前提としているようだ。

iCSeeアプリ(Android

カメラの初期設定は、iCSeeアプリでWiFiに接続した上で、アプリ側に表示されたQRコードをカメラ本体に読ませることでできるようになっている。

これは上手い方法だなぁと思う。ネットワークデバイス用アプリはこの方法を搭載すれば簡単に初期設定ができるので、ONVIF仕様とは別にこの方法がどういう仕組になっているのかも知りたくなった。

ONVIF Device Managerによる調査

最近のこの手のIPカメラは大抵ONVIF(Open Network Video Interface Forum)という仕様に準拠している。

www.onvif.org

ONVIF準拠カメラを操作することが目的のツールがいくつかあって、その中でもONVIF Device Managerというのが一番有名。

sourceforge.net

このツールを使って、対象IPカメラを調べてみた。

ONVIF Device Manager を起動すると、すぐに対象機が検出された。 やはりこいつもONVIF準拠カメラだということが判った。

ONVIF Device Manager〔対象機種〕

ただし、一概にONVIF準拠とは言っても、結構準拠程度に違いがあるらしい。 特に中華製IPカメラはONVIF準拠程度のバラツキが大きいと聞いたことがある。

このカメラもONVIF Device Managerの映像取得系コマンドは全滅で、下のようなエラーが表示されてしまう。

ONVIF Device Manager - Video streaming〔対象機種〕

VLCによる対象機カメラ映像の取得

ONVIF仕様を調べていくと、この仕様にはRTSP(Real Time Streaming Protocol)が含まれていて、デフォルト状態でONVIF準拠IPカメラはRTSPストリームが有効になっていることが解った。

ja.wikipedia.org

そこで、VLCを使って対象機からRTSP経由でカメラ映像の取得を試みてみた。

VLC RTSP設定〔対象機〕
VLC取得カメラ映像〔対象機〕

すると、問題なく対象機からカメラ映像を取得することができた。

対象機カメラのONVIF準拠程度

上記の情報だけでは不十分だと思ったので、他の調査方法がないかググってみた。そうしたら、ONVIF準拠情報を可能なかぎり詳しく調べることができるツールが見つかったので、このツールを使って本カメラの準拠程度を調べてみた。

その結果、本機のONVIF準拠には以下のような問題があることが判った。

  1. Media Configuration
    • 本系列コマンドによって取得されるURI記述に 'H265' != 'H264' という誤りあり
  2. Real Time Streaming
    • 本系列コマンドによって取得されるURI記述に 'H265' != 'H264' という誤りあり
  3. Real Time Streaming using Media2
    • 本系列コマンドによって取得されるURI記述に '=' != ':' という誤りあり
  4. PTZ using Media2 | Move Operation | PTZ CONTINUOUS MOVE USING MEDIA2 PROFILE
    • 本コマンドを実行すると、デバイスがリセットされてしまう → デバイスとの接続が切断される

上記の1〜3がONVIF Device Managerでカメラ映像が取得できない原因だろう。4は本機搭載ファームウェアのバグによる障害現象のようだ(iCSeeアプリでも、パン・チルト・ズーム操作をすると同現象が発生することがあるので)。

ここまで調べたのは、将来ONVIFカメラ用アプリ(Android, iOS, Windows, Mac版全部)を自作するつもりなので、現時点でONVIF仕様をある程度詳しく知っておきたかったから。

ONVIFカメラ用アプリを作り始めたら、その過程の情報を記事にしていこうと思っている。

【Homebrew】macOS High Sierraでの最新版LLVMのインストール

macOSのパッケージマネージャーとしてHomebrewを利用しています。GitHubなどから入手したプログラムソースをビルドしてMacで利用するには、Homebrewは必須のツールです。Homebrewがなければ、Macでのオープンソースを利用したソフトウェア開発はできないとも言えます。

ところが、現行のHomebrew(本記事執筆時点はバージョン3.6.1)ではmacOS 10.13 High Sierra はサポート対象外となっており、何かパッケージをインストールする度に次のような警告が表示されます。

Warning: You are using macOS 10.13.  
We (and Apple) do not provide support for this old version.  
You will encounter build failures with some formulae.  
Please create pull requests instead of asking for help on Homebrew's GitHub,  
Twitter or any other official channels. You are responsible for resolving  
any issues you experience while you are running this  
old version. 

Homebrewの多くフォーミュラはすでにBig Sur以降用に更新されているようで、一部のフォーミュラはそのままではHigh Sierraにインストールできなくなってしまっています。

事情があって、High Sierraを使い続けている人は結構多いのではないでしょうか。そういう私も2台のMacでまだHigh Sierraを使っています(マルチパーティションでBig Surと共存させたりしていますが)。一つの大きな理由として、NVIDIA GPUボードがHigh Sierraまでしか利用できないことがあります。NVIDIA GPUボード用ドライバがHigh Sierra対応版までしかリリースされておらず、macOS 10.14 Mojave以降ではCUDAや機械学習ディープラーニングのソフトウェア開発ができません。

HomebrewでHigh Sierraにインストールできないフォーミュラの一つとしてLLVMがというものがあります。Command Line Toolsにも入っているclangコンパイラを含んでいるLLVMの最新版ですが、この最新版LLVMにはclangも最新版バージョンが収納されています。この最新版LLVMをインストールできないことはHomebrewを利用したソフトウェア開発にとって大きな障害となります。多くのフォーミュアがこの最新バージョンのclangでビルドすることを前提として更新されており、それらは先に最新版LLVMがインストールされるからです。OpenCVやQtなどのメジャーなフォーミュラが最新版LLVMに依存しているため、High Sierraでは現行のHomebrewを使ってこれらをインストールすることができません。

GitHubから入手したいくつかのプログラムをビルドしようとして、この障害に何度か遭遇しましたが、試行錯誤しながら解決することができました。同じ問題によって困っている人は多いと思うので、その解決方法を本記事に書いておきます。

LLVMインストール時のエラー障害

High Sierra上でHomebrewを使って最新版LLVM(本記事執筆時点はバージョン14.0.6)をインストールしようとすると、以下のようなエラーが起きます。

% brew install llvm
... ...
==> Downloading https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.6/llvm-project-14.0.6.src.tar.xz
/usr/local/Homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/3.6.1\ \(Macintosh\;\ Intel\ Mac\ OS\ X\ 10.13.6\)\ curl/7.54.0 --header Accept-Language:\ en --retry 3 --location --silent --head --request GET https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.6/llvm-project-14.0.6.src.tar.xz
Already downloaded: /Users/yuhri/Library/Caches/Homebrew/downloads/ca2953276467b5dcc28485aa2b1afc3bcf32bbf84d5e0236f6284234afca2d8d--llvm-project-14.0.6.src.tar.xz
... ...
tar --extract --no-same-owner --file /Users/yuhri/Library/Caches/Homebrew/downloads/ca2953276467b5dcc28485aa2b1afc3bcf32bbf84d5e0236f6284234afca2d8d--llvm-project-14.0.6.src.tar.xz --directory /private/tmp/d20220915-7100-llrho7
cp -pR /private/tmp/d20220915-7100-llrho7/llvm-project-14.0.6.src/. /private/tmp/llvm-20220915-7100-9zovwz/llvm-project-14.0.6.src
==> cmake -G Unix Makefiles .. -DLLVM_ENABLE_PROJECTS=clang;clang-tools-extra;lld;lldb;mlir;polly -DLLVM_ENABLE_RUNTIMES=compiler-rt;libcxx;libcxxabi;libunwind;
==> cmake --build .
... ...
[ 80%] Built target lldELF
make: *** [all] Error 2

HomebrewはLLVMをソースからビルドしてインストールしようと試みますが、このエラーによってビルド処理が停止するため、LLVMのインストールは失敗してしまいます。

High Sierraに最新版LLVMをインスールする手順

上記のエラー障害を解決して、High Sierra上でHomebrewを使ってLLVMをインスールする手順を以降に説明します。

Xcode 10.1をインストールする

まずXcodeをHigh Sierraへインストールしておく必要があります。Xcode 10.1がHigh Sierraで利用可能な最終バージョンですが、これをApple Developerサイトからダウンロードした上で解凍し、Applicationsフォルダへコピーしてください。

Homebrewをインストール済みならCommand Line Toolsは単独でインストールされているはずで、フォーミュラのビルドは通常こちらを使って行われます。しかし、LLVMのインストールではXcodeに含まれる一部のツールがビルド処理で使われます。

すでにXcode 10.1をインストール済みなら、この操作を行う必要はありません。

なお、HombrewがXcodeの存在を認識しているかどうかは、以下のコマンドによって確認できます。

% brew config
HOMEBREW_VERSION: 3.6.1
ORIGIN: https://github.com/Homebrew/brew
HEAD: 6e2b162c4786e075323f038d46bfb566d91889e7
Last commit: 5 days ago
Core tap ORIGIN: https://github.com/Homebrew/homebrew-core
Core tap HEAD: 4d6529affa1851ffb992a33fe5641b0cd739c895
Core tap last commit: 2 hours ago
Core tap branch: master
HOMEBREW_PREFIX: /Users/yuhri/homebrew
HOMEBREW_REPOSITORY: /Users/yuhri/homebrew
HOMEBREW_CELLAR: /Users/yuhri/homebrew/Cellar
HOMEBREW_CASK_OPTS: []
HOMEBREW_DISPLAY: /private/tmp/com.apple.launchd.gBCDRKkzIz/org.xquartz:0
HOMEBREW_MAKE_JOBS: 24
Homebrew Ruby: 2.6.8 => /Users/yuhri/homebrew/Library/Homebrew/vendor/portable-ruby/2.6.8_1/bin/ruby
CPU: 24-core 64-bit westmere
Clang: 10.0.0 build 1000
Git: 2.17.2 => /Library/Developer/CommandLineTools/usr/bin/git
Curl: 7.54.0 => /usr/bin/curl
macOS: 10.13.6-x86_64
CLT: 10.1.0.0.1.1539992718
Xcode: 10.1

Xcodeがインストールされていないと、 "Xcode: N/A" と表示されます。

Command Line ToolsをXcode側へ切り替える

xcode-select コマンドを使って、Xcode側のCommand Line Toolsが使われるように変更します。

% xcode-select -p
/Library/Developer/CommandLineTools
$ sudo xcode-select -s /Applications/Xcode.app
Password:
% xcode-select -p
/Applications/Xcode.app/Contents/Developer

LLVMのインストールを”--debug”オプション付きで開始する

brew コマンドには --debug というオプションがありますが、このオプションを指定してLLVMのインストールを開始します。

% brew install --debug llvm

--debug オプションをつけると、エラーが起きた時点で、以下のようなメッセージが表示されてHomebrewのインストール処理が停止します。

... ...
[ 80%] Built target lldELF
make: *** [all] Error 2
/usr/local/Homebrew/Library/Homebrew/shims/shared/git --version
/usr/local/Homebrew/Library/Homebrew/shims/shared/curl --version
/usr/local/Homebrew/Library/Homebrew/ignorable.rb:29:in `block in raise'
BuildError: Failed executing: cmake --build .
1. raise
2. ignore
3. backtrace
4. irb
5. shell
Choose an action: 5
When you exit this shell, you will return to the menu.
%

この”Choose an action:” プロンプトに対して ”5”  を選ぶと、シェルプロンプトに復帰します。

LLVMのビルド・エラーの原因を解決する

シェルプロンプトになったら、以下のように作業ディレクトリを移動します。

% pwd
/private/tmp/llvm-20220915-7100-9zovwz/llvm-project-14.0.6.src
% cd llvm/build

そして、 HostInfoMacOSX.mm というファイルを以下のように編集します。

% vi ../../lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
--- ../../lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm.orig  2022-06-22 16:46:24.000000000 +0000
+++ ../../lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm    2022-09-15 13:18:17.000000000 +0000
@@ -228,7 +228,7 @@
     len = sizeof(is_64_bit_capable);
     ::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0);

-    if (cputype == CPU_TYPE_ARM64 && cpusubtype == CPU_SUBTYPE_ARM64E) {
+    if (cputype == CPU_TYPE_ARM64) {
       // The arm64e architecture is a preview. Pretend the host architecture
       // is arm64.
       cpusubtype = CPU_SUBTYPE_ARM64_ALL;

手動でLLVMのビルド処理を継続する

HostInfoMacOSX.mm の修正が終わったら、以下の一連のコマンドを順次実行していきます。

% cmake . -DLLVM_CREATE_XCODE_TOOLCHAIN=On
...   ...
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/llvm-20220915-7100-9zovwz/llvm-project-14.0.6.src/llvm/build
% cmake --build .
...   ...
[100%] Built target lldb-vscodex
/usr/local/Cellar/cmake/3.24.1/bin/cmake -E cmake_progress_start /tmp/llvm-20220915-7100-9zovwz/llvm-project-14.0.6.src/llvm/build/CMakeFiles 0
% cmake --build . --target install
...   ...
-- Installing: /usr/local/Cellar/llvm/14.0.6_1/lib/cmake/llvm/./FindSphinx.cmake
-- Installing: /usr/local/Cellar/llvm/14.0.6_1/lib/cmake/llvm/./FindGRPC.cmake
-- Installing: /usr/local/Cellar/llvm/14.0.6_1/lib/cmake/llvm/./TableGen.cmake
% cmake --build . --target install-xcode-toolchain

上記の最後のコマンドによるビルド処理が終わると、以下のようなメッセージが表示されます。

ここでの"Choose an action:"プロンプトでは、すべて "2" を選択します。

...   ...
-- Installing: /usr/local/Cellar/llvm/14.0.6_1/Toolchains/LLVM14.0.6.xctoolchain//usr/lib/cmake/llvm/./FindSphinx.cmake
-- Installing: /usr/local/Cellar/llvm/14.0.6_1/Toolchains/LLVM14.0.6.xctoolchain//usr/lib/cmake/llvm/./FindGRPC.cmake
-- Installing: /usr/local/Cellar/llvm/14.0.6_1/Toolchains/LLVM14.0.6.xctoolchain//usr/lib/cmake/llvm/./TableGen.cmake
Built target install-xcode-toolchain
/usr/local/Cellar/cmake/3.24.1/bin/cmake -E cmake_progress_start /tmp/llvm-20220915-7100-9zovwz/llvm-project-14.0.6.src/llvm/build/CMakeFiles 0
%
1. raise
2. ignore
3. backtrace
4. irb
5. shell
Choose an action: 2
==> cmake --build . --target install
Last 15 lines from /Users/yuhri/Library/Logs/Homebrew/llvm/03.cmake:
2022-09-15 07:06:11 +0000

cmake
--build
.
--target
install

Error: could not load cache
/usr/local/Homebrew/Library/Homebrew/shims/shared/curl --version
/usr/local/Homebrew/Library/Homebrew/ignorable.rb:29:in `block in raise'
BuildError: Failed executing: cmake --build . --target install
1. raise
2. ignore
3. backtrace
4. irb
5. shell
Choose an action: 2

2回 "2" を選択すると、LLVMのビルド処理が終了し、以降はHomebrewによってインストール処理が継続実行されます。

...   ...
==> Fixing /usr/local/Cellar/llvm/14.0.6_1/lib/python3.9/site-packages/clang/cindex.py permissions from 644 to 444
==> Fixing /usr/local/Cellar/llvm/14.0.6_1/lib/python3.9/site-packages/clang/enumerations.py permissions from 644 to 444
...   ...
==> Changing dylib ID of /Users/yuhri/homebrew/Cellar/llvm/14.0.6_1/lib/libomp.dylib
  from @rpath/libomp.dylib
    to /Users/yuhri/homebrew/opt/llvm/lib/libomp.dylib
==> Changing dylib ID of /Users/yuhri/homebrew/Cellar/llvm/14.0.6_1/lib/libunwind.1.0.dylib
  from @rpath/libunwind.1.dylib
    to /Users/yuhri/homebrew/opt/llvm/lib/libunwind.1.dylib
/Users/yuhri/homebrew/Library/Homebrew/brew.rb (Formulary::FromPathLoader): loading /Users/yuhri/homebrew/opt/llvm/.brew/llvm.rb
==> Caveats
To use the bundled libc++ please add the following LDFLAGS:
  LDFLAGS="-L/Users/yuhri/homebrew/opt/llvm/lib -Wl,-rpath,/Users/yuhri/homebrew/opt/llvm/lib"

llvm is keg-only, which means it was not symlinked into /Users/yuhri/homebrew,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

If you need to have llvm first in your PATH, run:
  echo 'export PATH="/Users/yuhri/homebrew/opt/llvm/bin:$PATH"' >> ~/.zshrc

For compilers to find llvm you may need to set:
  export LDFLAGS="-L/Users/yuhri/homebrew/opt/llvm/lib"
  export CPPFLAGS="-I/Users/yuhri/homebrew/opt/llvm/include"

==> Summary
🍺  /Users/yuhri/homebrew/Cellar/llvm/14.0.6_1: 11,663 files, 1.8GB, built in 76 minutes 6 seconds
...   ...

そして、最後はLLVMのインストールが成功して終わります。

インストールされたLLVMを確認する

インストールされたLLVMが利用可能かどうかは 、以下のコマンドによって確認できます。

% /usr/bin/clang --version
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
% /Library/Developer/CommandLineTools/usr/bin/clang --version
Apple LLVM version 10.0.0 (clang-1000.10.44.4)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
% /usr/local/opt/llvm/bin/clang --version
Homebrew clang version 14.0.6
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin

/usr/bin/clangXcode 10.1のclangコンパイラ/Library/Developer/CommandLineTools/usr/bin/clang がCommand Line Toolsのclang、/usr/local/opt/llvm/bin/clang がインストールしたLLVMのclangです。

Command Line Toolsの選択を元に戻す

上記までの手順でLLVMのインストールは完了ですが、"brew install --debug llvm " コマンドを実行する前に変更したCommand Line Toolsの選択を元に戻しておきます。

% xcode-select -p
/Applications/Xcode.app/Contents/Developer
% sudo xcode-select -s /Library/Developer/CommandLineTools
Password:
% xcode-select -p
/Library/Developer/CommandLineTools

【参考リンク】

stackoverflow.com