"真理本身之所以是真理,就在於它穿透了語言的有限性而將人帶入到對真實世界的直觀把握中。"
——http://my1510.cn/article.php?id=69054
最近在做sparse coding, 用Bruno Olshausen最原始的方法, 因此卻發現了一些背後直感上更接近真理的東西。中間有一步需要通過得到的sparse響應重建輸入映像,之前一直是用Matlab for迴圈直接解決的,但是速度奇慢,於是今天嘗試了一下把這一部分加速。
首先考慮的是fft2->ifft2的方法,代碼如下(參考了http://www.mathworks.com/matlabcentral/newsreader/author/121671):
% Load imageimage = im2double(imread('./data/lena.png'));% image=image(201:240,201:240);[M N] = size(image);figure(101),subplot(1,2,1),imshow(image,[]);% Here filter should be a 7x7 patchfilter = reshape(A(:,2),[7,7]);% Get the filtered response in fft2F=fft2(image);H=fft2(filter,M,N);G=H.*F;Gnew= G./H;gnew=real(ifft2(double(Gnew)));figure(101),subplot(1,2,2),imshow(gnew,[]);
出來的結果是正常。
但由於sparse coding的方法並不是直接利用濾波後響應而是將這個響應離散化並且在時間上積累(可以看成是神經元
的membrane potential隨著spike的輸入而增高)
我實際implement的code是
% Load imageimage = im2double(imread('./data/lena.png'));% image=image(201:240,201:240);[M N] = size(image);figure(101),subplot(1,2,1),imshow(image,[]);% Here filter should be a 7x7 patchfilter = reshape(A(:,2),[7,7]);% Get the filtered response in fft2F=fft2(image);H=fft2(filter,M,N);G=H.*F;% for ISTA or LCA algorithmg=real(ifft2(double(G)));g=g/10;g=max(abs(g)-0.01,0).*sign(g);G=fft2(g);Gnew= G./H;gnew=real(ifft2(double(Gnew)));figure(101),subplot(1,2,2),imshow(gnew,[]);
結果出來的結果就如中間一幅所示,與用filter乘以sparse響應重建的有一定差距
圖1,原圖(左), fft2->ifft2結果(中), sparse coding直接重建結果(右)
所以就不得不用c+mex的方法寫了一個2d image的deconvolution 程式,mex檔案代碼如下:
#include <stdio.h>#include <math.h>#include "mex.h"#definea_INprhs[0]/* sparse coefficient matrix */#definef_INprhs[1]/* filter matrix*/#definefb_OUT plhs[0]/* reconstructed image */#define a_(i,n)a[(i) + (n)*ra]/* A is L x M */#define f_(i,n)f[(i) + (n)*rf]/* X is L x npats */#define fb_(i,n)fb[(i) + (n)*rfb]/* S is M x npats */static int ra;/* row number of a */static int ca;/* column number of a */static int rf;/* row number of f */static int cf;/* column number of f */static int rfb;/* row number of fb */static int cfb;/* column number of fb */// const mwSize N_DIM=2;void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){ if (mxGetNumberOfDimensions(a_IN)!=2 || mxGetNumberOfDimensions(f_IN)!=2){ mexErrMsgTxt("Both inputs should be 2D matrix."); } double *a, *f, *fb; a = mxGetPr(a_IN); f = mxGetPr(f_IN); ra = (int)mxGetM(a_IN); ca = (int)mxGetN(a_IN); rf = (int)mxGetM(f_IN); cf = (int)mxGetN(f_IN); rfb = ra+rf-1; cfb = ca+cf-1; fb_OUT = mxCreateDoubleMatrix(rfb, cfb, mxREAL); fb = mxGetPr(fb_OUT); //printf("a: %d, %d\n f: %d, %d\n fb: %d, %d\n", ra,ca,rf,cf,rfb,cfb); //initialize fb to zero; for (int i=0;i<rfb;i++){ for (int j=0;j<cfb;j++){ fb_(i,j)=0; } } for (int i=0;i<ra;i++){ for (int j=0;j<ca;j++){ if (a_(i,j)!=0){ for (int i1=0;i1<rf;i1++){ for (int j1=0;j1<cf;j1++){ fb_(i+i1,j+j1)+=a_(i,j)*f_(i1,j1); } } } } }}
把這個檔案命名成deconv2.cpp 再在matlab裡面mex deconv2.cpp編譯一下,就是2d deconvolution函數了。運行速度比原來matlab code提高了1000倍左右
後記:後來發現原來這樣implement沒有必要,matlab裡面conv2就能實現這個功能,只不過要得到正確結果的話要先把filter行列反轉一下