DragonBoard 410c(Debian)でOpenCVを使ってみる

DragonBoard 410c(Debian)でOpenCVを使ってみる

DragonBoardを使用してWebCamを使用できるようになったので今度はOpenCVを使ってみます。概ねRaspberryPiと同じような設定で問題ありません。

(注意!)2017/08/12にapt-get dist-upgradeを行ったところ/dev/video0で認識されていたUSBカメラが/dev/video2として認識されるよになったようです。そのため、そのまま実行するとV4Lのエラーが発生するかもしれません。各ソースのカメラデバイスを0→2と変更する必要があるかと思います。その場合は変更をお願いします。

Python

uepon.hatenadiary.com

過去のエントリーを参考にモジュールをインストールします。

$ sudo apt-get install libopencv-dev python-opencv 

バージョンに関しては

$ less /usr/include/opencv2/core/version.hpp

で調べてみると…

#define CV_VERSION_EPOCH    2
#define CV_VERSION_MAJOR    4
#define CV_VERSION_MINOR    9
#define CV_VERSION_REVISION 1

2017年07月時点でのインストールではversionは2.4.9になっていたようです。

ではカメラ画像をX上に表示するプログラムを実行してみます。 以下のようなサンプルとなります。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import cv2.cv as cv
import time

cv.NamedWindow("camera", 1)

capture = cv.CaptureFromCAM(0)
# V4Lエラーが発生した場合には上記を/dev/video2と認識された場合には以下に置き換えます。
# capture = cv.CaptureFromCAM(2)


# 画像サイズの指定
cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_WIDTH,320)
cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_HEIGHT,240)

while True:
    img = cv.QueryFrame(capture)
    cv.ShowImage("camera", img)
    if cv.WaitKey(10) > 0:
        break
cv.DestroyAllWindows()

実行してみると

$ python camera.py

f:id:ueponx:20170812095932j:plain

無事に動作できました! まあ、OSは同じなのでRaspberryPiと同様ですね。

Node.js編

次はNode.jsでも確認してみます。

uepon.hatenadiary.com

こちらも過去記事を参照して行います。 インストールにはnpmを使用します。

念のため環境はこんな感じです。過去使用していてnpmのバージョンが低いと警告があったため、npmだけバージョンアップしています。

$ nodejs -v
v4.8.2
$ npm -v
5.3.0

では、インストールしてみます。

$ npm install opencv

> opencv@6.0.0 install /home/linaro/opencv/node_modules/opencv
> node-pre-gyp install --fallback-to-build

node-pre-gyp ERR! Tried to download(403): https://node-opencv.s3.amazonaws.com/opencv/v6.0.0/Release/node-v46-linux-arm64.tar.gz
node-pre-gyp ERR! Pre-built binaries not found for opencv@6.0.0 and node@4.8.2 (node-v46 ABI) (falling back to source compile with node-gyp)
make: Entering directory '/home/linaro/opencv/node_modules/opencv/build'
  CXX(target) Release/obj.target/opencv/src/init.o
  CXX(target) Release/obj.target/opencv/src/Matrix.o
  CXX(target) Release/obj.target/opencv/src/OpenCV.o
  CXX(target) Release/obj.target/opencv/src/CascadeClassifierWrap.o
  CXX(target) Release/obj.target/opencv/src/Contours.o
  CXX(target) Release/obj.target/opencv/src/Point.o
  CXX(target) Release/obj.target/opencv/src/VideoCaptureWrap.o
  CXX(target) Release/obj.target/opencv/src/CamShift.o
  CXX(target) Release/obj.target/opencv/src/HighGUI.o
  CXX(target) Release/obj.target/opencv/src/FaceRecognizer.o
  CXX(target) Release/obj.target/opencv/src/Features2d.o
  CXX(target) Release/obj.target/opencv/src/BackgroundSubtractor.o
  CXX(target) Release/obj.target/opencv/src/Constants.o
  CXX(target) Release/obj.target/opencv/src/Calib3D.o
  CXX(target) Release/obj.target/opencv/src/ImgProc.o
  CXX(target) Release/obj.target/opencv/src/Stereo.o
  CXX(target) Release/obj.target/opencv/src/LDAWrap.o
  SOLINK_MODULE(target) Release/obj.target/opencv.node
  COPY Release/opencv.node
  COPY /home/linaro/opencv/node_modules/opencv/build/opencv/v6.0.0/Release/node-v46-linux-arm64/opencv.node
  TOUCH Release/obj.target/action_after_build.stamp
  CXX(target) Release/obj.target/test_nativemat/test/nativemat.o
  SOLINK_MODULE(target) Release/obj.target/test_nativemat.node
  COPY Release/test_nativemat.node
