2018年9月17日月曜日

Fedora28でGCC7.3をビルドする

Fedora28ではGCCのバージョンは8.1だが、CUDA-9.2はGCC8ではできない。
(CUDAはもともとFedora27までのサポートなので、Fedora28は対象外。)

https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#system-requirements

CUDAのヘッダーファイルの定義を変えてもよいのだが、CUDAがビルドできるGCC7をソースビルドして用意することにした。
今回は、GCC7をビルドして、CUDAのサンプルをビルド&実行するところまで
方針としては、
  • もともと入っているGCC8と共存する
  • CUDAをビルドするときのみ(CUDAホストコンパイラ)にGCC7を指定する
  • GCC8と7は切り替えることができる


ビルドするにあたって、以下を参考にさせていただいた(ありがとうございます)。


環境

  • Fedora 28 x86_64
  • gcc バージョン 8.1.1 20180712 (Red Hat 8.1.1-5) (GCC)

GCCのビルド

ビルドに必要なパッケージをインストール。

$ sudo dnf install texinfo texi2html flex

CUDA9.2がサポートしているGCC 7.3のソースコードのダウンロードと展開。

$ wget http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-7.3.0/gcc-7.3.0.tar.gz
$ tar xvf gcc-7.3.0.tar.gz
$ cd gcc-7.3.0

ビルド。
必要なコンパイラはC, C++のみを指定。
インストールパス(prefix)に適当なパス(斜体部分)を指定。
(ここではhomeディレクトリ配下)
x86_64のみでi386のターゲットはビルドしない。

$ ./contrib/download_prerequisites
$ mkdir build
$ cd build
$ ../configure --enable-bootstrap --enable-languages=c,c++ --prefix=/home/username/gcc/7.3 --enable-shared --enable-threads=posix --enable-checking=release --disable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --enable-libmpx --enable-gnu-indirect-function --build=x86_64-redhat-linux
$make
$make install


specsファイルの作成

コンパイルしたGCC7でビルドした際に、適切な動的リンクライブラリ(libstdc++.so)がリンクされるようにSPECEファイルを修正する。
これは、CUDAホストコンパイラだけを指定する場合は問題ないと思うが、GCC7でビルドする場合もあるので行う。
specsファイルを出力。

$ /home/username/gcc/7.3/bin/gcc -dumpspecs > specs

出力したspecsファイルの以下を修正する。
変更前
*link_libgcc:
%D

変更後
*link_libgcc:
%{!static:%{!static-libgcc:-rpath /home/username/gcc/7.3/lib64/}} %D

修正したspecsファイルをコピー

$ cp specs /home/username/gcc/7.3/lib/gcc/x86_64-redhat-linux/7/


Environment Modulesの設定

GCC7, 8をEnvironment Modulesで切り替えられるようにする。
/etc/modulefiles 配下に、gcc7xのファイルを作成する。

#%Module 1.0
#
#  gcc-7.X module for use with 'environment-modules' package:
#

conflict        gcc8x
prepend-path    PATH                    /home/username/gcc/7.3/bin/

切り替えの確認

GCC7に切り替え

$ module add gcc7x
$ gcc -v
/home/username/gcc/7.3/lib/gcc/x86_64-redhat-linux/7/specs から spec を読み込んでいます
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/home/username/gcc/7.3/libexec/gcc/x86_64-redhat-linux/7/lto-wrapper
ターゲット: x86_64-redhat-linux
configure 設定: ../configure --enable-bootstrap --enable-languages=c,c++ --prefix=/home/nobuo/gcc/7.3 --enable-shared --enable-threads=posix --enable-checking=release --disable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --enable-libmpx --enable-gnu-indirect-function --build=x86_64-redhat-linux
スレッドモデル: posix
gcc バージョン 7.3.0 (GCC) 


もとに戻す

$ module unload gcc7x
$ gcc -v
組み込み spec を使用しています。
COLLECT_GCC=/usr/bin/gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/8/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
ターゲット: x86_64-redhat-linux
configure 設定: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,objc,obj-c++,ada,go,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --enable-libmpx --enable-offload-targets=nvptx-none --without-cuda-driver --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
スレッドモデル: posix
gcc バージョン 8.1.1 20180712 (Red Hat 8.1.1-5) (GCC) 

CUDAサンプルのビルド&実行

CUDA9.2のサンプルをビルドする。
まずはサンプルをコピー。

$ sh /usr/local/cuda/bin/cuda-install-samples-9.2.sh ./

GCC7に切り替え

$ module add gcc7x

あとは、ビルドだけ。
ただし、サンプルの中の 3_Imaging/cudaDecodeGL だけは、ビルドできないので除外。
(findgllib.mk でOpenGLのライブラリの検索がFedora用がなく無理だった)

OpenCVでCUDAをビルドする場合

OpenCVでCUDAを有効としたい場合は、GCC7に切り替えず、CUDA_HOST_COMPILERにGCC7のg++のパスを指定すれば良い。

2018年8月31日金曜日

OpenCVでYOLOv3のサンプルが動かなかったのでPRした

今回、OpenCVに初めてIssueとPull requestを発行して、Margeされたのでその経緯を書きたいと思う。
また、同じエラーの人のために(3.4.2、3.4.3で出ると思います)。




発端

OpenCV 3.4.2でYOLOv3がサポートされたので、動作確認しようと思ったのが発端。



しかし、サンプルを動かしたのだが、エラーとなってしまった。。。

サンプルはPython(samples/dnn/object_detection.py)。
自分の環境は以下。

  • OpenCV => 3.4.2
  • OS => Fedora 28
  • Compiler => GCC 8.1
  • Python3 => 3.6.6

