LoginSignup
33
36

More than 5 years have passed since last update.

Raspbian Stretch+NCS(Neural Compute Stick)+YoloV2+Webカメラ+ROSによるリアルタイム複数動体検知環境の構築

Last updated at Posted at 2017-12-10

I wrote it in English in the comment section.

◆ はじめに

Raspberry Pi 3 model B+ へ、タイトル記載のディープラーニング(DeepLearning)環境をインストール・構築する。
OSを導入するところからのクリーンな状態での作業を前提とし、初期状態から着手すれば、ほぼコピー&ペーストだけでつまづくことなく完了するはず。

ごちゃごちゃするのは好きではないため、pyenv, virtualenv は使用しない。
パーミッションの設定は適当とし、セキュリティは特に考慮しない。
同じパッケージを何度も導入しようとしているところ、無駄なパッケージをインストールしようとしているところはご愛敬で。
ノーミス・ノンストップで走っても半日以上かかるのでかなりの覚悟が必要。
ちなみに、Intel が公開しているNCS導入スクリプトはそのままではopenCVがまともに入らないので注意。
Stretchは初回起動時にSDのパーティション拡張を自動で実行してくれるため、Jessieより若干手順が楽。
SSHで作業している場合は、時間の掛かるスクリプト部分でターミナルがタイムアウトしてしまうことが多いため、Raspberry Pi→HDMI→ディスプレイ、の直接接続構成での作業をお勧めする。
ezgif-3-e1cfe20787.gif

次回は、Neural Compute Stickの3本挿し(Multi Stick構成)を試そうと思う。
結果だけ言うと1本でも次回の実装のほうが遥かに動作が速い。
https://qiita.com/PINTO/items/7f13fcb7c894c27691b2

次次回の実装は次回の実装より更に2倍速く動作する。
https://qiita.com/PINTO/items/db3ab44a3e2bcd87f2d8

そして更に上記のどれよりも速く高精度なMobileNet-SSDによる実装。
HW構成次第ではRaspberryPiで10FPS以上を達成。
https://qiita.com/PINTO/items/b97b3334ed452cb555e2

Raspbian JessieにてNCS無しの類似構成でSingle Shot MultiBox Detector環境を構築した前回の記事はこちら。
https://qiita.com/PINTO/items/bbf5ff907966f213fbdf

◆ 環境 [2017.12.11時点]

・Windows 10 Pro [作業用PC] + TeraTerm
・Raspberry Pi 3 model B+
・Intel Movidius Neural Compute Stick  https://developer.movidius.com/
・Raspbian Stretch 2017-11-29
・NCS SDK v1.11.00.04 → [2018.01.10 VerUp] v1.12.00
・ROS kinetic 1.12.11
・samba 4.2.14
・Python 2.7.13、3.5.3(OS標準導入済)
・Tensorflow 1.4.0
・Keras 2.1.2(今回は使わないのでお好みで)
・OpenCV 3.3.1 → [2018.01.12 VerUp] 3.4.0
・Jupyter notebook(今回は使わないのでお好みで)
・MicroSD Card class10 SDHC 32GB
・USBキーボード、USBマウス、液晶テレビ、HDMIケーブル
・インターネット接続可能な有線LAN 又は Wi-Fi環境

◆ Raspbian stretch のインストール

1.下記をダウンロード
http://ftp.jaist.ac.jp/pub/raspberrypi/raspbian/images/raspbian-2017-12-01/2017-11-29-raspbian-stretch.zip
2.ダウンロードされたzipを解凍
3.Win32DiskImagerをダウンロードしてインストール https://ja.osdn.net/projects/sfnet_win32diskimager/downloads/Archive/win32diskimager-1.0.0-install.exe/
4.SDカードをホストPCに挿入/接続
5.Win32DiskImagerを起動し、2017-11-29-raspbian-stretch.imgを指定して書き込み
6.Raspberry Pi 3 へSDカードを挿入して電源ON
7.スタートメニュー→設定→RaspberryPiの設定→インタフェース→必要なオプションを「有効」にする
8.スタートメニュー→設定→RaspberryPiの設定→ローカライゼーション
 (1)ロケールの設定「ja」「JP」「UTF-8」
 (2)タイムゾーン「Asia」「Tokyo」
 (3)キーボードの設定「日本」「日本語」
 (4)無線LANの国「JP Japan」