make: Leaving directory '/home/linaro/opencv/node_modules/opencv/build'
npm WARN saveError ENOENT: no such file or directory, open '/home/linaro/opencv/package.json'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN enoent ENOENT: no such file or directory, open '/home/linaro/opencv/package.json'
npm WARN opencv No description
npm WARN opencv No repository field.
npm WARN opencv No README data
npm WARN opencv No license field.

+ opencv@6.0.0
added 163 packages in 280.854s

実行するとエラーやWarningが発生します。うへぇ。ただ、なんとなくbuildは行われているので動作するのではないかと淡い望みをかけてテストします。

サンプルはこんな感じです。

var cv = require('opencv');

try {
        var camera = new cv.VideoCapture(0);
    // V4Lエラーが発生した場合には上記を/dev/video2と認識された場合には以下に置き換えます。
        // var camera = new cv.VideoCapture(2);


        var window = new cv.NamedWindow('Video', 0)

        setInterval(function() {
                camera.read(function(err, im) {
                        if (err) throw err;
                        console.log(im.size())
                        if (im.size()[0] > 0 && im.size()[1] > 0){
                                window.show(im);
                        }
                        window.blockingWaitKey(0, 50);
                });
        }, 20);
} catch (e){
          console.log("Couldn't start camera:", e)
}
$ nodejs camera.js

一応動いてくれました。

f:id:ueponx:20170812102853p:plain

エラーがでてしまったので無事に動くかかなり不安でしたが動作できたようです。でも、他の機能などもチェックしないと少し不安な印象でした。

まとめ

RaspberryPi同様にOpenCVpythonとNode.jsの両方で動作が確認できました。

あと個人的に気になるのはDragonBoardではBluetoothシリアルになるかなと思います。

DragonBoard 410c(Debian)でUSB接続のWebCamを使用してみる

DragonBoard 410c(Debian)でUSB接続のWebCamを使用してみる

なんとなく気になったので調べてみました。 結論からいうとUVC対応のものであれば問題なく使用できるようです。

接続

カメラをUSB接続します。

【接続前】

$ lsusb 
Bus 001 Device 003: ID 0b95:7720 ASIX Electronics Corp. AX88772
Bus 001 Device 002: ID 0424:2513 Standard Microsystems Corp. 2.0 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

【接続後】

linaro@linaro-alip:~$ linaro@linaro-alip:~$ lsusb 
Bus 001 Device 004: ID 0b95:7720 ASIX Electronics Corp. AX88772
Bus 001 Device 003: ID 045e:075d Microsoft Corp. LifeCam Cinema
Bus 001 Device 002: ID 0424:2513 Standard Microsystems Corp. 2.0 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

以下のエントリが一覧に追加しているので認識は問題ないようです。

Bus 001 Device 003: ID 045e:075d Microsoft Corp. LifeCam Cinema

念のため/dev/videoデバイスも追加されているか確認します。

$ /dev/video*
/dev/video0  /dev/video1  /dev/video2

問題なく生成されています。

$ sudo apt-get install guvcview

キャプチャしてみる

RaspberryPiとはことなり静止画のキャプチャのアプリケーションがないのでインストールを入れる必要がありそう?だったので、guvcviewインストールしてみます。

GTK+ UVC Viewer

インストールは以下でOK

$ sudo apt-get install guvcview

インストールするとX側の【サウンドとビデオ】のメニューにも反映されるので、マウスでクリックして起動します。

Xをリモートデスクトップ接続で開いて

f:id:ueponx:20170722065449j:plain

起動すると(オーディオ関連でWarningがたくさんでますが)

f:id:ueponx:20170722065453j:plain

メニューが出ましたというか、あれ?キャプチャ映像のウインドウは?

もしかしたらリモートデスクトップ接続だとだめなのかなと思って、HDMIモニタに接続したところ無事に表示されました。HDMI接続をしているとリモートデスクトップ接続していても、起動はできるようです。(どうも起動時にHDMIを接続している・いないかが関係している様です。) RaspberryPiではこういうことはなかったので多分設定があるんだろうなーと。

f:id:ueponx:20170722065457j:plain

HDMI接続していれば、リモート側にも画面出力は行われる。(ちょっとわかりにくい)