実行したときのコマンド
$ python3 object_detection.py --input=./test.jpg --model=./yolov3.weights --config=./yolov3.cfg --classes=./object_detection_classes_coco.txt --scale=0.00392 --width=416 --height=416

発生したエラー
Traceback (most recent call last):
File "object_detection.py", line 196, in 
postprocess(frame, outs)
File "object_detection.py", line 162, in postprocess
drawPred(classIds[i], confidences[i], left, top, left + width, top + height)
File "object_detection.py", line 73, in drawPred
cv.rectangle(frame, (left, top), (right, bottom), (0, 255, 0))
TypeError: integer argument expected, got float


調べてみた

ググってみても、同じようにコケている人もおらず、C++では動いていそう。

怒られている理由は「cv.rectangleの引数には整数を指定しろ!」。
確かに座標(left, top, right, bottom)は整数である必要がある。
おそらく座標のパラメータが整数でない型なんだなーと思っていた。
実際はleftとtopが浮動小数点だった。
はい。。。Pythonさん、すいません。。。


最初は環境??とか思っていたが、原因はサンプルの以下の2行が原因だとわかった。
https://github.com/opencv/opencv/blob/3.4.2/samples/dnn/object_detection.py#L145-L146
left = center_x - width / 2
top = center_y - height / 2

Python3の場合、整数除算の結果は浮動小数点である。
(Python2は整数除算の結果は整数なので、Python2で実行すると問題ない)

なので、整数型に変換してあげると動いた!
left = int(center_x - width / 2)
top = int(center_y - height / 2)


IssueとPull Requestを出してみる

今までお世話になったOpenCVなので、勇気をだして初めてのIssueとPull Requestを送ってみることにした。

Pull Requestを出すにあたって公式も含めて以下を参考にした(ありがとうございます)。


Issue、Pull Requestとも反応が早いことにびっくり!
簡単だったこともあと思うが、1日もせず、マージされクローズしてしまった。

初めて出してみた感想は
  • 英語、やっぱりだめ、、、もっと勉強しないと
    (Google翻訳すごい)
  • 焦ってはだめ
    (Enterキーを間違って押してIssueのタイトルが変になってしまった)
  • 反応早い!ソッコーで反応くる
  • しかも、解決方法を複数提案
    あ、、、そういう方法もあるねと勉強になる!
  • good first issueなんてラベルがつくとテンション上がる!
  • マージされたらテンションMax!!
  • あれ?Issue誰クローズするの?僕??と思っていたら、クローズされた
    (これなにがただしいんだろう?)
  • はじめの一歩はとても戸惑うが、機会があれば次もチャレンジ!

次のリリース(3.4.4)が楽しみ!

2018年8月20日月曜日

OpenCVでカメラパラメータの解像度を変更したい

OpenCVでカメラキャリブレーションを行ったときと異なる解像度で補正したい場合がある。
例えば、Raspberry Pi + PiCameraのような組込用途の場合、高い解像度でインタラクティブなキャリブレーションを行う場合、以下のような制約がでてくる。

  • カメラキャプチャの画像を表示するモニターがない
    (まあ、自分がFullHDより大きいモニターを持っていないのが原因なんだけど・・・)
  • キャリブレーションの処理が遅くなる
    Raspberry Pi 3 Model B+ でも、1640 x 1232の解像度でCircle Patternの場合、フレームレートがかなり遅くなる(chAruco Patternはそこまで遅くならない)。

まあ、撮影したパターンをマシンパワーのあるPCなどで解析することも可能なのだが、やはり、"インタラクティブ"にできることはメリットが大きいと思う。

OpenCVの場合、cv::getOptimalNewCameraMatrixを使うことで、カメラパラメータの解像度を変更することができる。

cv::getOptimalNewCameraMatrixは、解像度の変更だけでなく、歪み係数とフリースケールパラメータ(alpha)から周りの画像の欠損を考慮したカメラパラメータを作成してくれる(*1)。
歪み係数は解像度に依存しない(*2)。

Pythonでcv::getOptimalNewCameraMatrixを使って解像度を変更してみる。

使い方


カメラキャリブレーション

まずは、640 x 480でカメラキャリブレーションを行う。
その時のカメラパラメータ抜粋。

<cameraResolution>
  640 480</cameraResolution>
<cameraMatrix type_id="opencv-matrix">
  <rows>3</rows>
  <cols>3</cols>
  <dt>d</dt>
  <data>
    5.3447832911092576e+02 0. 3.1759911211440613e+02 0.
    5.3447832911092576e+02 2.3505836099223782e+02 0. 0. 1.</data></cameraMatrix>
...
<dist_coeffs type_id="opencv-matrix">
  <rows>1</rows>
  <cols>5</cols>
  <dt>d</dt>
  <data>
    2.7780784561125338e-01 -7.6282457474037868e-01 0. 0.
    6.2366706868917043e-01</data></dist_coeffs>

カメラパラメータの読み込み

前回のブログの通り、cv::FileStorageを使ってカメラパラメータ、歪み係数を読み込む。
fs = cv2.FileStorage("PathToCameraParameterFile", cv2.FILE_STORAGE_READ)
if fs.isOpened():
        width = (int)(camera_fs.getNode("cameraResolution").at(0).real())
        height = (int)(camera_fs.getNode("cameraResolution").at(1).real())
        camera_matrix = camera_fs.getNode("cameraMatrix").mat()
    dist_coeffs = camera_fs.getNode("dist_coeffs").mat()

新しいカメラパラメータの作成

