OpenCV-2.3.2-GPU-demo-pack-win32を試す

久々の投稿ですがSourceforgのOpenCVのページにGPUデモのプログラムが公開されていました。

http://sourceforge.net/projects/opencvlibrary/files/opencv-win/2.3.1/

 

バージョンもOpenCV2.3.2 って、まだ公開されていないのに...

 

で早速、このファイルをダウンロードし、試してみました。

私の環境は

OS:Windows7 64bit (ただし、サンプルは32bit動作)

CPU:Core i7 870 (2.93GHz)

GPU:NVIDIA GeForce GTX470

 

で、パフォーマンス評価用のサンプル(demo_performance.exe)を実行した時の結果がこちら↓

CPU msec   GPU msec   SPEEDUP   DESCRIPTION
matchTemplate
480 5 x86.5 src 3000, templ 5, 32F, CCORR
545 21 x24.9  src 3000, templ 25, 32F, CCORR
792 31 x25.4  src 3000, templ 5, 32F, CCORR
minMaxLoc
7  1  x4.81  src 2000, 32F, no mask
28  2  x14.3  src 4000, 32F, no mask
 106  3  x28.2  src 8000, 32F, no mask
 remap   
 8  0  x35.9  src 1000,8UC1
 30  0  x50.6  src 2000,8UC1
 124  2  x59.1  src 4000,8UC1
 12  0  x32.2  src 1000,8UC3
 42  1  x34.6  src 2000,8UC3
 164  4  x34.7  src 4000,8UC3
 11  0  x37.8  src 1000,8UC4
 40  0  x41.4  src 2000,8UC4
 156  3  x43.7  src 4000,8UC4
 29  0  x79.7  src 1000,16SC3
 117  1  x88.8  src 2000,16SC3
 481  4  x98.1  src 4000,16SC3
 dft   
 107  3  x29.2  size 1000, 32FC2, complex-to complex
 402 8  x45.3  size 2000, 32FC2, complex-to complex
 1781  32  x55.4  size 4000, 32FC2, complex-to complex
 cornerHarris
 129  19  x6.55  size 2000, 32F
 499  70  x7.06  size 4000, 32F
 integral