また、デフォルトでも【グラフィックス】のメニューにWebカメラアプリがあったので【ウェブカムビューア】(実体はcamorama)を使って見ると

f:id:ueponx:20170722065445j:plain

f:id:ueponx:20170722065440j:plain

こちらは問題なさそう。

謎すぎる…guvcview起動オプションで対応可能のかもしれない。

あと、RaspberryPiのようにコマンドライン上からraspistillで静止画をキャプチャするようなコマンドが見当たらなかったのでfswebcamをインストールしてみました。

$ sudo apt-get install fswebcam

実行は以下でOK

$ fswebcam sample.jpg
--- Opening /dev/video0...
Trying source module v4l2...
/dev/video0 opened.
No input was specified, using the first.
Adjusting resolution from 384x288 to 352x288.
--- Capturing frame...
Captured frame in 0.00 seconds.
--- Processing captured image...
Writing JPEG image to 'sample.jpg'.

こんな感じで使用はできました。

終わりに

RaspberryPi同様(?)にWebカメラが使用できました。

あとは、pythonとかnode.jsからの使用ができるかが気になるところです。 となるとOpenCVも入れなきゃなあ。

新しく使えるようになったUbuntuのコマンドラインをWindows10上で使う

新しく使えるようになったUbuntuコマンドラインをWindows10上で使う

7/10に「Ubuntu」が“Microsoftストア”でリリースされたそうです。ということでインストールしてみました。

f:id:ueponx:20170713175043p:plain

それだけのエントリーです。Bash on Ubuntu on Windowsとの違いってなんなんですかね?

事前の手順

まず、事前にWindows10 Insider Preview Buildに変更する必要があります。(16215以降でないとだめっぽいそうです。)

つべこべ言わずにInsiderPreviewにすればいいと思います。

f:id:ueponx:20170713181738p:plain

それもまた人生。 f:id:ueponx:20170713174028j:plain

また、UbuntuWindows 10にインストールする場合は、コントロールパネルから【プログラムと機能】を開き、【Windowsの機能の有効化または無効化】を選択、【Windows Subsystem for Linux】にチェックを入れ、一度OSの再起動が必要です。

f:id:ueponx:20170713174009j:plain

ウインドウ左側【Windowsの機能の有効化または無効化】を選択、

f:id:ueponx:20170713173959j:plain

リストから【Windows Subsystem for Linux】にチェックを入れ【OK】ボタンを押すと再起動を促されます。

ストアからインストー

あとはストアからダウンロードします。自分はインストール済みだったので表示が【起動】になっていますが、未インストールであれば【インストール】ボタンが表示されます。

f:id:ueponx:20170713175043p:plain

【インストール】ボタンをクリックするとダイアログが途中で表示されますが、気にする必要はありません。

f:id:ueponx:20170713173825j:plain

終わりにはユーザネームとパスワードが尋ねられます。これでインストール作業は完了です。

f:id:ueponx:20170713201147j:plain

root権限を使う場合にはsudoを使ってねって感じでインストールは完了します。スタートメニューやツールバーに登録もできるのでそこから起動するのが便利ですかね。

f:id:ueponx:20170713201208j:plain

終わりに

とりあえずインストールが完了しました。ssh、gitもデフォルトで使用可能でpython(Version3.5)も一応使えました。gccなんかはないですが、aptが使えるのでそれでインストールすればいいんでしょうか。

ip -aを実行するとインターフェースが多すぎて泣きたくなりました。

後は、ローカルマシンとのディレクトリ構造の対応が分かればまあいいのかなと思ったんですが、できるんでしょうかね。そのうち調べてみたいと思います。(ストアアプリ側にファイルシステムがあるみたいです)

Raspberry PiをFirewall/NAT越しにSSH・RDPをする【ngrok】

Raspberry PiをFirewall/NAT越しにSSH・RDPをする【ngrok】

前回のエントリーに引き続きngrokに関連した話題になります。

uepon.hatenadiary.com

前回の話題でhttphttpsに関しては無事にngrokを経由して公開をおこなうことができました(httpsに関しては言及してませんでしたが、URLは同時に発行されますのでそのまま使用できます。あと、httpなサーバーブログラムでも、ngrok側で対応してくれるようです。)

後はその他のサービスはどうなるかになります。ngrokはレジストしていないとhttp関連しか対応することができないのですが、サービスにユーザ登録を行うと別のサービスなどにも対応することができるというメリットがあります。

ユーザ登録

メインページに行って画面上部の【Login】をクリックします。

