Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
Halideによる画像処理について
saturday06
March 27, 2017
Programming
2
2k
Halideによる画像処理について
saturday06
March 27, 2017
Tweet
Share
More Decks by saturday06
See All by saturday06
HLSの遅延を350ms+ネットワーク遅延分まで削減する
saturday06
3
2.1k
Other Decks in Programming
See All in Programming
【Qiita Night】新卒エンジニアによるSwift6与太予想
eiji127
0
170
Named Document って何?
harunakano
0
360
アプリのログをチーム外で活用してもらうためにやったこと
shotakashihara
0
170
2022 Android Training
mixi_engineers
1
660
コードの解析と言語習得の心得
jinjin33333
0
130
Learning DDD輪読会#4 / Learning DDD Book Club #4
suzushin54
1
130
TSDサービスRecap ~PMBOK®ガイド第7版超速まるわかりガイド~|ミツエーリンクスTSD
mlctsd
0
100
Android入門
hn410
0
300
You CANt teach an old dog new tricks
michaelbukachi
0
110
Reinventing the wheel ... as a service
mariofusco
3
240
Language Summit 2022: WebAssembly: Python in the browser and beyond
tiran
2
310
Kueue入門/Kueue Introduction
bells17
0
510
Featured
See All Featured
The Straight Up "How To Draw Better" Workshop
denniskardys
225
120k
Visualization
eitanlees
124
11k
Music & Morning Musume
bryan
35
4.1k
Embracing the Ebb and Flow
colly
73
3.3k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
3
430
Three Pipe Problems
jasonvnalue
89
8.6k
Building Better People: How to give real-time feedback that sticks.
wjessup
343
17k
The MySQL Ecosystem @ GitHub 2015
samlambert
238
11k
Automating Front-end Workflow
addyosmani
1351
200k
Designing on Purpose - Digital PM Summit 2013
jponch
106
5.6k
Fireside Chat
paigeccino
11
1.2k
JazzCon 2018 Closing Keynote - Leadership for the Reluctant Leader
reverentgeek
172
8.3k
Transcript
Halideによる 画像処理について 2017/03/14 ピクシブ株式会社 茂木 勇
目次 - Halide概要 - Halideでぼかし処理 - Halideで画像縮小処理 - ベンチマーク
Halideとは? - C++の画像処理ライブラリ - 「ハロゲン化合物」という意味 - ライブラリではあるが「ハイパフォーマンスな画像処理を行うことができる新しい言 語」と名乗っている - 開発者「1500行のマルチスレッドとアセンブラで最適化されたPhotoshopのとある
フィルタのC++のコードを3ヶ月で10倍高速化した」 - http://halide-lang.org/assets/lectures/Halide_CVPR_intro.pdf
None
None
Halideの特徴 - C++の文法で数式を記述し、Halideが内部に持っているLLVMでコンパイルするこ とで画像処理用の関数を生成する - 数式自体をコンパイル、最適化をするので「縮小して輝度を上げる」など複数の画 像処理を組み合わせた際にパフォーマンスが向上する可能性がある - SSE,AVX,NEON等CPUのSIMD命令及びCUDA,OpenCLなどGPUを使った最適 化に対応している。
- CPU用に書いた処理をほとんど変更せず GPUでも動かせる
例: 近傍4ピクセルを使ったぼかし処理 blur(x, y) = (src(x-1,y) + src(x,y-1) + src(x,y)
+ src(x+1,y) + src(x,y+1))/5
例: 近傍4ピクセルを使ったぼかし処理(Halide版) Func src = …; Func blur; Var x,
y; blur(x, y) = (src(x-1,y)+src(x,y-1)+src(x,y)+src(x+1, y)+src(x,y+1))/5;
例: 近傍4ピクセルを使ったぼかし処理(Halide版) Func src = BoundaryConditions::repeat_edge(...); Func blur; Var x,
y; blur(x, y) = (src(x-1,y)+src(x,y-1)+src(x,y)+src(x+1, y)+src(x,y+1))/5; 画像端のデータを繰り返す
例: 近傍4ピクセルを使ったぼかし処理(Halide版) ImageParam input(type_of<uint8_t>(), 2); Func src = BoundaryConditions::repeat_edge(input); Func
blur; Var x, y; blur(x, y) = (src(x-1,y)+src(x,y-1)+src(x,y)+src(x+1, y)+src(x,y+1))/5; 入力画像データの定義
例: 近傍4ピクセルを使ったぼかし処理(Halide版) ImageParam input(type_of<uint8_t>(), 2); Func src = BoundaryConditions::repeat_edge(input); Func
blur; Var x, y; blur(x, y) = (src(x-1,y)+src(x,y-1)+src(x,y)+src(x+1, y)+src(x,y+1))/5; blur.compile_to_static_library("blur", {input}); これらを内部のLLVMで コンパイルして、 Cのライブラリとして出力
例: 近傍4ピクセルを使ったぼかし処理(Halide版) #include <Halide.h> int main() { using namespace Halide;
ImageParam input(type_of<uint8_t>(), 2); Func src = BoundaryConditions::repeat_edge(input); Func blur; Var x, y; blur(x, y) = (src(x-1,y)+src(x,y-1)+src(x,y)+src(x+1, y)+src(x,y+1))/5; blur.compile_to_static_library("blur", {input}); return 0; }
#include <Halide.h> int main() { using namespace Halide; ImageParam input(type_of<uint8_t>(),
2); Func src = BoundaryConditions::repeat_edge(input); Func blur; Var x, y; blur(x, y) = (src(x-1,y)+src(x,y-1)+src(x,y)+src(x+1, y)+src(x,y+1))/5; blur.compile_to_static_library("blur", {input}); return 0; } 例: 近傍4ピクセルを使ったぼかし処理(Halide版)
#include <Halide.h> int main() { using namespace Halide; ImageParam input(type_of<uint8_t>(),
2); Func src = BoundaryConditions::repeat_edge(input); Func blur; Var x, y; blur(x, y) = (src(x-1,y)+src(x,y-1)+src(x,y)+src(x+1, y)+src(x,y+1))/5; blur.compile_to_static_library("blur", {input}); return 0; } 例: 近傍4ピクセルを使ったぼかし処理(Halide版)
例: 近傍4ピクセルを使ったぼかし処理(Halide版) ImageParam input(type_of<uint8_t>(), 2); Func src = BoundaryConditions::repeat_edge(input); Func
blur; Var x, y; blur(x, y) = (src(x-1,y)+src(x,y-1)+src(x,y)+src(x+1, y)+src(x,y+1))/5;
例: 近傍4ピクセルを使ったぼかし処理(Halide版) ImageParam input(type_of<uint8_t>(), 2); Func src = BoundaryConditions::repeat_edge(input); Func
blur; Var x, y; blur(x, y) = (src(x-1,y)+src(x,y-1)+src(x,y)+src(x+1, y)+src(x,y+1))/5; 画素値は8bit整数のため 足し算結果がオーバーフローしている
例: 近傍4ピクセルを使ったぼかし処理(Halide版) ImageParam input(type_of<uint8_t>(), 2); Func src = BoundaryConditions::repeat_edge(input); Func
blur; Var x, y; blur(x, y) = src(x-1,y)/5+src(x,y-1)/5+src(x,y)/5+src(x+1, y)/5+src(x,y+1)/5; オーバーフローしにくいように修正 (型変換とかもできる)
#include <Halide.h> int main() { using namespace Halide; ImageParam input(type_of<uint8_t>(),
2); Func src = BoundaryConditions::repeat_edge(input); Func blur; Var x, y; blur(x, y) = src(x-1,y)/5+src(x,y-1)/5+src(x,y)/5+src(x+1, y)/5+src(x,y+1)/5; blur.compile_to_static_library("blur", {input}); return 0; } 例: 近傍4ピクセルを使ったぼかし処理(Halide版)
blur(x, y) = src(x-1,y)/5+src(x,y-1)/5+src(x,y)/5+src(x+1, y)/5+src(x,y+1)/5; blur.gpu_tile(x, y, 16, 16); auto
target = Halide::get_host_target(); target.set_feature(Target::OpenCL); blur.compile_to_static_library("blur", {input}, "", target); return 0; } 例: 近傍4ピクセルを使ったぼかし処理(Halide版) GPU使う場合
画像縮小処理 - pixivではサムネイル作成用の画像縮小にffmpeg(libswscale) を用いているが、幾つかの問題点があり乗り換え先を検討し ている - 高速で、高品質な縮小処理が求められている - halideが代わりとして使えないか?
例: Nearest Neighber法による画像縮小処理 縮小
例: Nearest Neighber法による画像縮小処理 out(out_x, out_y) = in(nearest_in_x(out_x),nearest_in_y(out_y)) in画像 out画像
例: Nearest Neighber法による画像縮小処理(Halide) out(out_x, out_y) = in(nearest_in_x(out_x),nearest_in_y(out_y))
例: Nearest Neighber法による画像縮小処理(Halide) Func out; Var out_x, out_y; out(out_x, out_y)
= in(nearest_in_x(out_x),nearest_in_y(out_y)) 出力変数、関数定義
例: Nearest Neighber法による画像縮小処理(Halide) ImageParam in(type_of<uint8_t>(), 2); Param<uint32_t> out_width, out_height; Func
out; Var out_x, out_y; out(out_x, out_y) = in(nearest_in_x(out_x),nearest_in_y(out_y)) 入力画像、出力サイズ 定義
例: Nearest Neighber法による画像縮小処理(Halide) ImageParam in(type_of<uint8_t>(), 2); Param<uint32_t> out_width, out_height; Func
nearest_in_x; Var x; nearest_in_x(x) = x * in.width() / out_width; Func out; Var out_x, out_y; out(out_x, out_y) = in(nearest_in_x(out_x),nearest_in_y(out_y)) 「最近傍のx座標を取得」関数定義
例: Nearest Neighber法による画像縮小処理(Halide) ImageParam in(type_of<uint8_t>(), 2); Param<uint32_t> out_width, out_height; Func
nearest_in_y; Var y; nearest_in_y(y) = y * in.height() / out_height; Func nearest_in_x; Var x; nearest_in_x(x) = x * in.width() / out_width; Func out; Var out_x, out_y; out(out_x, out_y) = in(nearest_in_x(out_x),nearest_in_y(out_y)) 「最近傍のy座標を取得」関数定義
例: Nearest Neighber法による画像縮小処理(Halide) #include <Halide.h> int main() { using namespace
Halide; ImageParam in(type_of<uint8_t>(), 2); Param<uint32_t> out_width, out_height; Func nearest_in_x; Var x; nearest_in_x(x) = (x * in.width() + out_width / 2) / out_width; Func nearest_in_y; Var y; nearest_in_y(y) = (y * in.height() + out_height / 2) / out_height; Func out; Var out_x, out_y; out(out_x, out_y) = BoundaryConditions::repeat_edge(in)(nearest_in_x(out_x), nearest_in_y(out_y)); out.compile_to_static_library("nearest_neighber", {in, out_width, out_height}); return 0; } 現実の問題に対するワークアラウンドとか追加
例: Nearest Neighber法による画像縮小処理(Halide) #include <Halide.h> int main() { using namespace
Halide; ImageParam in(type_of<uint8_t>(), 2); Param<uint32_t> out_width, out_height; Func nearest_in_x; Var x; nearest_in_x(x) = (x * in.width() + out_width / 2) / out_width; Func nearest_in_y; Var y; nearest_in_y(y) = (y * in.height() + out_height / 2) / out_height; Func out; Var out_x, out_y; out(out_x, out_y) = BoundaryConditions::repeat_edge(in)(nearest_in_x(out_x), nearest_in_y(out_y)); out.compile_to_static_library("nearest_neighber", {in, out_width, out_height}); return 0; } in画像
例: Nearest Neighber法による画像縮小処理(Halide) #include <Halide.h> int main() { using namespace
Halide; ImageParam in(type_of<uint8_t>(), 2); Param<uint32_t> out_width, out_height; Func nearest_in_x; Var x; nearest_in_x(x) = (x * in.width() + out_width / 2) / out_width; Func nearest_in_y; Var y; nearest_in_y(y) = (y * in.height() + out_height / 2) / out_height; Func out; Var out_x, out_y; out(out_x, out_y) = BoundaryConditions::repeat_edge(in)(nearest_in_x(out_x), nearest_in_y(out_y)); out.compile_to_static_library("nearest_neighber", {in, out_width, out_height}); return 0; } in画像 out画像
ベンチマーク 内容: サイズ1600x3200のグレースケール画像を320x480に様々な方式で縮小 環境: MacBook Pro (Retina, 15-inch, Mid 2015)
Processor Name: Intel Core i7 Processor Speed: 2.2 GHz Total Number of Cores: 4 Memory: 16 GB GPU: Intel Iris Pro 1536 MB
ベンチマーク結果(小さい値だとより良い) Benchmark Time CPU ------------------------------------------------------- HalideResizeNearestNeighber 2083577 ns 2081819 ns
HalideResizeBilinear 10228914 ns 10225705 ns HalideResizeGpuBilinear 947467 ns 736395 ns FfmpegResizeFastBilinear 1418483 ns 1416548 ns FfmpegResizeBilinear 6036412 ns 6033964 ns FfmpegResizeLanczos3 18074324 ns 18070590 ns
Halideの特徴(再掲) - C++の文法で数式を記述し、Halideが内部に持っているLLVMでコンパイルするこ とで画像処理用の関数を生成する - 数式自体をコンパイル、最適化をするので「縮小して輝度を上げる」など複数の画 像処理を組み合わせた際にパフォーマンスが向上する可能性がある - x86,arm等CPUのSIMD命令及びCUDA、OpenCLを使った最適化に対応してい る。
- CPU用に書いた処理をほとんど変更せず GPUでも動かせる
ベンチマーク2 内容: サイズ1600x3200のグレースケール画像をネガポジ変換をして から320x480にバイリニア法で縮小
ベンチマーク結果2(小さい値だとより良い) Benchmark Time CPU ----------------------------------------------------------- HalideResizeBilinear 10228914 ns 10225705 ns
HalideNegateResizeBilinear 10417060 ns 10413506 ns FfmpegResizeBilinear 6036412 ns 6033964 ns OpenCVNegateFfmpegResizeBilinear 9038528 ns 9036810 ns
ベンチマーク結果まとめ - FFmpegのような職人芸コードに比べて速度60%くらいのコードが生成される - GPUにオフロードすることで、CPUでは実現不可能な速度で処理ができる - GPUの職人芸にどのくらい及んでいるのかはまだ未検証 - 数式DSLを内部のLLVMでコンパイルするため、複数の画像処理を組み合わせた際 には職人芸コードの組み合わせよりも高速なコードが生成される可能性がある