9.Wi-Fiの省電力モード無効化

$ sudo iwconfig wlan0 power off

10.rootユーザのパスワード設定

$ sudo passwd root ※好きなパスワードを登録

◆ ROS [kinetic]のインストール

1.下記のコマンドを実行

$ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
$ wget https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -O - | sudo apt-key add -
$ sudo apt-get update
$ sudo apt-get -y upgrade
$ sudo apt-get install -y python-rosdep python-rosinstall-generator python-wstool python-rosinstall build-essential cmake
$ sudo apt-get install -y python-pip python-setuptools python-yaml python-distribute python-docutils python-dateutil python-six
$ sudo rosdep init
$ rosdep update
$ mkdir -p ~/ros_catkin_ws
$ pushd ~/ros_catkin_ws
$ rosinstall_generator ros_comm common_msgs tf --rosdistro kinetic --deps --wet-only --tar > kinetic-ros_comm-wet.rosinstall
$ wstool init src kinetic-ros_comm-wet.rosinstall
$ rosdep install -y --from-paths src --ignore-src --rosdistro kinetic -r --os=debian:stretch
$ sudo ./src/catkin/bin/catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release --install-space /opt/ros/kinetic -j2
$ popd
$ echo "source /opt/ros/kinetic/setup.bash" >> ~/.bashrc
$ source ~/.bashrc
$ sudo reboot

◆ 環境変数の追加

1.下記のコマンドを実行

$ export ROS_HOSTNAME=raspberrypi.local
$ export ROS_IP=`hostname -I`
$ export ROS_MASTER_URI=http://192.168.xxx.xxx:11311

※`hostname -I`の部分はPCのホスト名を入力するのではなく、hostnameとそのままの文脈で入力する
※RaspberryPi側でマスターを起動する場合は、export ROS_MASTER_URI=http://`hostname -I`:11311
※上記の環境変数を削除する場合は、unset ROS_MASTER_URI
※RaspberryPi以外の端末をマスターとする場合はIP部分を読み替える

 例)リモートのUbuntuをマスターとする場合は、Ubuntu側で下記を追加
   PC起動のたびに下記コマンドを打つ必要があるため、~/.bashrcに書いておくと良い

   $ export ROS_HOSTNAME=ubuntu.local
   $ export ROS_IP=`hostname -I`
   $ export ROS_MASTER_URI=http://`hostname -I`:11311

◆ Sambaのインストール

1.下記のコマンドを実行

$ sudo apt-get install -y samba
$ sudo nano /etc/samba/smb.conf

2.設定ファイル(smb.conf)に下記を追記して保存

[pi]
path = /home/pi
read only = No
guest ok = Yes
force user = pi

[etc]
path = /etc
read only = No
guest ok = Yes
force user = root

[usr]
path = /usr
read only = No
guest ok = Yes
force user = root

[tmp]
path = /tmp
read only = No
guest ok = Yes
force user = root

[opt]
path = /opt
read only = No
guest ok = Yes
force user = root

3.sambaのデーモンを再起動する

$ sudo service smbd restart

◆ TMP領域の拡張とログファイルのRAMDISK化

1.下記のコマンドを実行

$ cd /etc
$ sudo cp fstab fstab_org
$ sudo nano /etc/fstab

2.ファイルの末尾に下記を追記して保存

# TMP領域の拡張
tmpfs /tmp tmpfs defaults,size=512m,noatime,mode=1777 0 0
tmpfs /var/tmp tmpfs defaults,size=128m,noatime,mode=1777 0 0
# /var/log をRAMディスクにマウント
tmpfs /var/log tmpfs defaults,size=32m,noatime,mode=0755 0 0
# ~/.ros/log をRAMディスクにマウント
tmpfs /home/pi/.ros/log tmpfs defaults,size=32m,noatime,mode=1777 0 0