f:id:ueponx:20170709115536p:plain

画面が切り替わります。

f:id:ueponx:20170709115551p:plain

メールアドレスやパスワードを使っても新規登録を行うことはできるのですが、Githubアカウントやgoogleアカウントでもログインが可能です。今回はGithubアカウントを使用してみます。画面内の【Login with Github】のボタンをクリックします。

すると、画面が切り替わりログインが完了し(登録状態になります。)、【Get Started】という画面の表示になり自分のサービストークンなどが表示される画面になります。

f:id:ueponx:20170709115602p:plain

この【Get Started】の画面の手順通りに進めます。発行されたトークンを引数に以下のコマンドを実行します。実行すると~/.ngrok2/ngrok.yamlトークン情報が保存されます。CLIで実行する度に指定することもできるのですが面倒なのでこの方法のほうがおすすめです。

$ ./ngrok authtoken 【発行されたAuthkey】
Authtoken saved to configuration file: /home/pi/.ngrok2/ngrok.yml

以降はトークンの指定は自動的に行われます。 後は該当するポートなどを指定してngrokを起動します。

SSH接続を行う

例えば、SSHであればport番号は22でtcp接続になりますので

$ ./ngrok tcp 22

となります。実行するとこんな風な画面になります。

f:id:ueponx:20170709121718j:plain

あとは画面に記載されたForwardingの値を使用して接続をします。 teratermの場合にはログインダイアログで

f:id:ueponx:20170709115717j:plain

【host】と【port番号】を変更します。これで接続はOKです。

RDP接続を行う

RDPであればポート番号は3386になりますので以下のようにします。ネットを検索していたところ、デフォルトではサービスリージョンがus(アメリカ)になってしまうのですが、コマンドラインでサービスリージョンを変更できるようです。(-regionオプションがそれになります)。今回は流れるデータが大きくなるのでap(アジアパシフィック)にしました。

$ ./ngrok tcp -region=ap 3389

となります。

【参考】

qiita.com

情報ありがとうございます。

実行すると以下のような画面になります。RegionもAsia Pacificに変更されているのがわかります。

f:id:ueponx:20170709121734j:plain

これで準備完了です。接続はWindowsリモートデスクトップ接続で行います。xrdpなどはインストールされている前提となります。Forwardingの値を【コンピュータ】のパラメータに設定して【接続】をクリックします。

f:id:ueponx:20170709115744j:plain

vncのログインダイアログが表示されるのでいつも通りログインすれば…

f:id:ueponx:20170709115757j:plain

Xが起動します。まあ、実用できるかというとやっぱり反応はそれほど良くないので、保険のような感じなるのかもしれませんが。

f:id:ueponx:20170709115813j:plain

ちなみにngrokでも接続ステータスもみることができるので色々良さそうです。

f:id:ueponx:20170709115608p:plain

終わりに

ngrokを使用することでローカルの環境を比較的自由にネットワークサービスを公開できるようになりました。あくまでも、デバッグハッカソンなどでの短時間の使用になるかと思います。ご使用にはごくれぐれもご注意ください。

Raspberry PiをFirewall/NAT越しにWebアプリケーションを公開する【ngrok】

Raspberry PiをFirewall/NAT越しにWebアプリケーションを公開する【ngrok】

RaspberryPiなどでWebアプリケーションを使用しているとルータなどの環境ではネットワークのポート開放などをしないとWebアプリケーションの公開ができないというのがちょっと残念なことが多くあります。

以前もSlackのWebhookを使用したbotの作成時にはルータのポート開放をやるのが非常に手間だったという印象です。

先日行った勉強会でngrokというものを教えていただき、この悩みが解決しましたのでメモとしておいておきます。

ngrok.com

Secure tunnels to localhost

簡単にいうとプログラムを起動すると、ngrok.com側に登録し、更にローカルホスト側にサービス経由でトンネルを開けてくれるサービスになります。

インストールの準備

インストールは簡単でバイナリをダウンロードするだけです。RaspberryPiの場合にはLinux ARMをダウンロードすることになります。

上記のリンクにバイナリのダウンロードリンクがあります。

ページにアクセスして

f:id:ueponx:20170708160038p:plain

下にスクロールすると出てきます。

f:id:ueponx:20170708152221p:plain

ダウンロードが終わったら、unzipして展開します。基本的にはこれだけで終了です。Pathの通ったところにコピーするなどすれば便利かと思います。

