//单通道单卷积
#define IMG_SIZE 5
#define W_SIZE 3
#define OUT_SIZE 3 // (f-w+2p)/s + 1 = (5-3+0)/1+1 = 3
int conv(float img[IMG_SIZE][IMG_SIZE],float w[W_SIZE][W_SIZE],float out[OUT_SIZE][OUT_SIZE])
{
float tmp=0.0;
for(int k=0;k<=IMG_SIZE - W_SIZE;k++) //特征平面的行 列平移 行卷积
{
for(int r=0;r<=IMG_SIZE - W_SIZE;r++) //特征平面的列 行平移 列卷积
{
tmp = 0.0;
//单次卷积 点对点相乘 然后相加
for(int i=0;i<W_SIZE;i++) //卷积的行
{
for(int j=0;j<W_SIZE;j++) //卷积的列
{
tmp += img[i+k][j+r]*w[i][j];
}
}
out[k][r] = tmp;
}
}
return 0;
}
运行结果:
关键代码实现如下:
//多通道多卷积
#define IMG_SIZE 7
#define IMG_CH 3
#define CONV_KERNEL_SIZE 3
#define CONV_KERNEL_CH 3
#define CONV_KERNEL_NUM 2
#define OUT_SIZE 5
#define OUT_CH 2
/*
注意:这里把通道数放后面 是为了与后续 tensorflow 提取的参数保持一致
如:
# 进行卷积计算
# x表示输入的描述表示4阶张量,类似[1,2,2,3], 由于使用一张图 于是可以写成[2][3][3]
# 第一维参数表示一次性读取的图片数量
# 第2、3维表示图片的分辨率,最后一维表示图片的通道数
# w表示卷积核的表述,同样是4维张量
# 第1、2维表示卷积核的分辨率,第3维表示图片的通道数
# 第4维表示卷积核的个数
*/
/*
img : [7][7][3] 输入图像大小 7*7 有3个通道数
w : [3][3][3][2] 权重大小 3*3 有3个通道数 一共有2个卷积核
out : [5][5][2] 输出图像大小 5*5 有2个通道数 (输出通道数等于卷积核的数量)
*/
int convs( float img[IMG_SIZE][IMG_SIZE][IMG_CH],
float w[CONV_KERNEL_SIZE][CONV_KERNEL_SIZE][CONV_KERNEL_CH][CONV_KERNEL_NUM],
float out[OUT_SIZE][OUT_SIZE][OUT_CH])
{
float tmp=0.0,tmp1=0.0;
for(int m=0;m<CONV_KERNEL_NUM;m++)
{
for(int k=0;k<=IMG_SIZE - W_SIZE;k++) //特征平面的行 列平移 行卷积
{
for(int r=0;r<=IMG_SIZE - W_SIZE;r++) //特征平面的列 行平移 列卷积
{
//多通道累加
tmp1 = 0.0;
for(int n=0;n<CONV_KERNEL_CH;n++)
{
tmp = 0.0;
//单次卷积 点对点相乘 然后相加
for(int i=0;i<W_SIZE;i++) //卷积的行
{
for(int j=0;j<W_SIZE;j++) //卷积的列
{
tmp += img[i+k][j+r][n]*w[i][j][n][m];
}
}
//累加多个特征平面的卷积结果
tmp1 += tmp;
}
out[k][r][m] = tmp1;
}
}
}
}
//实现多维转一维
#define IN_SIZE 3
#define IN_CH 3
#define OUT_LEN (IN_SIZE*IN_SIZE*IN_CH)
int convert(float in[IN_SIZE][IN_SIZE][IN_CH],float out[OUT_LEN])
{
// float *p = out;
for(int k=0;k<IN_CH;k++)
{
for(int i=0;i<IN_SIZE;i++)
{
for(int j=0;j<IN_SIZE;j++)
{
#if 0
*p = in[i][j][k];
#else
out[k*IN_SIZE*IN_SIZE+i*IN_SIZE+j] = in[i][j][k];
#endif
}
}
}
return 0;
}
#include
//单通道单卷积
#define IMG_SIZE 5
#define W_SIZE 3
#define OUT_SIZE 3 // (f-w+2p)/s + 1 = (5-3+0)/1+1 = 3
int conv(float img[IMG_SIZE][IMG_SIZE],float w[W_SIZE][W_SIZE],float out[OUT_SIZE][OUT_SIZE])
{
float tmp=0.0;
for(int k=0;k<=IMG_SIZE - W_SIZE;k++) //特征平面的行 列平移 行卷积
{
for(int r=0;r<=IMG_SIZE - W_SIZE;r++) //特征平面的列 行平移 列卷积
{
tmp = 0.0;
//单次卷积 点对点相乘 然后相加
for(int i=0;i<W_SIZE;i++) //卷积的行
{
for(int j=0;j<W_SIZE;j++) //卷积的列
{
tmp += img[i+k][j+r]*w[i][j];
}
}
out[k][r] = tmp;
}
}
return 0;
}
int conv_test()
{
float img_in[IMG_SIZE][IMG_SIZE] = { 1,1,1,0,0,
0,1,1,1,0,
0,0,1,1,1,
0,0,1,1,0,
0,1,1,0,0};
float conv_w[W_SIZE][W_SIZE] = { 1,0,1,
0,1,0,
1,0,1};
float img_out[OUT_SIZE][OUT_SIZE] = {0};
//调用卷积函数
conv(img_in,conv_w,img_out);
int i,j;
printf("Input picture:\n");
for(i=0;i<5;i++)
{
for(j=0;j<5;j++)
{
printf("%.1f ",img_in[i][j]);
}
printf("\n");
}
printf("Input weight:\n");
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
printf("%.1f ",conv_w[i][j]);
}
printf("\n");
}
printf("Output picture:\n");
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
printf("%.1f ",img_out[i][j]);
}
printf("\n");
}
return 0;
}
//多通道多卷积
#define IMG_SIZE 7
#define IMG_CH 3
#define CONV_KERNEL_SIZE 3
#define CONV_KERNEL_CH 3
#define CONV_KERNEL_NUM 2
#define OUT_SIZE 5
#define OUT_CH 2
/*
注意:这里把通道数放后面 是为了与后续 tensorflow 提取的参数保持一致
如:
# 进行卷积计算
# x表示输入的描述表示4阶张量,类似[1,2,2,3], 由于使用一张图 于是可以写成[2][3][3]
# 第一维参数表示一次性读取的图片数量
# 第2、3维表示图片的分辨率,最后一维表示图片的通道数
# w表示卷积核的表述,同样是4维张量
# 第1、2维表示卷积核的分辨率,第3维表示图片的通道数
# 第4维表示卷积核的个数
*/
/*
img : [7][7][3] 输入图像大小 7*7 有3个通道数
w : [3][3][3][2] 权重大小 3*3 有3个通道数 一共有2个卷积核
out : [5][5][2] 输出图像大小 5*5 有2个通道数 (输出通道数等于卷积核的数量)
*/
int convs( float img[IMG_SIZE][IMG_SIZE][IMG_CH],
float w[CONV_KERNEL_SIZE][CONV_KERNEL_SIZE][CONV_KERNEL_CH][CONV_KERNEL_NUM],
float out[OUT_SIZE][OUT_SIZE][OUT_CH])
{
float tmp=0.0,tmp1=0.0;
for(int m=0;m<CONV_KERNEL_NUM;m++)
{
for(int k=0;k<=IMG_SIZE - W_SIZE;k++) //特征平面的行 列平移 行卷积
{
for(int r=0;r<=IMG_SIZE - W_SIZE;r++) //特征平面的列 行平移 列卷积
{
//多通道累加
tmp1 = 0.0;
for(int n=0;n<CONV_KERNEL_CH;n++)
{
tmp = 0.0;
//单次卷积 点对点相乘 然后相加
for(int i=0;i<W_SIZE;i++) //卷积的行
{
for(int j=0;j<W_SIZE;j++) //卷积的列
{
tmp += img[i+k][j+r][n]*w[i][j][n][m];
}
}
//累加多个特征平面的卷积结果
tmp1 += tmp;
}
out[k][r][m] = tmp1;
}
}
}
}
int convs_test()
{
float input[IMG_CH][IMG_SIZE][IMG_SIZE] = {
0,0,0,0,0,0,0,
0,1,1,2,2,1,0,
0,1,1,1,2,1,0,
0,2,1,1,0,2,0,
0,2,1,0,1,2,0,
0,2,1,2,2,2,0,
0,0,0,0,0,0,0,
0,0,0,0,0,0,0,
0,0,1,2,0,1,0,
0,2,2,1,1,0,0,
0,2,1,0,0,2,0,
0,1,0,0,0,2,0,
0,0,1,0,1,2,0,
0,0,0,0,0,0,0,
0,0,0,0,0,0,0,
0,2,2,0,1,2,0,
0,0,0,2,1,2,0,
0,2,1,0,2,1,0,
0,1,1,0,0,0,0,
0,0,0,1,1,1,0,
0,0,0,0,0,0,0,};
float conv_w[CONV_KERNEL_NUM][CONV_KERNEL_CH][CONV_KERNEL_SIZE][CONV_KERNEL_SIZE] = {
1,1,1,
-1,-1,0,
-1,1,0,
-1,-1,1,
-1,1,0,
-1,1,0,
1,0,-1,
0,0,0,
1,-1,-1,
0,0,-1,
-1,1,1,
0,0,0,
0,0,1,
1,0,1,
0,-1,-1,
-1,1,1,
0,1,1,
1,-1,1};
//由于输入的图像是正规的数据排列 ,但是函数调用是图像数据需要做预处理
float input1[IMG_SIZE][IMG_SIZE][IMG_CH] = {0};
float conv_w1[CONV_KERNEL_SIZE][CONV_KERNEL_SIZE][CONV_KERNEL_CH][CONV_KERNEL_NUM] = {0};
float img_out[OUT_SIZE][OUT_SIZE][OUT_CH] = {0};
int i,j,k,r,m,n;
printf("Input picture\n");
for(k =0;k<IMG_CH;k++)
{
for(i=0;i<IMG_SIZE;i++)
{
for(j=0;j<IMG_SIZE;j++)
{
input1[i][j][k] = input[k][i][j];
printf("%.1f ",input1[i][j][k]);
}
printf("\n");
}
printf("\n");
}
printf("\n");
printf("CONV_KERNEL:\n");
for(r=0;r<CONV_KERNEL_NUM;r++)
{
for(k=0;k<CONV_KERNEL_CH;k++)
{
for(i=0;i<CONV_KERNEL_SIZE;i++)
{
for(j=0;j<CONV_KERNEL_SIZE;j++)
{
conv_w1[i][j][k][r] = conv_w[r][k][i][j];
printf("%.1f ",conv_w1[i][j][k][r]);
}
printf("\n");
}
printf("\n");
}
}
printf("\n");
convs(input1,conv_w1,img_out);
printf("Output picture\n");
for(k=0;k<OUT_CH;k++)
{
for(i=0;i<OUT_SIZE;i++)
{
for(j=0;j<OUT_SIZE;j++)
{
printf("%.1f ",img_out[i][j][k]);
}
printf("\n");
}
printf("\n");
}
printf("\n");
return 0;
}
//实现多维转一维
#define IN_SIZE 3
#define IN_CH 3
#define OUT_LEN (IN_SIZE*IN_SIZE*IN_CH)
int convert(float in[IN_SIZE][IN_SIZE][IN_CH],float out[OUT_LEN])
{
// float *p = out;
for(int k=0;k<IN_CH;k++)
{
for(int i=0;i<IN_SIZE;i++)
{
for(int j=0;j<IN_SIZE;j++)
{
#if 0
*p = in[i][j][k];
#else
out[k*IN_SIZE*IN_SIZE+i*IN_SIZE+j] = in[i][j][k];
#endif
}
}
}
return 0;
}
int convert_test()
{
float input[IN_CH][IN_SIZE][IN_SIZE] = {
1,1,1,
-1,-1,0,
-1,1,0,
-1,-1,1,
-1,1,0,
-1,1,0,
1,0,-1,
0,0,0,
1,-1,-1,
};
float input1[IN_SIZE][IN_SIZE][IN_CH] = {0};
float output[OUT_LEN] ={0};
int i,j,k,r,m,n;
float *p = output;
printf("Input picture\n");
for(k=0;k<IN_CH;k++)
{
for(i=0;i<IN_SIZE;i++)
{
for(j=0;j<IN_SIZE;j++)
{
input1[i][j][k] = input[k][i][j];
printf("%.1f ",input1[i][j][k]);
}
printf("\n");
}
printf("\n");
}
printf("\n");
convert(input1,output);
printf("Output picture\n");
for(k=0;k<IN_CH;k++)
{
for(i=0;i<IN_SIZE;i++)
{
for(j=0;j<IN_SIZE;j++)
{
// printf("%.1f ",*p);
// p++;
// printf("%.1f ",output[i][j][k]);
printf("%.1f ",output[k*IN_SIZE*IN_SIZE+i*IN_SIZE+j]);
// printf("%.1f ",output[k*IN_SIZE*IN_SIZE+i*IN_SIZE+j]);
}
}
}
return 0;
}
int main()
{
//conv_test();
//convs_test();
convert_test();
return 0;
}