3.Raspberry Piを再起動

$ sudo reboot

◆ 無用なシステムログの無効化

1.下記コマンドを実行

$ cd /etc
$ sudo cp rsyslog.conf rsyslog.conf_org
$ sudo nano rsyslog.conf

2.下記のように書き換えて保存する

###############
#### RULES ####
###############

#
# First some standard log files.  Log by facility.
#
auth,authpriv.*                 /var/log/auth.log
*.*;auth,authpriv.none          -/var/log/syslog
#cron.*                         /var/log/cron.log
daemon.*                        -/var/log/daemon.log
#kern.*                         -/var/log/kern.log
#lpr.*                          -/var/log/lpr.log
#mail.*                         -/var/log/mail.log
#user.*                         -/var/log/user.log

#
# Logging for the mail system.  Split it up so that
# it is easy to write scripts to parse these files.
#
#mail.info                      -/var/log/mail.info
#mail.warn                      -/var/log/mail.warn
#mail.err                       /var/log/mail.err

◆ Raspberry Pi起動時にログ出力先フォルダを自動生成するよう変更

1.下記コマンドを実行

$ cd /etc
$ sudo cp rc.local rc.local_org
$ sudo nano rc.local

2.既に入力済みの部分を下記のように書き換えて保存する

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

# 
# RAMディスクに自動的にフォルダを追加
# 
mkdir -p /var/log/ConsoleKit
mkdir -p /var/log/samba
mkdir -p /var/log/fsck
mkdir -p /var/log/apt
mkdir -p /var/log/ntpstats
#chown root.ntp /var/log/ntpstats
chown root.adm /var/log/samba
touch /var/log/lastlog
touch /var/log/wtmp
touch /var/log/btmp
chown root.utmp /var/log/lastlog
chown root.utmp /var/log/wtmp
chown root.utmp /var/log/btmp

exit 0

◆SWAP領域の一時的な拡張 2018/03/17追記

これを実施しておかないとOpenCVのビルド時にスワップが大量に発生してフリーズする、かつ SWAP領域が不足してビルド中に異常終了する、 かつ ビルドが1日経っても終わらない。ビルドのシーケンスとdf -hコマンド、free -hコマンドの状況を張り付いて見ていたところ、OpenCVビルド時にはMEM:1GB + SWAP:1GB以上消費するようだ。単位はMB。

$ sudo nano /etc/dphys-swapfile
CONF_SWAPSIZE=2048

$ sudo /etc/init.d/dphys-swapfile restart swapon -s
$ free -h

◆ 必要なパッケージの一部分インストール

1.下記のコマンドを実行する

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install -y build-essential libc6-dev libncurses5-dev libncursesw5-dev libreadline6-dev libdb5.3-dev
$ sudo apt-get install -y libgdbm-dev libsqlite3-dev libssl-dev libbz2-dev libexpat1-dev liblzma-dev zlib1g-dev
$ sudo apt-get install -y cmake git pkg-config unzip qtbase5-dev python-dev python3-dev python-numpy python3-numpy
$ sudo apt-get install -y cmake-qt-gui mesa-utils libgl1-mesa-dri libprotobuf-dev protobuf-compiler libvtk6-dev
$ sudo apt-get install -y libvtk6-qt-dev python-vtk6 tcl-vtk6 libopencv-dev libgtk-3-dev libdc1394-22 libdc1394-22-dev
$ sudo apt-get install -y libjpeg-dev libpng12-dev libtiff5-dev libjasper-dev libavcodec-dev libavformat-dev
$ sudo apt-get install -y libswscale-dev libxine2-dev libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libv4l-dev
$ sudo apt-get install -y libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev
$ sudo apt-get install -y libxvidcore-dev v4l-utils gfortran python-opencv libgtk2.0-dev libx264-dev libqt5core5a
$ sudo apt-get install -y libqtgui4 libqt4-test libqt4-opengl-dev libatlas-base-dev libeigen3-dev libtesseract-dev
$ sudo apt-get install -y libleptonica-dev tesseract-ocr tesseract-ocr-jpn tesseract-ocr-osd libblas-dev liblapack-dev
$ sudo apt-get install -y python-setuptools python3-decorator python3-scipy python3-pandas python3-h5py libhdf5-dev libpq5 libpq-dev apt-show-versions ffmpeg
$ sudo reboot
$ sudo pip3 install h5py;sudo pip3 install imageio;sudo apt-get update;sudo apt-get upgrade;sudo apt-get clean;
$ sudo apt-get clean;sudo pip3 install --upgrade pillow
$ sudo apt-get clean;sudo pip3 install --upgrade matplotlib
$ sudo apt-get update;sudo apt-get upgrade
$ sudo reboot