cv::getOptimalNewCameraMatrixを使って新しいカメラパラメータを生成する。
このとき、引数のnewImgSizeに新しい解像度を指定する。
    frame_width = 1640
    frame_height = 1232
    new_camera_matrix, roi = cv2.getOptimalNewCameraMatrix(camera_matrix, dist_coeffs,
            (width, height), 0.0, (frame_width, frame_height))

戻り値のnew_camera_matrixに新しい解像度のカメラパラメータが返る。

確認

念の為、カメラパラメータの値を確認する。
確認方法は、前回のブログcv::calibrationMatrixValuesを使ってみる。
Fx, Fy, Cx, Cy はカメラパラメータを出力。

まずは、解像度を変更しない場合(640 x 480 → 640 x 480)
  Fx   =  550.963135
  Fy   =  551.406250
  Cx   =  317.560888
  Cy   =  235.058842
  FOVX =  60.295405
  FOVY =  47.039412
  Focal length    =  3.168038
  Principal point =  1.825975, 1.351588
  Aspect ratio    =  1.000804

次に、解像度を変更する場合(640 x 480 → 1640 x 1232)
  Fx   =  1411.843018
  Fy   =  1415.276123
  Cx   =  813.749768
  Cy   =  603.317729
  FOVX =  60.295406
  FOVY =  47.039410
  Focal length    =  3.168038
  Principal point =  1.825975, 1.351588
  Aspect ratio    =  1.002432

カメラパラメータが適切に変更されていることがわかった。

参考情報



2018年8月18日土曜日

OpenCVのcv::calibrationMatrixValuesで焦点距離を求める

OpenCVの"opencv_interactive-calibration"やカメラキャリブレーションで求めたカメラパラメータからmm単位での焦点距離などを求めたいときがある。
自作している3Dスキャナーでも使用したい。

(OenCVでは)カメラパラメータのfx, fyはピクセル単位で扱われるため、以下のように計算すればmm単位での焦点距離は求められる。

焦点距離(mm) = fx × W ÷ w
 fx : 焦点距離(pixel)
 W  : イメージセンサーの幅(mm)
 w  : 画像の幅(pixel)

電卓で計算すればよいのだけど、OpenCVにはcv::calibrationMatrixValuesのAPIで焦点距離を含むカメラのスペックを計算してくれる。

せっかくなので、このAPIをPythonで使って見ようと思う。

使い方

まず、カメラパラメータと画像の解像度を読み込む。
これは、"opencv_interactive-calibration"で出力したファイルから読み込んでいる。
fs = cv2.FileStorage("PathToCameraParameterFile", cv2.FILE_STORAGE_READ)
if fs.isOpened():
        width = (int)(camera_fs.getNode("cameraResolution").at(0).real())
        height = (int)(camera_fs.getNode("cameraResolution").at(1).real())
        camera_matrix = camera_fs.getNode("cameraMatrix").mat()


そして、calibrationMatrixValuesを呼び出す。
fovx, fovy, focal_length, principal_point, aspect_ratio = cv2.calibrationMatrixValues(camera_matrix,
            (width, height), aperture_width, aperture_height)

print("  FOVX = ", "{:.6f}".format(fovx))
print("  FOVY = ", "{:.6f}".format(fovy))
print("  Focal length    = ", "{:.6f}".format(focal_length))
print("  Principal point = ", "{:.6f}, {:6f}".format(*principal_point))
print("  Aspect ratio    = ", "{:.6f}".format(aspect_ratio))
引数には以下を指定する。
  • cameraMatrix  カメラパラメータ(先程ファイルから得たパラメータ)
  • imageSize    画像の解像度(先程ファイルから得たパラメータ, 単位:pixel)
  • apertureWidth    イメージセンサーの幅(単位:mm)
  • apertureHeight    イメージセンサーの高さ(単位:mm)
戻り値にはカメラのスペックが返る。
  • fovx    垂直画角(単位:度)
  • fovy    水平画角(単位:度)
  • focalLength    焦点距離(単位:mm)
  • principalPoint    主点(単位:mm)
  • aspectRatio    fy / fz

試してみる

PiCamera V2.1でカメラキャリブレーションを行った結果で試してみる。
キャリブレーションした結果は以下の通りだった(chArucoパターンでキャリブレーション)。
<cameraResolution>
  640 480</cameraResolution>
<cameraMatrix type_id="opencv-matrix">
  <rows>3</rows>
  <cols>3</cols>
  <dt>d</dt>
  <data>
    5.3447832911092576e+02 0. 3.1759911211440613e+02 0.
    5.3447832911092576e+02 2.3505836099223782e+02 0. 0. 1.</data></cameraMatrix>

cv::calibrationMatrixValuesでカメラのスペックを出力してみる。
イメージセンサーのサイズは、公式ドキュメントから3.68 x 2.76 mm を指定。
FOVX =  61.818399
FOVY =  48.360546
Focal length    =  3.073250
Principal point =  1.826195, 1.351586
Aspect ratio    =  1.000000

公式のドキュメントからと比較すると
  • Sensor image area    3.68 x 2.76 mm (4.6 mm diagonal)
  • Focal length    3.04 mm
  • Horizontal field of view    62.2 degrees
  • Vertical field of view    48.8 degrees
なので、まずまず良いカメラキャリブレーションができたかな?

2018年8月16日木曜日

OpenCVのcv::FileStorageをPythonで扱う

OpenCVでXML/YAML/JSONのデータ構造を扱う

OpenCVでcvパラメータを扱う場合、cv::FileStorageクラスが用意されている。XML, YAML, JSONの各フォーマットのファイルからパラメータの読み書きができる。