28 15 x1.82  size 4000, 8U
20 9 x2.04  size 4000, 8U
20 9 x2.11  size 4000, 8U
21 9 x2.2  size 4000, 8U
21 9 x2.15  size 4000, 8U
norm
139 5 x27.3 size 2000, 32FC4, NORM_INF
310 8 x35.2 size 3000, 32FC4, NORM_INF
555 14 x38.2 size 4000, 32FC4, NORM_INF
meanShift
304 8 x36.3  size 400, 8UC3 vs 8UC4
1187 29 x40.2  size 800, 8UC3 vs 8UC4
SURF
5179 117 x43.9
BruteForceMatcher
1230 8 x144 match
1257 9 x136 knnMatch, 2
1301 9 x139 knnMatch, 3
1220 9 x135 radiusMatch
magnitude
41 0 x86 size 2000
88 1 x85 size 3000
162 1 x95 size 4000
add
10 0 x20.1 size 2000, 32F
22 1 x21.4 size 3000, 32F
41 1 x23.9 size 4000, 32F
log
25 0 x55.8 size 2000, 32F
54 0 x66.1 size 3000, 32F
97 1 x71.3 size 4000, 32F
exp
25 0 x53 size 2000, 32F
58 0 x73.7 size 3000, 32F
10 1 x74.6 size 4000, 32F
mulSpectrums
24 0 x53 size 2000, 32F
58 0 x73.7 size 3000, 32F
101 1 x74.6 size 4000, 32F
resize
7 0 x33.5 size 1000, 8UC1, up
28 0 x50.4 size 2000, 8UC1, up
64 1 x53.3 size 3000, 8UC1, up
2 0 x26.6 size 1000, 8UC1, down
8 0 x51.6 size 2000, 8UC1, down
18 0 x94.6 size 3000, 8UC1, down
21 2 x8.5 size 1000, 8UC3, up
82 8 x10.2 size 2000, 8UC3, up
187 17 x10.9 size 3000, 8UC3, up
7 0 x13.8 size 1000, 8UC3, down
26 1 x23.8 size 2000, 8UC3, down
58 1 x32.7 size 3000, 8UC3, down
27 1 x17.1 size 1000, 8UC4, up
108 4 x26 size 2000, 8UC4, up
250 9 x27.5 size 3000, 8UC4, up
9 0 x14.6 size 1000, 8UC4, down
32 0 x37.4 size 1000, 8UC4, down
73 1 x52 size 1000, 8UC4, down
9 2 x4.72 size 1000, 32FC1, up
41 6 x6.25 size 2000, 32FC1, up
88 13 x6.45 size 3000, 32FC1, up
2 0 x4.92 size 1000, 32FC1, down
10 0 x12.1 size 2000, 32FC1, down
23 1 x17.2 size 3000, 32FC1, down
cvtColor
29 0 x37.1 size 4000, CV_GRAY2BGRA
82 1 x61.8 size 4000, CV_BGR2YCrCb
105 1 x71.3 size 4000, CV_YCrCb2BGR
123 1 x84.4 size 4000, CV_BGR2XYZ
116 1 x83.7 size 4000, CV_XYZ2BGR
195 2 x72.9 size 4000, CV_BGR2HSV
550 2 x189 size 4000, CV_HSV2BGR
erode 
9 3 x2.65 size 2000
22 7 x3.07 size 3000
39 11 x3.35 size 4000
threshold   
0 0  x1.62 size 1000, 8U, THRESH_BINARY
1 0  x6.15 size 2000, 8U, THRESH_BINARY
3 0  x11.1 size 3000, 8U, THRESH_BINARY
6 0  x11.4 size 4000, 8U, THRESH_BINARY
1 0  x7.49 size 1000, 32F, THRESH_BINARY
6 0  x18.8 size 2000, 32F, THRESH_BINARY
14 0  x19.6 size 3000, 32F, THRESH_BINARY
25 1  x21.9 size 4000, 32F, THRESH_BINARY
pow   
5 0 x32.9 size 1000, 32F
20 0 x57.1 size 2000, 32F
44 0 x58.2 size 3000, 32F
83 1 x55.8 size 4000, 32F
projectPoints
49 2 x23.3 size 1000000
37 2 x16.1 size 714285
26 1 x24.5 size510203
19 0 x20.9 size 364430
12 0 x21.6 size 230307
solvePnPRansac
217 118 x1.84 num_points 5000
392 120 x3.25 num_points 18800
1315 127 x10.3 num_points 70688
4984 160 x31 num_points 265786
GaussianBlur
1  0 x4.26 8UC1, size 1000
6  1 x5.61 8UC1, size 2000
14  2 x6.08 8UC1, size 3000
24  3 x6.36 8UC1, size 4000
5  0 x7.57 8UC4, size 1000
24  2 x10.2 8UC4, size 2000
56  4 x11.8 8UC4, size 3000
100  8 x11.7 8UC4, size 4000
2  0 x5.16 32FC1, size 1000
8  1 x7.39 32FC1, size 2000
17  2 x7.6 32FC1, size 3000
33  3 x8.63 32FC1, size 4000
pryDown
18 5 x3.55 8UC1, size 4000
10 2 x3.62 8UC1, size 3000
4 1 x3.41 8UC1, size 2000
1 0 x2.74 8UC1, size 1000
64 6 x9.52 8UC3, size 4000
38 3 x10 8UC3, size 3000
16 1 x9.26 8UC3, size 2000
4 0 x7.71 8UC3, size 1000
66 7 x8.98 8UC4, size 4000
38 4 x9.14 8UC4, size 3000
17 2 x6.36 8UC4, size 2000
4 0 x7.98 8UC4, size 1000
107 6 x15.6 16SC4, size 4000
60 3 x15.6 16SC4, size 3000
26 1 x14.9 16SC4, size 2000
7 0 x10.2 16SC4, size 1000
29 5 x5.7 32FC1, size 4000
17 3 x5.92 32FC1, size 3000
7 1 x5.65 32FC1, size 2000
1 0 x4.62 32FC1, size 1000
88 6 x13 32FC3, size 4000
52 3 x13.8 32FC3, size 3000
22 1 x12.7 32FC3, size 2000
5 0 x4.92 32FC3, size 1000
122 7 x17 32FC4, size 4000
67 4 x16.9 32FC4, size 3000
30 1 x16.6 32FC4, size 2000
7 0 x14.4 32FC4, size 1000
pyrUp
51 5 x8.97 8UC1, size 2000
12 1 x8.52 8UC1, size 1000
145 8 x17.3 8UC3, size 2000
36 2 x16.5 8UC3, size 1000
198 11 x17.6 8UC4, size 2000
48 2 x16.7 8UC4, size 1000
170 8 x19.6 16SC3, size 2000
44 2 x20.1 16SC3, size 1000
69 5 x12.2 32FC1, size 2000
17 1 x11.4 32FC1, size 1000
205 7 x27.3 32FC3, size 2000
21 1 x26.2 32FC3, size 1000
equalizeHist
2 1 x1.93 size 1000
10 2 x4.78 size 2000
23 3 x6.37 size 3000
Canny
29 3  x9.63
reduce
1 0 x7.79 size 1000, dim = 0
1 0 x10.1 size 1000, dim = 1
6 0 x14.5 size 2000, dim = 0
6 0 x25.2 size 2000, dim = 1
13 0 x17.5 size 3000, dim = 0
13 0 x29.3 size 3000, dim = 1