◆ Python3.x版 Tensorflow1.4.0のインストール

1.下記のコマンドを実行

$ cd ~
$ mkdir tensorflow1.4.0;cd tensorflow1.4.0
$ wget https://github.com/lhelontra/tensorflow-on-arm/releases/download/v1.4.0/tensorflow-1.4.0-cp35-none-linux_armv7l.whl
$ sudo pip3 install tensorflow-1.4.0-cp35-none-linux_armv7l.whl
$ sudo apt-get update;sudo apt-get upgrade
$ python3
>>> import tensorflow
>>> exit()

◆TBB (Intel Threading Building Blocks)の導入 2018/03/17追記

毎度ビルドするのが面倒なため、お手軽導入用パッケージを作った。
OpenCVの並列処理対応用。
あえて自分でビルドしたい物好きな人はこちらの手順
https://github.com/PINTO0309/TBBonARMv7/blob/master/TBB_BuildProcedure_2018U2_arm.txt

【導入による効果】
OpenCVの並列化クラスParallelLoopBodyとparallel_for_ - Qiita
C++17時代の並列ソート - Qiita

1.TBB(2018 U2)インストール用debファイルのダウンロード

$ cd ~
$ wget https://github.com/PINTO0309/TBBonARMv7/raw/master/libtbb-dev_2018U2_armhf.deb

2.下記のコマンドを実行してインストール

$ sudo dpkg -i ~/libtbb-dev_2018U2_armhf.deb
$ sudo ldconfig

◆ Neural Compute Stick SDKのインストール

1.Neural Compute Stick をRaspberry PiのUSBポートへ挿入する
※Raspberry PiのUSBポート残りの3個のうち1個は、Neural Compute Stickの横幅が太いため挿せなくなる。
※常時4ポート使用したい場合はUSBハブの追加を検討する。
※このタイミングでNeural Compute Stickを挿しておかないと後続のビルドに失敗する、ように見える。
※処理途中に表示されるWarningは無視してもかまわない。

2.Neural Compute Stick SDKのインストール
【参考】https://movidius.github.io/ncsdk/install.html

$ cd ~
$ git clone https://github.com/movidius/ncsdk.git
$ cd ~/ncsdk
$ nano ./install-opencv.sh