利点は、
  • C++で簡単にパラメータのファイルを扱うことができる
  • cv::Mat, cv::Size等のOpenCVの形式でパラメータを読み書きできること

カメラキャリブレーションのopencv_interactive-calibrationもXML形式のファイルを出力するので、パラメータを読む際は、cv::FileStorageクラスが利用できる。

自作中のPaspberry Piの3Dスキャナーでもcv::FileStorageクラスを利用してパラメータの読み込みを行う予定。


cv::FileStorageをPythonで使う

手書きでパラメータのファイルを作成するより、ファイルを自動生成できたほうが良いと考え、Pythonでツールを作成したのだが、思ったように使えないことが判明した。
(Pythonでサクッと作ってしまえば良いと思っていた)


Pythonで扱う場合の問題(デメリット)

配列(シーケンス)のデータを出力できない

例えば、C++で解像度などcv::Sizeで保持されるデータを出力した場合、シーケンスとして出力される。

<cameraResolution>
  640 480</cameraResolution>

しかし、Pythonにはcv::Sizeはなく、タプルで扱うことになるが、タプルはcv::Matに変換されてしまうため、シーケンスとして出力されず、以下のように出力されてしまう。

<cameraResolution type_id="opencv-matrix">
  <rows>2</rows>
  <cols>1</cols>
  <dt>d</dt>
  <data>
    640. 480.</data></cameraResolution>

これは、Pythonの場合、タプル、リストはすべてcv::Matにバインディングされるためである。読み込み時もPythonであれば、問題はないのだが、C++の場合、cv::Matにしか使えなくなってしまう。


マッピングのデータを出力できない

C++では<< operatorで"{", "}"を出力することで、マッピングされたデータを出力できる。
(同じように"[", "]"でシーケンスのデータを出力できる)
詳細は、OpenCVのドキュメントを参照。

しかし、Pythonには<< operatorはバインディングされていないため出力できない。


代替え方法

もともと、cv::FileStorageはC++でパラメータを扱いやすくするためであり、Pythonで扱うこと自体があまり良い考えでないと思う。
Pythonで扱うのであれば、PyYAMLを使ったほうが良く、Pythonで出力したデータをC++のcv::FileStorageで読み込むこともできるはず。
ただし、PyYAMLではcv::Matの形式では出力できなくなるが、その場合は自作してしまえば良いとなる。

2018年7月25日水曜日

PiCameraをOpenCVのCameraCaptureで使用する

v4l2ドライバーの読み込み


Raspberry Pi の PiCameraをOpenCVのカメラキャプチャで使用する場合、オフィシャルのV4L2ドライバーをロードする必要がある。

$ sudo modprobe bcm2835-v4l2

起動時に自動的にロードできるように、/etc/modules ファイルに以下の行を追加する。

bcm2835-v4l2


大きい解像度でカメラキャプチャすると画像が青みがかる


640×480などの解像度でカメラキャプチャする場合、問題ないが、1640×1232や3280×2464などの解像度を指定すると、カメラキャプチャした画像が青みがかってしまう。

原因は、bcm2835-v4l2は、パラメータを指定しない場合、1280×720までしか対応していないためである。これより大きい解像度を使う場合、ドライバーのロード時のパラメータを設定する必要がある(解像度が限定されている理由はv4l2ドライバーではFPSが低下するための模様)。

$ sudo modprobe bcm2835-v4l2 max_video_width=3280 max_video_height=2464

※解像度の指定はPiCamera v2.1の最大解像度

あとは、起動時にもパラメータを指定するために、/etc/modprobe.d/bcm2835-v4l2.conf ファイルを新規作成し、以下のオプションを指定する。
options bcm2835-v4l2 max_video_width=3280 max_video_height=2464


参考

2018年7月20日金曜日

cvui を Python で試す

OpenCVでGUIを描画する場合、highguiの機能だと難しいケースがある。
特に画像いじる際に、パラメータを変更しながらリアルタイムに確認したい場合など、trackBarだけだと結構厳しい。
やっぱり、ボタンとか、チェックボックスとかのGUIツールも欲しい。でもQtやWFPだと気軽には試せなくなってしまう。

そんな不満を解消するcvuiはC++の"header only"のOpenCVのUIを描画する軽量ライブラリで、ヘッダーファイルをインクルードすれば気軽に使えてしまうので重宝していた。

そんなcvuiがBETA releaseでPythonに対応していたので試してみる。

注意
Githubにも記載がる通り、あくまでBETA releaseです。
不具合や今後何があるかわかりません。

https://github.com/Dovyski/cvui/releases/tag/v2.7.0-BETA
NOTICE: this is a BETA release, a particularly special one. From now on, cvui has two implementations: a C++ and a Python one. The C++ implementation only received bug fixes since its last release, so there should be no problems regarding upgrades. The Python implementation, however, is brand new. Its API is unlikely to change until the final 2.7.0 release, but please bare in mind it might present problems and things could change to improve the overall Python experience of cvui.

インストール

Fedora 28, OpenCV3.4.1, Python 3.6.5 の環境にインストール
pipでpython版のcvuiをインストールする
$ sudo pip3 install cvui

簡単なサンプルを動かしてみる

テキストとボタンを描画する簡単なサンプル。
リファレンスのドキュメントはC++だが、PythonもほぼおなじようなIFで使用できる。
(Python用のドキュメントは見つからなかった)

テキストとボタンを表示する簡単なサンプルを作ってみる
WINDOW_NAME = "CVUI Sample"
import numpy as np
import cv2
import cvui

