前面的哪个卷积只适合用方形图像,一般的图像是长方形的,所以
这里重新找了一个博文《关于图像的二维卷积各种版本的实现(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;
}
效果图:
卷积部分暂时就这样吧。