average GPU speedup: x29.202

 

sizeの表記は、size1000の場合、画像サイズは1000×1000となります。

 

一般的にGPUを使った画像処理ではメモリの転送時間がかかり処理時間トータルでは、あまり高速化されない

と言われる場合も多いので、ソースコードを見てみないと、いまいち結果をそのまま信用できない...

でも、とりあえずは、そこそこ速そうな結果でした

 

ソースコードは こちら

https://code.ros.org/trac/opencv/changeset/6950?utm_source=twitterfeed&utm_medium=twitter

 

OpenCVへ戻る

 

最小二乗法の最適化(高速化)

最小二乗法を用いて曲線近似するとき、近似するX座標の値が等間隔に並んでいる場合、奇関数、偶関数の特性を使って最小二乗法を高速に処理することが可能になります。

 

例えば、画像中の線の中心位置や、エッジの位置をサブピクセル単位で求める場合などに有効です。

 

 

以下からは線の輝度値を2次曲線で近似して、線の中心を求める例を示します。

 

X方向の輝度値が最大となる座標付近の輝度値を抜き出し、2次式で近似すると
X座標が180と181との間に最大値がありそうな事が分かります。

 

 

この輝度値を二次式(Y = aX2 + bX + c)で近似する場合、下記の行列の式を解くと二次式が求まります。

 

 

ここで、逆行列の中は奇関数、偶関数の集まりなので、輝度値データのX座標を中心座標(X = 180.5)で割り振ると

 

 

となります。
よって、奇関数、偶関数の特性から、行列の式は

 

 

となり、行列の計算量を減らすことができます。

 

また、近似するデータの個数が固定できるなら、逆行列の部分はあらかじめ計算しておく事ができるので、さらに計算量を減らすことができます。

 

これで、求める線の中心座標は近似曲線の頂点位置、つまり微分の値が0となる座標(Y’ = 0の座標)なので、

線の中心座標 = Xの中心座標 – b / 2a
(今回の例ではXの中心座標 = 180.5)

 

となり、より高速に線の中心座標を求めることができるようになります。

 

この前提条件とした『X座標の値が等間隔に並んでいる場合』という部分ですが、画像処理においては、画素のX座標、Y座標を用いて、輝度値に関して近似する場合が多いので、for文などで、ある関数の総和などを求める場合には、この奇関数・偶関数が使えないか?検討してみると良いと思います。

 