WINDOW_NAME = "CVUI Sample" # cvuiの初期化時に指定するWindow Name

def main():
    frame = np.zeros((200, 500, 3), np.uint8)
    is_on = False

    # cvuiの初期化
    cvui.init(WINDOW_NAME)

    while True:
        frame[:] = (49, 52, 49)

        # テキストの描画
        cvui.text(frame, 110, 80, "Hello, world!")
        # ボタンの描画と押下したときの判定
        if cvui.button(frame, 100, 40, "Button"):
            is_on = not(is_on)

        # ボタンが押されたら、テキストを描画する(トグルボタン)
        if is_on:
            cvui.text(frame, 150, 150, "Button Clicked")

        # 画像を描画する(cv2.imshowとおなじ)
        cvui.imshow(WINDOW_NAME, frame)

        if cv2.waitKey(20) == 27:
            break;

if __name__ == '__main__':
    main()

スクリーンショット

ボタンを押すと、トグルでテキストを表示・非表示する。




2018年7月9日月曜日

Raspberry pi 3 model B+ で Yoct(weston)

Raspberry Pi 3 Model B+を入手したので、YoctoでAArch64のイメージを作成してみる。
半年前(2017年後半?)ごろは、Raspberry Pi 3(無印)のAArch64では、Wifi、Bluetoothはドライバがないため、使えなかったが今回は使えそうなことが判明した。
なので、ブラウザ(Chromium)を組み込んだWestonのイメージを作成してみることにした。

準備

Chromiumをビルドするには、追加でlibatomicをビルド環境にインストールする
(筆者の環境はFedora28です)
$ sudo dnf install libatomic

ダウンロード・レイヤーの追加

master環境を引っ張ってくる。
Chromiumを追加するために、meta-browserも引っ張ってくる。
$ git clone git://git.yoctoproject.org/poky.git
$ cd poky/
$ git clone git://git.openembedded.org/meta-openembedded
$ git clone git://git.yoctoproject.org/meta-raspberrypi
$ git clone https://github.com/OSSystems/meta-browser
$ cd ../
$ source poky/oe-init-build-env rpi-build
$ bitbake-layers add-layer ../poky/meta-openembedded/meta-oe/
$ bitbake-layers add-layer ../poky/meta-openembedded/meta-multimedia/
$ bitbake-layers add-layer ../poky/meta-openembedded/meta-python/
$ bitbake-layers add-layer ../poky/meta-openembedded/meta-networking/
$ bitbake-layers add-layer ../poky/meta-raspberrypi/
$ bitbake-layers add-layer ../poky/meta-browser/

Bitbake

conf/local.confに以下を追加する。
(AArch64ビルドの指定と、Chromiumと日本語フォントの追加指定)
MACHINE ?= "raspberrypi3-64"
IMAGE_INSTALL_append = " chromium-ozone-wayland "
IMAGE_INSTALL_append = " source-han-sans-jp-fonts "

あとは、bitbakeコマンドでビルド

$ bitbake core-image-weston
WARNING: Host distribution "fedora-28" has not been validated with this version of the build system; you may possibly experience unexpected failures. It is recommended that you use a tested distribution.
Loading cache: 100% |#####################################################################| Time: 0:00:00
Loaded 3089 entries from dependency cache.
NOTE: Resolving any missing task queue dependencies

Build Configuration:
BB_VERSION = "1.39.0"
BUILD_SYS = "x86_64-linux"
NATIVELSBSTRING = "universal"
TARGET_SYS = "aarch64-poky-linux"
MACHINE = "raspberrypi3-64"
DISTRO = "poky"
DISTRO_VERSION = "2.5+snapshot-20180703"
TUNE_FEATURES = "aarch64"
TARGET_FPU = ""
meta 
meta-poky 
meta-yocto-bsp = "master:7cb125d7ee4b80fb33d87bdd0b257bc6daaff051"
meta-oe 
meta-multimedia 
meta-python 
meta-networking = "master:4517d1c695efd0b175f4e7242e1a7bb4361527d9"
meta-raspberrypi = "master:3b6549a5e016efe63c9d1463948b9de1ee5d89ed"
meta-browser = "master:1cd38d701a49eade80a04140f70d3383117b9745"

Initialising tasks: 100% |################################################################| Time: 0:00:03
NOTE: Executing SetScene Tasks
NOTE: Executing RunQueue Tasks
NOTE: Tasks Summary: Attempted 4831 tasks of which 4803 didn't need to be rerun and all succeeded.

Summary: There was 1 WARNING message shown.

SDカード書き込み・起動

ifconfigコマンドでwlan0が認識していることを確認。
SSID、キーを登録して、ルーターからIPアドレスが払い出されることを確認。
Chromiumを起動して、googleのトップページが開けた!!


2018年6月23日土曜日

OpenCV Viz の Widgetのサンプル(その3)

OpenCVのVizにはどんなWidgetがあるのか?確認してみる。
全3回

WSphere(球体)

中心座標、円の半径、球体の面を指定。

  auto sphere = cv::viz::WSphere(cv::Point3d(0.0, 0.0, -2.5), // 中心
                                 2.0,                         // 半径
                                 30,                          // 球体の面
                                 cv::viz::Color::rose());     // 色
  myWindow.showWidget("Sphere", sphere);


WText(テキスト)

2次元平面にテキストを描画する。
視点を変えてもテキストの位置は変わらない。

  auto text = cv::viz::WText("OpenCV Viz",
                             cv::Point(100, 100),
                             20,
                             cv::viz::Color::black());
  myWindow.showWidget("Text", text);