3.下記のように、ファイル中盤あたりに記載されているopenCV周りの記述を変更して保存
※バックスラッシュ「\」は「半角の¥」に読み替える。
※この部分はOpenCVを単体でインストールしたい時のシーケンスとしてもそのまま使える。

                cd ~
                wget -O opencv.zip https://github.com/Itseez/opencv/archive/3.4.0.zip
                unzip opencv.zip
                wget -O opencv_contrib.zip https://github.com/Itseez/opencv_contrib/archive/3.4.0.zip
                unzip opencv_contrib.zip
                cd ~/opencv-3.4.0/
                mkdir build
                cd build
                cmake -D CMAKE_CXX_FLAGS="-DTBB_USE_GCC_BUILTINS=1 -D__TBB_64BIT_ATOMICS=0" \
                      -D CMAKE_BUILD_TYPE=RELEASE \
                      -D CMAKE_INSTALL_PREFIX=/usr/local \
                      -D INSTALL_PYTHON_EXAMPLES=OFF \
                      -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib-3.4.0/modules \
                      -D BUILD_EXAMPLES=OFF \
                      -D PYTHON_DEFAULT_EXECUTABLE=$(which python3) \
                      -D INSTALL_PYTHON_EXAMPLES=OFF \
                      -D BUILD_opencv_python2=ON \
                      -D BUILD_opencv_python3=ON \
                      -D WITH_OPENCL=OFF \
                      -D WITH_OPENGL=OFF \
                      -D WITH_TBB=ON \
                      -D BUILD_TBB=OFF \
                      -D WITH_CUDA=OFF \
                      -D ENABLE_NEON:BOOL=ON \
                      -D WITH_QT=OFF \
                      -D BUILD_opencv_dnn_modern=OFF ..
                make -j $(($(nproc) + 1))
                sudo make install
                sudo ldconfig

4.下記のコマンドを実行
make examples で openCV3.4.0/opencv_contrib3.4.0 が自動でフルインストールされる、ワーニングが4~5件表示されるが無視してよし

$ make install
$ make examples
$ sudo /bin/bash -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf'
$ sudo /bin/bash -c 'echo "/usr/lib" >> /etc/ld.so.conf.d/opencv.conf'
$ sudo ldconfig
$ sudo apt-get update
$ cd ~;sudo rm opencv.zip;sudo rm opencv_contrib.zip
$ python3
>>> import cv2
>>> exit()

$ sudo reboot

◆ Keras2.1.2インストール

1.下記のコマンドを実行

 $ sudo pip3 install keras

2.実行確認、importしてエラーが出なければ正常

$ python3
>>> import keras
Using TensorFlow backend.
>>> exit()

◆ Jupyter notebookのインストール

1.下記のコマンドを実行

$ cd ~
$ git clone https://github.com/kleinee/jns.git
$ cd jns
$ sudo chmod +x *.sh
$ sudo pip3 install jupyter;sudo pip3 install readline;sudo pip3 install ipyparallel
$ ./configure_jupyter.sh
$ sudo ./install_tex.sh;sudo ./install_stack.sh;

2.Jupyterのインストール先パス確認
※ 表示されたパスは後続の作業で使用 (1)

$ which jupyter

3.Jupyter notebookの自動起動設定

$ sudo nano /etc/systemd/system/jupyter.service

※空のファイルが開かれるので下記のとおり入力して保存(notebookの左側のパスを(1)で置き換え)

[Unit]
Description=Jupyter notebook

[Service]
Type=simple
PIDFile=/var/run/jupyter-notebook.pid
ExecStart=/usr/local/bin/jupyter notebook  ←(1)
User=pi
Group=pi
WorkingDirectory=/home/pi/notebooks
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

4.下記のコマンドを実行

$ sudo systemctl start jupyter;sudo systemctl enable jupyter;sudo systemctl status jupyter
$ sudo reboot

◆ Jupyter notebook動作確認

1.操作用PCのブラウザから「http://(Raspberry PiのIPアドレス):8888/」にアクセス
2.ログインパスワード:jns

◆ 後始末

1.下記コマンドを実行

$ sudo apt-get autoremove
$ sudo apt-get clean

◆ Webカメラ + YoloV2 での複数動体検出環境の導入と味見

1.下記のコマンドを実行

$ cd ~
$ git clone https://github.com/duangenquan/YoloV2NCS.git
$ cd YoloV2NCS
$ nano ~/YoloV2NCS/src/PythonWrapper.cpp
※下記のとおり編集して保存。
    //long buflen;
    int buflen;
$ make
$ mvNCCompile ./models/caffemodels/yoloV2Tiny20.prototxt -w ./models/caffemodels/yoloV2Tiny20.caffemodel -s 12
$ cd detectionExample
$ mkdir utils
$ nano app_utils.py

