高斯濾波在項目裏很常用,尤其是SIFT特徵點提取的時候,PCA也要用。
但是原始的高斯濾波是一個二維的卷積,速度很慢。即使採用優化後的分離高斯濾波(先在x方向濾波,然後在y方向濾波),依然不快。
查閱了很多國內外的文獻,在項目中實現了遞歸高斯濾波, 已經量產運行,效果很不錯,運行時間是分離高斯濾波的三分之一到四分之一, 也可以運行到MCU裏了!!
遞歸濾波器能近似模擬高斯濾波器,也是分成兩次一維濾波,但是不需要設定濾波窗口大小,複雜度跟窗口大小無關,對於一維濾波先進行一次正向濾波,然後進行一次逆向濾波,每次濾波的結果迭代更新。
公式如下:
Forward:
Backward:
代碼實現:
- typedef struct
- {
- gint scale;
- gint nscales;
- gint scales_mode;
- gfloat cvar;
- } RetinexParams;
- /*
- * Calculate the coefficients for the recursive filter algorithm
- * Fast Computation of gaussian blurring.
- */
- static void
- compute_coefs3 (gauss3_coefs *c, gfloat sigma)
- {
- /*
- * Papers: "Recursive Implementation of the gaussian filter.",
- * Ian T. Young , Lucas J. Van Vliet, Signal Processing 44, Elsevier 1995.
- * formula: 11b computation of q
- * 8c computation of b0..b1
- * 10 alpha is normalization constant B
- */
- gfloat q, q2, q3;
- q = 0;
- if (sigma >= 2.5)
- {
- q = 0.98711 * sigma - 0.96330;
- }
- else if ((sigma >= 0.5) && (sigma < 2.5))
- {
- q = 3.97156 - 4.14554 * (gfloat) sqrt ((double) 1 - 0.26891 * sigma);
- }
- else
- {
- q = 0.1147705018520355224609375;
- }
- q2 = q * q;
- q3 = q * q2;
- c->b[0] = (1.57825+(2.44413*q)+(1.4281 *q2)+(0.422205*q3));
- c->b[1] = ( (2.44413*q)+(2.85619*q2)+(1.26661 *q3));
- c->b[2] = ( -((1.4281*q2)+(1.26661 *q3)));
- c->b[3] = ( (0.422205*q3));
- c->B = 1.0-((c->b[1]+c->b[2]+c->b[3])/c->b[0]);
- c->sigma = sigma;
- c->N = 3;
- /*
- g_printerr ("q %f\n", q);
- g_printerr ("q2 %f\n", q2);
- g_printerr ("q3 %f\n", q3);
- g_printerr ("c->b[0] %f\n", c->b[0]);
- g_printerr ("c->b[1] %f\n", c->b[1]);
- g_printerr ("c->b[2] %f\n", c->b[2]);
- g_printerr ("c->b[3] %f\n", c->b[3]);
- g_printerr ("c->B %f\n", c->B);
- g_printerr ("c->sigma %f\n", c->sigma);
- g_printerr ("c->N %d\n", c->N);
- */
- }
- static void
- gausssmooth (gfloat *in, gfloat *out, gint size, gint rowstride, gauss3_coefs *c)
- {
- /*
- * Papers: "Recursive Implementation of the gaussian filter.",
- * Ian T. Young , Lucas J. Van Vliet, Signal Processing 44, Elsevier 1995.
- * formula: 9a forward filter
- * 9b backward filter
- * fig7 algorithm
- */
- gint i,n, bufsize;
- gfloat *w1,*w2;
- /* forward pass */
- bufsize = size+3;
- size -= 1;
- w1 = (gfloat *) g_try_malloc (bufsize * sizeof (gfloat));
- w2 = (gfloat *) g_try_malloc (bufsize * sizeof (gfloat));
- w1[0] = in[0];
- w1[1] = in[0];
- w1[2] = in[0];
- for ( i = 0 , n=3; i <= size ; i++, n++)
- {
- w1[n] = (gfloat)(c->B*in[i*rowstride] +
- ((c->b[1]*w1[n-1] +
- c->b[2]*w1[n-2] +
- c->b[3]*w1[n-3] ) / c->b[0]));
- }
- /* backward pass */
- w2[size+1]= w1[size+3];
- w2[size+2]= w1[size+3];
- w2[size+3]= w1[size+3];
- for (i = size, n = i; i >= 0; i--, n--)
- {
- w2[n]= out[i * rowstride] = (gfloat)(c->B*w1[n] +
- ((c->b[1]*w2[n+1] +
- c->b[2]*w2[n+2] +
- c->b[3]*w2[n+3] ) / c->b[0]));
- }
- g_free (w1);
- g_free (w2);
- }
注意邊界的處理,這對結果很重要。