WText3D(3Dテキスト)

3次元平面にテキストを描画する。
引数のface_cameraにtrue(常にテキストが見えるようになる)を指定すると初期表示位置がおかしい(falseを指定するとそんなことはない)。

  auto text_3d = cv::viz::WText3D("OpenCV Viz",	// 表示するテキスト
                                  cv::Point3d(1.0, 0.0, 0.0),	// 表示位置
                                  1.0,	// テキストのサイズ
                                  false,	// テキストが常に見えるようにするか?
                                  cv::viz::Color::black());
  myWindow.showWidget("Text3D", text_3d);


まだ、載せていないのがいくつかあるけど、ここまで

2018年6月22日金曜日

OpenCV Viz の Widgetのサンプル(その2)

OpenCVのVizにはどんなWidgetがあるのか?確認してみる。

全3回

WImage3D(画像)


cv::imreadで読み出しが画像を描画する。
vizの座標系はx軸が下なので、画像を180度回転して上げる必要がある(キャプチャはしていない)。

  auto im = cv::imread("./lena.jpg");
  auto image_3d = cv::viz::WImage3D(im, cv::Size2d(40, 40));
  myWindow.showWidget("Image3D", image_3d);




WImageOverlay(画像のオーバーレイ)

画像を3次元空間描画するのでなく、2次元の平面に描画。
視点をグリグリしても、位置は変わらない。
座標をcv::Rectで指定する(左下が原点になるので注意!)。

  auto im = cv::imread("./lena.jpg");
  auto image_overlay = cv::viz::WImageOverlay(im, cv::Rect(0, 0, 250, 250));
  myWindow.showWidget("ImageOverlay", image_overlay);



WPlane(パネル)

中心座標、平面の法線、Y軸の方向、サイズを指定する。
(色はネイビーなんだけど、ちょっと見た目が違う???)


  auto plane = cv::viz::WPlane(cv::Point3d(0.0, 0.0, 0.0),  // 中心座標
                               cv::Vec3d(1.0, 0.0, 0.0),    // 平面の法線
                               cv::Vec3d(1.0, 1.0, 0.0),    // Y軸の方向
                               cv::Size2d(3.0, 3.0),        // サイズ
                               cv::viz::Color::navy());     // 色
  myWindow.showWidget("Plane", plane);


WPolyLine(多角形)

頂点の座標の配列を指定する。
ぐるぐる

  cv::Mat polyline(1, 32, CV_64FC3);
  for (auto i = 0; i < (int)polyline.total(); i++)
  {
    polyline.at(i) = cv::Vec3d(i / 16.0, cos(i * CV_PI / 6), sin(i * CV_PI / 6));
  }
  myWindow.showWidget("Polyline", cv::viz::WPolyLine(polyline));



2018年6月21日木曜日

OpenCV Viz の Widgetのサンプル(その1)

OpenCVのVizにはどんなWidgetがあるのか?確認してみる。
3Dスキャナーで計算した3次元の点をOpenCVのVizで表示するための下準備。
チュートリアルにないものを抜粋。
ここを見れば良い。
https://docs.opencv.org/3.4.1/d1/d19/group__viz.html

全3回

WAllow(矢印)

始点、終点、太さを指定する。
 auto arrow = cv::viz::WArrow(cv::Point3d(1, 0, 0),        // 始点
                               cv::Point3d(1, 1, 0),        // 終点
                               0.01,                         // 太さ
                               cv::viz::Color::amethyst());  // 色
  myWindow.showWidget("Arrow", arrow);↲         


WCircle(円)

半径、中心座標、平面の法線、太さを指定する。
塗りつぶしたいときは、半径を半分にして、太さを半径と同じ値にする。
  auto circle = cv::viz::WCircle(1.0,                         // 半径
                                 cv::Point3d(0.0 ,0.0, 0.0),  // 中心
                                 cv::Vec3b(1.0, 0.0, 0.0),    // 平面の法線
                                 0.01,                        // 太さ
                                 cv::viz::Color::celestial_blue());
  myWindow.showWidget("Circle", circle);



WCone(円柱)

長さ、中心座標、先端座標、円の解像度を指定。
  auto cone = cv::viz::WCone(0.5,                     // 長さ
                             cv::Point3d(-1, -1, -1), // 中心
                             cv::Point3d(-2, -2, -2), // 先端
                             12,                           // 円の解像度(何角型か)
                             cv::viz::Color::chartreuse());
  myWindow.showWidget("Cone", cone);


WCylinder(円柱)

始点、終点、半径、円の解像度を指定。
両端は閉じていないので、WCricleを描画してあげる必要がある。
   auto cylinder = cv::viz::WCylinder(cv::Point3d(2.0, 2.0, 2.0),  // 始点
                                     cv::Point3d(3.0, 2.0, 2.0),  // 終点
                                     1.0, // 半径
                                     30,  // 円の解像度(何角型か)
                                     cv::viz::Color::maroon());
  myWindow.showWidget("Cylinder", cylinder);


WGrid(グリッド)

グリッドの平面を描画。
中心座標、平面の法線、Y軸の方向、グリットのマス目、グリット間の距離を指定。
  auto grid = cv::viz::WGrid(cv::Point3d(0.0, 0.0, 0.0),  // 中心座標
                             cv::Vec3d(-1.0, 1.0, 0.0),   // 平面の法線
                             cv::Vec3d(0.0, 1.0, 0.0),    // Y軸の方向
                             cv::Vec2i(10, 10),           // グリッドのマス目
                             cv::Vec2d(0.2, 0.2),         // グリッド間の距離
                             cv::viz::Color::lime());
  myWindow.showWidget("Grid", grid);