2.下記のソースを全コピペ

app_utils.py
# From http://www.pyimagesearch.com/2015/12/21/increasing-webcam-fps-with-python-and-opencv/

import struct
import six
import collections
import cv2
import datetime
from threading import Thread
from matplotlib import colors


class FPS:
    def __init__(self):
        # store the start time, end time, and total number of frames
        # that were examined between the start and end intervals
        self._start = None
        self._end = None
        self._numFrames = 0

    def start(self):
        # start the timer
        self._start = datetime.datetime.now()
        return self

    def stop(self):
        # stop the timer
        self._end = datetime.datetime.now()

    def update(self):
        # increment the total number of frames examined during the
        # start and end intervals
        self._numFrames += 1

    def elapsed(self):
        # return the total number of seconds between the start and
        # end interval
        return (self._end - self._start).total_seconds()

    def fps(self):
        # compute the (approximate) frames per second
        return self._numFrames / self.elapsed()


class WebcamVideoStream:
    def __init__(self, src, width, height):
        # initialize the video camera stream and read the first frame
        # from the stream
        #print(src)
        self.stream = cv2.VideoCapture(src)
        self.stream.set(cv2.CAP_PROP_FRAME_WIDTH, width)
        self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
        (self.grabbed, self.frame) = self.stream.read()

        # initialize the variable used to indicate if the thread should
        # be stopped
        self.stopped = False

    def start(self):
        # start the thread to read frames from the video stream
        Thread(target=self.update, args=()).start()
        return self

    def update(self):
        # keep looping infinitely until the thread is stopped
        while True:
            # if the thread indicator variable is set, stop the thread
            if self.stopped:
                return

            # otherwise, read the next frame from the stream
            (self.grabbed, self.frame) = self.stream.read()

    def read(self):
        # return the frame most recently read
        return self.frame

    def stop(self):
        # indicate that the thread should be stopped
        self.stopped = True


def standard_colors():
    colors = [
        'AliceBlue', 'Chartreuse', 'Aqua', 'Aquamarine', 'Azure', 'Beige', 'Bisque',
        'BlanchedAlmond', 'BlueViolet', 'BurlyWood', 'CadetBlue', 'AntiqueWhite',
        'Chocolate', 'Coral', 'CornflowerBlue', 'Cornsilk', 'Crimson', 'Cyan',
        'DarkCyan', 'DarkGoldenRod', 'DarkGrey', 'DarkKhaki', 'DarkOrange',
        'DarkOrchid', 'DarkSalmon', 'DarkSeaGreen', 'DarkTurquoise', 'DarkViolet',
        'DeepPink', 'DeepSkyBlue', 'DodgerBlue', 'FireBrick', 'FloralWhite',
        'ForestGreen', 'Fuchsia', 'Gainsboro', 'GhostWhite', 'Gold', 'GoldenRod',
        'Salmon', 'Tan', 'HoneyDew', 'HotPink', 'IndianRed', 'Ivory', 'Khaki',
        'Lavender', 'LavenderBlush', 'LawnGreen', 'LemonChiffon', 'LightBlue',
        'LightCoral', 'LightCyan', 'LightGoldenRodYellow', 'LightGray', 'LightGrey',
        'LightGreen', 'LightPink', 'LightSalmon', 'LightSeaGreen', 'LightSkyBlue',
        'LightSlateGray', 'LightSlateGrey', 'LightSteelBlue', 'LightYellow', 'Lime',
        'LimeGreen', 'Linen', 'Magenta', 'MediumAquaMarine', 'MediumOrchid',
        'MediumPurple', 'MediumSeaGreen', 'MediumSlateBlue', 'MediumSpringGreen',
        'MediumTurquoise', 'MediumVioletRed', 'MintCream', 'MistyRose', 'Moccasin',
        'NavajoWhite', 'OldLace', 'Olive', 'OliveDrab', 'Orange', 'OrangeRed',
        'Orchid', 'PaleGoldenRod', 'PaleGreen', 'PaleTurquoise', 'PaleVioletRed',
        'PapayaWhip', 'PeachPuff', 'Peru', 'Pink', 'Plum', 'PowderBlue', 'Purple',
        'Red', 'RosyBrown', 'RoyalBlue', 'SaddleBrown', 'Green', 'SandyBrown',
        'SeaGreen', 'SeaShell', 'Sienna', 'Silver', 'SkyBlue', 'SlateBlue',
        'SlateGray', 'SlateGrey', 'Snow', 'SpringGreen', 'SteelBlue', 'GreenYellow',
        'Teal', 'Thistle', 'Tomato', 'Turquoise', 'Violet', 'Wheat', 'White',
        'WhiteSmoke', 'Yellow', 'YellowGreen'
    ]
    return colors


