如何在C语言中正确定义并使用返回自定义结构体的函数?
帮你搞定卷积函数里的矩阵输出实现
我太懂这种感觉了——搜了一堆基础教程,全是讲怎么定义个矩阵、简单遍历打印,完全碰不到卷积场景下的具体内存分配和元素计算细节对吧?咱们一步步把这个convolve函数的核心逻辑补全。
首先先明确核心前提:假设你要实现的是valid卷积(不补零,只计算filter和输入矩阵完全重叠的区域),那输出矩阵的尺寸公式是:
- 输出高度 = 输入高度 - 滤波器高度 + 1
- 输出宽度 = 输入宽度 - 滤波器宽度 + 1
如果之后需要支持same卷积(补零让输出和输入尺寸一致),咱们后面再提,先从最常用的valid场景入手。
第一步:给输出矩阵分配内存
首先得给out矩阵的行指针和每行的内存空间分配好,还要加内存分配失败的防护(避免内存泄漏):
// 先做输入合法性检查:滤波器不能比输入矩阵大,否则输出尺寸为负 if (filter.height > data.height || filter.width > data.width) { out.height = 0; out.width = 0; out.map = NULL; return out; } // 计算输出矩阵的尺寸 out.height = data.height - filter.height + 1; out.width = data.width - filter.width + 1; // 先分配行指针数组 out.map = malloc(out.height * sizeof(double*)); if (out.map == NULL) { // 分配失败就返回空矩阵 out.height = 0; out.width = 0; return out; } // 给每一行分配内存,同时做失败回滚 for (int i = 0; i < out.height; i++) { out.map[i] = malloc(out.width * sizeof(double)); if (out.map[i] == NULL) { // 某一行分配失败,要把已经分配的内存全部释放 for (int j = 0; j < i; j++) { free(out.map[j]); } free(out.map); out.height = 0; out.width = 0; out.map = NULL; return out; } }
第二步:计算卷积的每个元素值
卷积的本质就是滑动窗口内的元素对应相乘再求和,用四层循环就能搞定:
// 遍历输出矩阵的每个行 for (int i = 0; i < out.height; i++) { // 遍历输出矩阵的每个列 for (int j = 0; j < out.width; j++) { double sum = 0.0; // 遍历滤波器的行 for (int fi = 0; fi < filter.height; fi++) { // 遍历滤波器的列 for (int fj = 0; fj < filter.width; fj++) { // 对应位置相乘累加:输入矩阵的(i+fi,j+fj) 乘 滤波器的(fi,fj) sum += data.map[i + fi][j + fj] * filter.map[fi][fj]; } } out.map[i][j] = sum; } }
完整的convolve函数
把上面的逻辑整合到你的代码里,最终版本是这样:
Matrix convolve(Matrix data, Matrix filter) //this is line 28 btw { Matrix out; // 输入合法性校验 if (filter.height > data.height || filter.width > data.width) { out.height = 0; out.width = 0; out.map = NULL; return out; } // 计算输出尺寸 out.height = data.height - filter.height + 1; out.width = data.width - filter.width + 1; // 分配输出矩阵内存 out.map = malloc(out.height * sizeof(double*)); if (out.map == NULL) { out.height = 0; out.width = 0; return out; } for (int i = 0; i < out.height; i++) { out.map[i] = malloc(out.width * sizeof(double)); if (out.map[i] == NULL) { // 内存分配失败的回滚逻辑 for (int j = 0; j < i; j++) { free(out.map[j]); } free(out.map); out.height = 0; out.width = 0; out.map = NULL; return out; } } // 计算卷积结果 for (int i = 0; i < out.height; i++) { for (int j = 0; j < out.width; j++) { double sum = 0.0; for (int fi = 0; fi < filter.height; fi++) { for (int fj = 0; fj < filter.width; fj++) { sum += data.map[i + fi][j + fj] * filter.map[fi][fj]; } } out.map[i][j] = sum; } } return out; }
额外的重要提示
- 内存泄漏防护:用完
out矩阵后,一定要写一个释放函数来清理内存:void freeMatrix(Matrix mat) { if (mat.map != NULL) { for (int i = 0; i < mat.height; i++) { free(mat.map[i]); } free(mat.map); } } - same卷积支持:如果需要输出尺寸和输入一致,要先给输入矩阵补零,补零的行数是
filter.height/2,列数是filter.width/2,之后再用上面的逻辑计算即可。
内容的提问来源于stack exchange,提问作者Sam Haese
相关产品推荐
相关产品推荐