続く。

2018年6月17日日曜日

YOLOv3をFedora28+CUDAで動かしてみる

YOLOv3

YOLOとは、state-of-the-artsなリアルタイム一般物体認識。
詳細の説明は割愛。
今回は、Fedora28でYOLOv3を試そうとしたときにつまずいたポイントを紹介。

Fedora28でつまずいたポイント

darknetのビルドで、OPENCV、CUDAを有効とすると、ビルドエラーが発生。
環境は以下
  • CPU AMD Ryzen 7 1700
  • GPU NVIDIA GeForce GTX 1070
  • OS Fedora 28 
  • GCC 8.1.1
  • CUDA 9.1
  • OpenCV 3.4.1(ソースビルド)
ビルドエラーの内容と解決した方法について解説。
解決方法は公式の手順ではないので注意。

OpenCV

MakefileのOPENCVを有効にしてビルドすると、ビルドエラーが発生。
$ make
gcc -Iinclude/ -Isrc/ -DOPENCV `pkg-config --cflags opencv`  -DGPU -I/usr/local/cuda/include/ -DCUDNN  -Wall -Wno-unused-result -Wno-unknown-pragmas -Wfatal-errors -fPIC -Ofast -DOPENCV -DGPU -DCUDNN -c ./src/gemm.c -o obj/gemm.o
In file included from /usr/local/include/opencv2/core/types_c.h:59,
                 from /usr/local/include/opencv2/core/core_c.h:48,
                 from /usr/local/include/opencv2/highgui/highgui_c.h:45,
                 from include/darknet.h:25,
                 from ./src/utils.h:5,
                 from ./src/gemm.c:2:
/usr/local/include/opencv2/core/cvdef.h:485:1: エラー: 不明な型名 ‘namespace’ です
 namespace cv {
 ^~~~~~~~~
-Wfatal-errors によりコンパイルを停止しました。
make: *** [Makefile:85: obj/gemm.o] エラー 1

原因は、darknetはOpenCVのC言語IFを呼び出しているが、OpenCV3系はC言語IFはサポートしなくなったためらしい。。。(ほんと?)
みんな、コンパイルできなくて困っている。。。
https://github.com/pjreddie/darknet/issues/485
https://github.com/opencv/opencv/issues/10963

解決方法

OpenCV2系をビルド・インストール
以下から2.4.13.6のソースをダウンロードしていつもどおりビルド。
https://github.com/opencv/opencv/releases/tag/2.4.13.6

ビルドする際の注意
あとは、darknetのMakefileでpkg-configでopencvを指定している箇所をopencv2に変更してビルドすればOK。


CUDA

CUDAのhost compilerはGCC 6以下がサポートしており、Fedora 28のGCC 8はサポートしていない。このため、CUDAを有効としてビルドするとビルドエラーが発生する。
In file included from /usr/local/cuda/include/host_config.h:50,
                 from /usr/local/cuda/include/cuda_runtime.h:78,
                 from <コマンドライン>:
/usr/local/cuda/include/crt/host_config.h:121:2: エラー: #error -- unsupported GNU version! gcc versions later than 6 are not supported!
 #error -- unsupported GNU version! gcc versions later than 6 are not supported!
  ^~~~~

解決方法

host compilerにGCC 6以下を指定する。
MakefileのNVCC=nvccに-ccbinオプションでコンパイラを指定。
gccは5.5をソースビルドしたものを使用。

結果

darknetのサンプルファイル"data/kite.jpg"で確認


Model
Build option
Prediction time
(seconds)
Prediction time
(milliseconds)
FPS
GPUCUDAOPENMP
YOLOv31100.03365633.729.7
YOLOv3-tiny 1100.0062996.3158.8
YOLOv30007.9802647980.30.1
YOLOv3-tiny 0000.729358729.41.4
YOLOv30012.3087572308.80.4
YOLOv3-tiny 0010.286995287.03.5
GPUありのYOLOv3で約30fps。早い!

2018年4月14日土曜日

OpenCVでビデオキャプチャが遅く感じるとき

事象

OpenCVでビデオキャプチャの画像を表示すると遅くなる場合がある。
例えば、このようなコードを書いたときに遅くなる(Python, C++に関係なく発生する)。
以下はPythonコード。

cap = cv2.VideoCapture(0)
while (True):
    ret, frame = cap.read()

    # 何か重い処理

    cv2.imshow("camera", frame)
    key = cv2.waitKey(1) & 0xff
    if key == 27:
        break

原因

これは、OpenCVはキャプチャした画像はバッファリングしているが、重い処理が原因で常にバッファの一番最後の画像を取得してしまうので遅くなってしまう(タイムラグが発生してしまう)。

解決方法

ビデオキャプチャのループ処理は設定したビデオキャプチャで指定したFPS内で処理できるようにすること。つまり、重い処理をしてはいけない。
どうしても重い処理を行うのであれば、

  • ビデオキャプチャのFPSを下げる(CV_CAP_PROP_FPSを指定)
  • ビデオキャプチャのループと何か重い処理を別スレッドにする(処理しないフレームが発生する)
のいずれかが必要。これは「何か重い処理」の内容を見極めて対応する必要がある。

2018年3月24日土曜日

Open3Dを動かしてみる

最近、話題のOpen3Dをビルドしてみた。
DesktopPC(Ryzen 1700)とRaspberry pi 3で動作させてみた。

ビルド方法

チュートリアルに書かれてある通りにビルド
$ git clone https://github.com/IntelVCL/Open3D
$ ./scripts/install-deps-ubuntu.sh
$ mkdir build
$ cd build
$ cmake ../src
$ make -j

Tutorial/Basicのコードを動かしてみる

Raspberry pi 3の場合、画面が重くてほとんど動かない。表示もおかしい。
チュートリアルのコードを実行すると
GLFW Error: X11: RandR gamma ramp support seems broken
が出力されているのでOpenGL?の問題もありそう。

手持ちの環境(Ryzen1700 と Raspberry pi 3)で処理時間を比較してみる。
処理時間の計測はPython3のtime.perf_counter()を使用。単位はすべて秒

rgbd_redwood.py


Open3D python apiRyzen 1700Raspberry pi 3
create_rgbd_image_from_color_and_depth0.0031308780.035566293
create_point_cloud_from_rgbd_image0.0031308780.146715472

rgbd_odometry.py


Open3D python apiRyzen 1700Raspberry pi 3
compute_rgbd_odometry(using RGB-D Odometery)0.7698600583.41303919
compute_rgbd_odometry(using Hybrid RGB-D Odometery)0.7833153363.615518965

odometeryの結果、RtはRyzen, Raspberry pi 3とも一致。
Ryzenの場合
Using RGB-D Odometry
[[ 9.99985161e-01 -2.24233601e-04 -5.44316453e-03 -4.82515882e-04]
 [ 1.46064327e-04  9.99896920e-01 -1.43571495e-02  2.89043658e-02]
 [ 5.44582281e-03  1.43561414e-02  9.99882115e-01  7.88078866e-04]
 [ 0.00000000e+00  0.00000000e+00  0.00000000e+00  1.00000000e+00]]
Using Hybrid RGB-D Odometry
[[ 9.99994666e-01 -1.00290832e-03 -3.10826679e-03 -3.75410519e-03]
 [ 9.64494137e-04  9.99923448e-01 -1.23356688e-02  2.54977515e-02]
 [ 3.12040039e-03  1.23326051e-02  9.99919082e-01  1.88139777e-03]
 [ 0.00000000e+00  0.00000000e+00  0.00000000e+00  1.00000000e+00]]
Raspberry pi 3の場合
[[ 9.99985161e-01 -2.24233601e-04 -5.44316453e-03 -4.82515882e-04]
 [ 1.46064327e-04  9.99896920e-01 -1.43571495e-02  2.89043658e-02]
 [ 5.44582281e-03  1.43561414e-02  9.99882115e-01  7.88078866e-04]
 [ 0.00000000e+00  0.00000000e+00  0.00000000e+00  1.00000000e+00]]
Using Hybrid RGB-D Odometry
[[ 9.99994666e-01 -1.00290832e-03 -3.10826679e-03 -3.75410519e-03]
 [ 9.64494137e-04  9.99923448e-01 -1.23356688e-02  2.54977515e-02]
 [ 3.12040039e-03  1.23326051e-02  9.99919082e-01  1.88139777e-03]
 [ 0.00000000e+00  0.00000000e+00  0.00000000e+00  1.00000000e+00]]

pointcloud.py


Open3D python apiRyzen 1700Raspberry pi 3
voxel_down_sample0.0153782820.136582671
estimate_normals0.0052679820.085729508
crop_point_cloud0.0284832150.285484762
paint_uniform_color0.0001464830.00105934

kdtree.py


Open3D python apiRyzen 1700Raspberry pi 3
KDTreeFlann0.0005339760.00671003
search_knn_vector_3d0.0000498730.000483227
search_radius_vector_3d0.0000223110.000134426

icp_registration.py


Open3D python apiRyzen 1700Raspberry pi 3
evaluate_registration0.0733231261.06074374
registration_icp
(point-to-point ICP)
1.19398570718.54412634
registration_icp
(point-to-plane ICP)
1.13801447217.36850839

Raspberry pi 3の場合、ほとんど表示されない(黒い点の集合だけ)。

いや、もっとPoint Couldのことを覚えないと。。。

2018年2月16日金曜日

Fedora27にNVIDIA driverとcudaをインストール


概要

NVIDIAのドライバーはFedoraには25しか提供されていない。Fedora 27にインストールしたい場合は、25のものを使用すれば良い。オフィシャルのパッケージを手動で入れるか、rpmfusionなどのレポジトリから導入する手順がある。
今回は、rpmfusionのレポジトリからインストールした。
https://rpmfusion.org/Howto/NVIDIA

なお、rpmfusionやcudaのレポジトリからインストールした場合は、セキュアブートを無効にしないとドライバがロードできない。セキュアブートを有効にしたい場合は手動のインストールが必要。自分の環境では、DKMSでエラーとなってしまうことからrpmfusionのレポジトリからインストールすることにした。

事前の確認

まず、HW情報を確認。
(自分の環境は Ryzen 1700 + Gforce 1070)
$ /sbin/lspci | grep -e VGA
28:00.0 VGA compatible controller: NVIDIA Corporation GP104 [GeForce GTX 1070] (rev a1)


rpmfusionのレポジトリを登録

sudo dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm

ディスプレイドライバのインストール

sudo dnf install xorg-x11-drv-nvidia akmod-nvidia
sudo dnf update


cudaのインストール

cudaのレポジトリを登録する。
オフィシャルページのFedora25のrpm[network]をダウンロード&インストールする
https://developer.nvidia.com/cuda-downloads
sudo dnf install cuda

注意

cudaとrpmfusionのレポジトリでドライバが競合してしまうため、インストール後はcudaのレポジトリは無効にしておいたほうがよい(excludeを指定すればよい)