def color_name_to_rgb():
    colors_rgb = []
    for key, value in colors.cnames.items():
        colors_rgb.append((key, struct.unpack('BBB', bytes.fromhex(value.replace('#', '')))))
    return dict(colors_rgb)


def draw_boxes_and_labels(
        boxes,
        classes,
        scores,
        category_index,
        instance_masks=None,
        keypoints=None,
        max_boxes_to_draw=20,
        min_score_thresh=.5,
        agnostic_mode=False):
    """Returns boxes coordinates, class names and colors

    Args:
      boxes: a numpy array of shape [N, 4]
      classes: a numpy array of shape [N]
      scores: a numpy array of shape [N] or None.  If scores=None, then
        this function assumes that the boxes to be plotted are groundtruth
        boxes and plot all boxes as black with no classes or scores.
      category_index: a dict containing category dictionaries (each holding
        category index `id` and category name `name`) keyed by category indices.
      instance_masks: a numpy array of shape [N, image_height, image_width], can
        be None
      keypoints: a numpy array of shape [N, num_keypoints, 2], can
        be None
      max_boxes_to_draw: maximum number of boxes to visualize.  If None, draw
        all boxes.
      min_score_thresh: minimum score threshold for a box to be visualized
      agnostic_mode: boolean (default: False) controlling whether to evaluate in
        class-agnostic mode or not.  This mode will display scores but ignore
        classes.
    """
    # Create a display string (and color) for every box location, group any boxes
    # that correspond to the same location.
    box_to_display_str_map = collections.defaultdict(list)
    box_to_color_map = collections.defaultdict(str)
    box_to_instance_masks_map = {}
    box_to_keypoints_map = collections.defaultdict(list)
    if not max_boxes_to_draw:
        max_boxes_to_draw = boxes.shape[0]
    for i in range(min(max_boxes_to_draw, boxes.shape[0])):
        if scores is None or scores[i] > min_score_thresh:
            box = tuple(boxes[i].tolist())
            if instance_masks is not None:
                box_to_instance_masks_map[box] = instance_masks[i]
            if keypoints is not None:
                box_to_keypoints_map[box].extend(keypoints[i])
            if scores is None:
                box_to_color_map[box] = 'black'
            else:
                if not agnostic_mode:
                    if classes[i] in category_index.keys():
                        class_name = category_index[classes[i]]['name']
                    else:
                        class_name = 'N/A'
                    display_str = '{}: {}%'.format(
                        class_name,
                        int(100 * scores[i]))
                else:
                    display_str = 'score: {}%'.format(int(100 * scores[i]))
                box_to_display_str_map[box].append(display_str)
                if agnostic_mode:
                    box_to_color_map[box] = 'DarkOrange'
                else:
                    box_to_color_map[box] = standard_colors()[
                        classes[i] % len(standard_colors())]

    # Store all the coordinates of the boxes, class names and colors
    color_rgb = color_name_to_rgb()
    rect_points = []
    class_names = []
    class_colors = []
    for box, color in six.iteritems(box_to_color_map):
        ymin, xmin, ymax, xmax = box
        rect_points.append(dict(ymin=ymin, xmin=xmin, ymax=ymax, xmax=xmax))
        class_names.append(box_to_display_str_map[box])
        class_colors.append(color_rgb[color.lower()])
    return rect_points, class_names, class_colors

