做圖像處理,最耗時間的運算應該就是卷積運算那一步了。以后如果有機會在用c++做圖像處理的項目的話,那么這個卷積部分還是要優化的。Matlab因為是驗證算法,其實是沒必要優化的。所以我就把卷積這一部分單獨列出一個函數,用匯編實現了。我可是電子工程出身,匯編當然不在話下。
函數是用匯編寫的,用的是c++內嵌asm匯編,相同功能的c++代碼也實現了,不過注釋掉了,去掉注釋能得到相同的結果。
讀和顯示圖像用了opencv函數庫,話說上一個項目結束之后好像就沒怎么用過這個庫了,畢竟,單單調用庫中的函數是沒辦法真正理解原理的。
#include <iostream> #include "cv.h" #include "highgui.h" using namespace std; //*img是圖像數據,i_h是圖像的高,i_w是圖像的寬 //*m是卷積模板,m_h是模板的高,m_w是模板的寬 //x,y是在圖像(x,y)坐標處卷積 //返回卷積的值 int conv(int *img,int i_h,int i_w,int *m,int m_h,int m_w,int y,int x) { int re; int sum1; int sum2; int half_m_w; int half_m_h; int i; int j; int ii; int jj; __asm { mov re,0; mov sum1,0; mov sum2,0; mov eax,m_w; //half_m_w=(m_w-1)/2; dec eax; mov bl,2; div bl; mov ah,0; mov half_m_w,eax; mov eax,m_h; //half_m_h=(m_h-1)/2; dec eax; mov bl,2; div bl; mov ah,0; mov half_m_h,eax; mov ecx,m_w; //m_w*h_h imul ecx,m_h; mov eax,0; label1: mov ebx,m; // for (i=0;i<m_w*m_h;i++) add eax,[ebx]; // { add ebx,4; // sum2+=m[i]; dec ecx; // } jnz label1; mov sum2,eax; mov i,0; mov ii,0; mov eax,y; //i=y-half_m_h; sub eax,half_m_h; mov i,eax; label2: mov j,0; mov jj,0; mov eax,x; //j=x-half_m_w; sub eax,half_m_w; mov j,eax; label3: mov ebx,img; //每次循環重新賦值img基址 mov edx,m; //每次重新賦值m基址 mov eax,i; //i*i_w+j imul eax,4; imul eax,i_w; mov ecx,j; imul ecx,4; add eax,ecx; add ebx,eax; mov eax,ii; //ii*m_w+jj imul eax,4; imul eax,m_w; mov ecx,jj; imul ecx,4; add eax,ecx; add edx,eax; mov eax,[ebx]; //sum1+=img[i*i_w+j]*m[ii*m_w+jj]; imul eax,[edx]; add eax,sum1; mov sum1,eax; mov eax,jj; //jj++ inc eax; mov jj,eax; mov eax,x; //j?<x+half_m_w add eax,half_m_w; mov ecx,eax; sub ecx,j; mov eax,j; //j++ inc eax; mov j,eax; test ecx,ecx; jnz label3; mov eax,ii; //ii++ inc eax; mov ii,eax; mov eax,y; //i?<y+half_m_h add eax,half_m_h; mov ecx,eax; sub ecx,i; mov eax,i; //i++ inc eax; mov i,eax; test ecx,ecx; jnz label2; mov eax,sum1; //sum1/sum2 mov ebx,sum2; div bl; mov ah,0; mov re,eax; } /* half_m_h=(m_h-1)/2; half_m_w=(m_w-1)/2; sum1=0; sum2=0; for (i=0;i<m_w*m_h;i++) { sum2+=m[i]; } for (i=y-half_m_h,ii=0;i<=y+half_m_h;i++,ii++) { for (j=x-half_m_w,jj=0;j<=x+half_m_w;j++,jj++) { sum1+=img[i*i_w+j]*m[ii*m_w+jj]; } } re=int(sum1/sum2); */ return re; } int main() { IplImage *image; CvScalar s; image=cvLoadImage("C:/Users/tc/Documents/Visual Studio 2010/Projects/vm/Debug/lena.jpg",0); int *img; img=new int[image->height*image->width]; for (int i=0;i<image->height;i++) { for (int j=0;j<image->width;j++) { s=cvGet2D(image,i,j); img[i*image->width+j]=(int)s.val[0]; } } int *m; m=new int[9]; for (int i=0;i<9;i++) { m[i]=1; } for (int i=1;i<image->height-1;i++) { for (int j=1;j<image->width-1;j++) { s=cvGet2D(image,i,j); s.val[0]=conv(img,image->height,image->width,m,3,3,i,j); cvSet2D(image,i,j,s); } } cvNamedWindow("lena",1); cvShowImage("lena",image); cvWaitKey(0); cvReleaseImage(&image); cvDestroyAllWindows(); delete[] img; delete[] m; return 0; }
注:要是使用mmx,sse指令效果就更好了,可惜這個我不太熟悉。