图像处理时用的卷积函数
做图像处理,最耗时间的运算应该就是卷积运算那一步了。以后如果有机会在用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指令效果就更好了,可惜这个我不太熟悉。