3../detectionExample/Main.py をWebカメラ対応のロジックに変更

$ cd ..
$ cp ./detectionExample/Main.py ./detectionExample/Main_BK.py
$ nano ./detectionExample/Main.py

4.下記のソースを全コピペ

Main.py
import sys,os,time,csv,getopt,cv2,argparse
import numpy as np
from datetime import datetime

from ObjectWrapper import *
from Visualize import *

from utils.app_utils import FPS, WebcamVideoStream

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--graph', dest='graph', type=str,
                        default='graph', help='MVNC graphs.')
    parser.add_argument('-src', '--source', dest='video_source', type=int,
                        default=0, help='Device index of the camera.')
    parser.add_argument('-wd', '--width', dest='width', type=int,
                        default=400, help='Width of the frames in the video stream.')
    parser.add_argument('-ht', '--height', dest='height', type=int,
                        default=300, help='Height of the frames in the video stream.')

    args = parser.parse_args()

    network_blob=args.graph

    detector = ObjectWrapper(network_blob)

    video_capture = WebcamVideoStream(src=args.video_source,
                                      width=args.width,
                                      height=args.height).start()

    # image preprocess
    img = video_capture.read()

    while True:
        results = detector.Detect(img)

        imdraw = Visualize(img, results)
        cv2.imshow('Demo',imdraw)
        #print(datetime.now())

        key = cv2.waitKey(1)
        if key == ord('q'):
            break
        img = video_capture.read()

video_capture.stop()
cv2.destroyAllWindows()

5.WEBカメラ (UVC [USB Video Class] 対応のもの) をRaspberry PiのUSBポートへ接続

6.動体検知の実行テスト、下記コマンドを実行

$ startx   ← CLIモードで作業中のときのみ実行、GUIモードへ切り替え、SSHで作業していないときは無視
$ cd ~/YoloV2NCS   ← GUI側(Desktop側)の「端末」アプリで実行
$ python3 ./detectionExample/Main.py   ← GUI側(Desktop側)の「端末」アプリで実行

◆SWAP領域の縮小

$ sudo nano /etc/dphys-swapfile
CONF_SWAPSIZE=100

$ sudo /etc/init.d/dphys-swapfile restart swapon -s

◆ TMP領域の縮小

1.下記のコマンドを実行

$ cd /etc
$ sudo nano /etc/fstab

2.ファイルの下記の箇所を変更して保存

tmpfs /tmp tmpfs defaults,size=32m,noatime,mode=1777 0 0
tmpfs /var/tmp tmpfs defaults,size=32m,noatime,mode=1777 0 0

3.下記のコマンドを実行

$ sudo reboot

◆ おまけ

(1) 実行時にSWAP領域が不足した場合は下記実施

$ sudo nano /etc/dphys-swapfile
CONF_SWAPSIZE=1024

$ sudo /etc/init.d/dphys-swapfile restart swapon -s

(2) SDカード長寿命化のためSWAPを無効化

1.下記のコマンドを実行

$ free
$ sudo swapoff --all
$ sudo apt-get remove dphys-swapfile
$ sudo reboot

(3) Python3 コマンドを Python コマンドへ誘導する設定

1.下記のコマンドを実行

$ sudo nano ~/.bashrc

2.下記一行をファイルの一番下に追記

alias python=python3

3.下記コマンドを実行

$ source ~/.bashrc

4.下記コマンドを実行、PythonコマンドでPython3が起動するようになる

$ python
>>>

(4) Ubuntu 16.04 amd64,x86/x64用 TBB(2018 U2) debパッケージ

deb: https://drive.google.com/open?id=1MyaI9dgTO47_18HeVjmycC2zZeE46rdo
ビルドシーケンス: https://drive.google.com/open?id=10FbuthIF2EEDilN1j0RoK-InmPKNYb_A

33
36
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
36