前面的哪个卷积只适合用方形图像,一般的图像是长方形的,所以
这里重新找了一个博文《关于图像的二维卷积各种版本的实现(C++,Cuda和mex)》中的做模板:
首先是最常用的C++版本的卷积实现,代码如下: void Conv2(int** filter, int** arr, int** res, int filterW, int filterH, int arrW, int arrH) { int temp; for (int i=0; i<filterH+arrH-1; i++) { for (int j=0; j<filterW+arrW-1; j++) { temp = 0; for (int m=0; m<filterH; m++) { for (int n=0; n<filterW; n++) { if ((i-m)>=0 && (i-m)<arrH && (j-n)>=0 && (j-n)<arrW) { temp += filter[m][n]*arr[i-m][j-n]; } } } res[i][j] = temp; } } }
实现:
//c++实现卷积 #define USE_EGE 0 //选择ege (1)或 easyx(0)的开关 #if USE_EGE #include <ege.h> //使用ege库 和 easyx 差不多,这里没有实现 using namespace ege; #else #include <easyx.h>//使用easyx库 #include<conio.h> #endif #include<iostream> #include<vector> using namespace std; #define SCREEN_WIDTH 1100 //窗口大小 #define SCREEN_HEIGHT 600 #define byte unsigned char struct 卷积矩阵 { int width; //宽 int height; //高 //数据 int * data; //构造函数 卷积矩阵(int iwidth,int iheight); }; IMAGE jpg;//一张原图 //定义一个卷积过程中的矩阵 卷积矩阵::卷积矩阵(int iwidth,int iheight): width(iwidth), height(iheight) { int size=sizeof(int)*width*iheight; data=(int*)malloc(size); memset(data, 0,size); } void error(char *s) { printf("%s\n",s); getch(); exit(1); } void loadjpg(char * jpgname) { loadimage(&jpg,jpgname);//载入图像 } //C++版本的卷积实现 void Conv2(float* filter, int* arr, int* res, int filterW, int filterH, int arrW, int arrH) { float temp; int resW=filterW+arrW-1;//输出宽 int resH=filterH+arrH-1;//输出高 for (int i=0; i<resH; i++) //输入 { for (int j=0; j<resW; j++) { temp = 0; for (int m=0; m<filterH; m++) //核 { for (int n=0; n<filterW; n++) { if ((i-m)>=0 && (i-m)<arrH && (j-n)>=0 && (j-n)<arrW) { temp += filter[m*filterW+n]*arr[(i-m)*arrW+(j-n)]; //积 和 } } } res[i*resW+j] = (int)temp; } } } int main() { initgraph(SCREEN_WIDTH, SCREEN_HEIGHT,SHOWCONSOLE);//, INIT_RENDERMANUAL char jpgname[]="butterfly-0.jpg"; //载入图片 loadjpg(jpgname); SetWorkingImage(&jpg);//设置已经加载图片为要扫描的图片 int height = jpg.getheight(); int width = jpg.getwidth(); // 1。定义被卷积的矩阵(其实是一个数组) // 这里用一张单色图代替 卷积矩阵 isA(width,height); int *A=isA.data;//(int*)malloc(sizeof(int)*map*map); //图像转化单色并保存结果 for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { A[i*width+j]= GetRValue(RGBtoGRAY(getpixel(j , i)));//返回指定颜色 范围0-255 } } SetWorkingImage();//还原为屏幕 int c; //显示原图 for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { c=A[i*width+j];//返回指定颜色 范围0-255 putpixel(j, i, RGB(c,c,c)); } } getch(); // 2。定义卷积核矩阵(其实也是一个数组,数组元素的个数3*3) int const kernel = 3; float B[kernel*kernel] = { #if 1 //'sobel' 索贝尔水平边缘增强滤波器 //-1, 0, 1, //-2, 0, 2, //-1, 0, 1 1.2886529 , 0.04068733 , -1.3082279, 1.43157125, 0.01173212 , -1.45389295, 1.34158182, -0.07245208, -1.27504027 #else // 'unsharp' 反锐化对比度增强滤波器 -0.1667, -0.6667,-0.1667, -0.6667, 4.3333,-0.6667, -0.1667, -0.6667,-0.1667 #endif }; //计算卷积输出矩阵宽、高 int c_width= kernel+width-1; //filterW+arrW-1; int c_height= kernel+height-1; // filterH+arrH-1; //3。卷积后输出矩阵 卷积矩阵 isC(c_width,c_height); int * C=isC.data; //Conv2(int** filter, int** arr, int** res, int filterW, int filterH, int arrW, int arrH) Conv2(B, A, C, kernel, kernel, width, height) ; //归一化 //1。找最小最大值 int imin=0,imax=255; for (int i = 0; i < c_height; i++) { for (int j = 0; j < c_width; j++) { c= C[i*c_width + j]; //找最小值 if(c<imin) imin=c; //找最大值 if(c>imax)imax=c; } } cout << "最小值:"<<imin<<"最大值:"<<imax<<endl; //2。用最小最大值来归一化 for (int i = 0,k; i < c_height; i++) { for (int j = 0; j < c_width; j++) { k=i*c_width + j; float p= C[k]; p=(p-imin)/(imax-imin)*255; C[k]=p; } } //显示卷积图 //cout << "卷积后输出矩阵:" << endl; for (int i = 0; i < c_height; i++) { for (int j = 0; j < c_width; j++) { c= C[i*c_width + j]; putpixel(j+c_width+5, i, RGB(c,c,c)); } } getch(); closegraph(); system("pause"); return 0; }
效果图:
卷积部分暂时就这样吧。