$ ls
ngrok-stable-linux-arm.zip
$ unzip ngrok-stable-linux-arm.zip
Archive:  ngrok-stable-linux-arm.zip
  inflating: ngrok

起動するかを実験してみます。

$ ./ngrok help
NAME:
   ngrok - tunnel local ports to public URLs and inspect traffic

DESCRIPTION:
    ngrok exposes local networked services behinds NATs and firewalls to the
    public internet over a secure tunnel. Share local websites, build/test
    webhook consumers and self-host personal services.
    Detailed help for each command is available with 'ngrok help <command>'.
    Open http://localhost:4040 for ngrok's web interface to inspect traffic.

EXAMPLES:
    ngrok http 80                    # secure public URL for port 80 web server
    ngrok http -subdomain=baz 8080   # port 8080 available at baz.ngrok.io
    ngrok http foo.dev:80            # tunnel to host:port instead of localhost
    ngrok tcp 22                     # tunnel arbitrary TCP traffic to port 22
    ngrok tls -hostname=foo.com 443  # TLS traffic for foo.com to port 443
    ngrok start foo bar baz          # start tunnels from the configuration file

VERSION:
   2.2.6

AUTHOR:
  inconshreveable - <alan@ngrok.com>

COMMANDS:
   authtoken    save authtoken to configuration file
   credits      prints author and licensing information
   http         start an HTTP tunnel
   start        start tunnels by name from the configuration file
   tcp          start a TCP tunnel
   tls          start a TLS tunnel
   update       update ngrok to the latest version
   version      print the version string
   help         Shows a list of commands or help for one command

実験してみる

基本的には

ngrok 【プロトコル】 【portナンバー】

と実行すれば大丈夫です。 例えば、httpをポート80で公開するのであれば

$ ngrok http 80

となります。実行してみます。

今回は次の様に実行してみます。

$ ngrok http 8080

f:id:ueponx:20170708153553j:plain

実行するとこのような画面になります。赤く四角のある部分にはランダムな文字列がngrok側から発行されます。このURLにアクセスを行うと公開ができるようになります。(もちろん、8080ポートに対応したプログラムがないと失敗しますので注意です)

では、アクセスの実験を行います。 サーバとしてはpythonのSimpleHTTPServerモジュールを使用します。

ngrokを起動したコンソールとは別のものを開いて以下の様に起動します。(-mはモジュール起動の際に必要になります)

$ python -m SimpleHTTPServer 8080

これで準備OKです。あとはクライアント側からアクセスを行います。まずはローカル環境からのアクセスを行ってみます。更にクライアント用のコンソールを開きcurlコマンドを使用してアクセスしてみます。実行すると以下の様になると思います。(実行するとサーバ側のカレントディレクトリ一覧が表示されるます。)

$ curl http://localhost:8080
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /</title>
<body>
<h2>Directory listing for /</h2>
<hr>
<ul>
<li><a href=".bash_history">.bash_history</a>
<li><a href=".bash_logout">.bash_logout</a>
<li><a href=".bashrc">.bashrc</a>
<li><a href=".cache/">.cache/</a>
<li><a href=".config/">.config/</a>
【中略】
</ul>
<hr>
</body>
</html>

【実行画面】 f:id:ueponx:20170708155249j:plain

ローカルでのテストがうまくいったので、今度はngrok経由でアクセスを行います。ngrok起動時に表示されたURLに対してアクセスを行います。(*********はランダムな文字列です)

$ curl http://********.ngrok.io
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /</title>
<body>
<h2>Directory listing for /</h2>
<hr>
<ul>
<li><a href=".bash_history">.bash_history</a>
<li><a href=".bash_logout">.bash_logout</a>
<li><a href=".bashrc">.bashrc</a>
<li><a href=".cache/">.cache/</a>
<li><a href=".config/">.config/</a>
【中略】
</ul>
<hr>
</body>
</html>

【実行画面】 f:id:ueponx:20170708154030j:plain

無事にアクセスしデータが取得できたと思います。

アクセスはngrokプロセス側にも以下の様に表示されます。

f:id:ueponx:20170708155501j:plain

終わりに

ngrokを使用することでRaspberryPiで作成したWebアプリケーションを容易に公開することができました。開発時やハッカソンなどで短時間で公開したい場合にはかなり有効かなと思います。

ngrokはユーザ登録しない場合にはhttp(https)しか使用できませんが、ユーザ登録を行うとSSHやRDPなども使用できるようです。次回はそのあたりも行ってみようと思います。