ASUS tinker boardのMali T764をOpenCV 3.3.1のOpenCLで酷使してみる

# はじめに
この記事は[OpenCV Advent Calendar 2017](https://qiita.com/advent-calendar/2017/opencv)の3日目の記事です。他の記事は[目次](https://qiita.com/advent-calendar/2017/opencv)にまとめられています。

# ASUS tinker board とは？
[ASUS Tinker Board](https://www.asus.com/jp/Single-board-Computer/tinker-board/)は、RK3288(Cortex-A17/Mali T764)を搭載した、SBC[^sbc]です。**OpenCL FullProfile** が使えるので、Umatを使うと**GPGPU**で画像処理できることが期待されます!! 
以上を鑑みて、**安価なSBCで、OpenCLでの高速化の恩恵があずかれるか確認してみました。**

[^sbc]: [single board computer](https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%B3%E3%82%B0%E3%83%AB%E3%83%9C%E3%83%BC%E3%83%89%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF)の略。Raspberry PiのようにCPU/Memory等をオンボードし、単体で動作可能になっているコンピュータボード。 

## 方法
OpenCVのソースコードでOpenCLのカーネルがある関数の中から、Sobel/Canny/cvtColorを対象とした。読み込み済み画像に当該関数の処理をする関数の呼び出しを100回を繰り返した処理時間の平均値を、代表値として用いる。[^1][^2]

[^1]: 今回はGPU側にやや不利な条件として、毎回CPUから画像転送する形でテストを行う。実際には１画像に対して複数のフィルタをかけるため、これよりも負荷は低くなることが予想される。
[^2]: Cannyの場合、GPUを叩いてくれなかったことが分かったので、泣く泣く結果から除外しました。

## 処理時間とCPU負荷
左図はMatで処理する時の時間を1,00とした場合の、処理時間比較、小さいほど早い（左ほど早い）。
右図はCPU使用率。小さいほど、CPUに負荷をかけていない（左ほど軽い）。

- Sobel(CV_16S)
 - CPU負荷軽減できるが（30%->5%)、個々の処理時間は伸びてしまう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/89434/45472dab-23f2-d120-7de3-893a30b22abc.png)

- Sobel(CV_8U) 2017/12/3 9:50 更新
 - だんでらいおん先生に指摘され、再度コードを見直したところ、 ` cv::Sobel(u_src, u_dst, CV_8U, 1, 0); ` とあるべきところが、` cv::Sobel(u_src, u_dst, CV_16S, 1, 0); ` になっていることが判明。やり直したところ、こちらもGPUのほうが早い＋CPU負荷も小さい、となりました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/89434/fa386504-d96c-e434-be87-1c4e865197b4.png)

- cvtColor(BGR2GRAY)
 - cvtColor(BGR2GRAY)は、処理時間はほぼ変わらずに、CPU負荷をかなり軽減できる（40%->10%)。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/89434/f9b74091-e2d4-2bc9-befa-1d562ab9f8eb.png)
 
- cvtColor(BGR2HSV)
 - cvtColor(BGR2HSV)は、CPU負荷軽減できるうえに（80%->10%)、個々の処理時間も短縮できる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/89434/cdb0defa-a243-4759-5757-840fdaaf5b01.png)

##GPUを使った場合のオーバーヘッド
オーバーヘッドを観測するために、cvtColor(RGB2HSV)を実行した時のそれぞれの処理時間をグラフ化してみる。なお、実装は「同一プロセス内」で行われている（毎回再起動しているわけではない）。

- 初回実行時には、300msほどかかり、平均性能を引き下げる。
- ２回目以後については、カーネルコンパイル済みであるため、そのオーバーヘッドが軽減されている。
- 最終的にはCPU性能と同等以上の処理時間にまで短縮している。（そのうえ、CPU負荷も低い）。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89434/10e6b895-b951-9053-59ee-6c6bc4f927de.png)


# まとめ
**SBC環境でも、(一部機能であれば)、OpenCLによって処理負荷軽減・高速化できることが確認できた！** OpenCL FullProfile対応のSBCが今後も増えていくと、据え置き型デバイスのみならず、可搬デバイスにまでOpenCVの活用範囲が広がることが期待できます。

更に、現在、[Raspberry pi上でもOpenCLが使えるように検討をしている方](https://www.raspberrypi.org/forums/viewtopic.php?t=194952) もいます。RasPi ZERO上のOpenCVでもそこそこの性能が出せるようになる事に強い期待を持ち、本アドベントカレンダーのまとめとします（つまり、来年はほぼこの内容でRaspiを検討すれば１日分の記事に…？）。

明日は、[tomoaki_teshima](https://twitter.com/tomoaki_teshima)  さんの投稿で、執筆時点でのタイトルは **「OpenCVのコマンドラインパーサ」** です！コマンドラインのオプションに対する処理、移植性まで考えると面倒ですよね！CUI大好きおじさんとしては大いにワクワクしています！

# Appendix
## データ概略
> linaro@tinkerboard:~/work$ jpeginfo lena.jpg
> lena.jpg  512 x 512  24bit JFIF  N   91814
> linaro@tinkerboard:~/work$ jpeginfo nakau.jpg
> nakau.jpg 1920 x 1080 24bit Exif  P  684309
> linaro@tinkerboard:~/work$ jpeginfo matsuya.jpg
> matsuya.jpg 3264 x 2448 24bit Exif  N 1364147

## 実験環境
- tinker board
 - CPU
  - Quad core Cortex-A17 1.8GHz
  - CPUの速度固定( `$ sudo cpupower frequency-set -g performance ` )
 - GPU
 -  600 MHz Mali-T760 MP4
 - GPUの速度固定( `# echo "performance" > /sys/devices/platform/ffa30000.gpu/devfreq/ffa30000.gpu/governor ` )
- OpenCV 3.3.1
 - pthreadによる並列化が行われている