このテクニックは計算量が格段に少なくなるので、効果的な場合が多いと思います。

 

使える数学へ戻る

 

フィルタ処理の高速化アルゴリズム(縦横に処理を分ける)

前回、フィルタ処理の高速化アルゴリズム(重複した計算を行わない)で紹介した方法ではカーネルの値が全て同じでないと使えないので、今回はフィルタ処理を縦方向と横方向に分けて行う事でフィルタ処理の高速化を行う方法をガウシアンフィルタを例にとって紹介します。

 

ガウシアンフィルタのカーネルには、

 

が良く用いられますが、この処理を注目画素の周辺の輝度値をI0~I8とした場合、
ガウシアンフィルタの処理を行列で

 

と、表すこともでき、この事は縦方向に3×1のガウシアンフィルタ処理をおこなってから、
横方向に1×3のガウシアンフィルタ処理を行うことを意味しています。
(横方向に処理をしてから縦方向に処理をしても同じです。)

 

このように処理を縦と横に分けることで、カーネルのサイズm×nの場合、通常の処理では
m×n回の掛け算を行うところ、m+n回の掛け算で済む事になります。
(ただし、縦横に処理を分ける事で全画素を2回参照することになるので、カーネルのサイズが
小さいと効果はあまりありません。)

他にも、移動平均フィルタの場合

ソーベルフィルタの場合

 

となります。
ソーベルフィルタの行列を見ると、縦方向にガウシアンフィルタ処理をしてから、横方向に微分処理している事が分かりやすくなっているかと思います。

 

また、比較的処理の重いメディアンフィルタにおいても、処理を縦と横に分けることによって、
ほぼ、同様な効果を得ることができます。
厳密には同じ結果にはならないのですが、スパイクノイズを除去するという意味では
十分な結果を得る事が出来ます。

試しに何回か、メディアンフィルタ処理を縦方向に1列分の処理を行ってから、横方向に1列分の
処理を行ってみましたが、ほぼ、良好な結果を得る事ができていると思います。
(画像にするともう少し分かりやすいかと思いますが、プログラムが無いもので...)

 

 

画像処理アルゴリズムへ戻る

 

フィルタ処理の高速化アルゴリズム(重複した計算を行わない)

画像フィルタ処理の高速化のテクニックを移動平均フィルタを例にとって紹介したいと思います。

 

カーネルのサイズが5×5の移動平均フィルタの場合、注目画素の周辺の5×5の輝度値を合計し、
その輝度値の合計を画素数(5×5=25)で割る処理をラスタスキャンしながら、全画素に対して
処理を行います。

 

 

ここで、隣の画素へ処理が移った時に、輝度値の合計の計算処理は前に行った輝度値の合計の
処理とかなりかぶっている(下図の緑色の部分)事に気が付きます。

 

 

そこで、最初の輝度値の平均値を計算をした時の輝度値の合計値を保持しておき、最初の輝度値の
合計値から、最初のカーネルの左端の1列分の輝度値(上図の赤色の部分)を引き、
次のカーネルの右端の1列分の輝度値(上図の青色の部分)を足すと、次のカーネル内の
輝度値の合計値を求める事が出来ます。

 

そうすると、カーネル内の輝度値の合計の計算に25回の足し算をしていたところ、5回の引き算と
5回の足し算の計10回の計算で済ませることが分かります。
この効果はカーネルサイズが大きくなればなる程、大きくなります。

 

さらに画像の1行分の合計値を確保するメモリを確保しておくと、縦方向に関しても同様の処理が
できるので、高速化が期待できます。

 

と、今回は画像のフィルタ処理を例にとって紹介していますが、この考え方は他にもいろいろと
応用が効くので、輝度値の合計の計算に留まらず、毎回同じような処理をしているな~と思ったら、
前回行った処理の使いまわしができないか?検討してみると良いでしょう。

 

画像処理アルゴリズムへ戻る