无噪声场景下2D反卷积的C++实现方法(小矩阵适用)
针对小整数矩阵的C++反卷积实现(暴力/直接求解法)
前提:保证卷积可逆
要从卷积输出还原原始矩阵,必须确保卷积操作无信息丢失,满足以下条件:
- 步长
stride = 1 - 使用Same Padding:输入矩阵周围补零,让卷积输出矩阵尺寸和输入完全一致(比如3x3卷积核处理10x10输入,输出仍为10x10)
- 卷积核尺寸为奇数(如3x3、5x5),确保每个输入元素都对应输出的有效计算
核心思路
卷积本质是线性变换:把输入矩阵元素按行优先展开为向量,卷积核对应一个变换矩阵,输出矩阵展开后是变换矩阵乘以输入向量。反卷积就是已知输出向量和变换矩阵,求解输入向量——这是一个线性方程组求解问题。
由于矩阵最大10x10(最多100个变量),直接用高斯消元法解方程组完全可行,属于暴力但高效的方案。
伪代码实现
1. 基础卷积函数(用于生成测试输出)
// 输入:原始矩阵I(MxM),卷积核K(NxN, N为奇数) // 输出:Same Padding后的卷积矩阵O(MxM) vector<vector<int>> convolution(vector<vector<int>>& I, int M, vector<vector<int>>& K, int N) { int k = (N - 1) / 2; // 卷积核半宽 vector<vector<int>> O(M, vector<int>(M, 0)); for (int i = 0; i < M; i++) { for (int j = 0; j < M; j++) { int sum = 0; for (int dx = -k; dx <= k; dx++) { for (int dy = -k; dy <= k; dy++) { int x = i + dx; int y = j + dy; if (x >= 0 && x < M && y >= 0 && y < M) { sum += I[x][y] * K[dx + k][dy + k]; } } } O[i][j] = sum; } } return O; }
2. 反卷积函数(高斯消元解线性方程组)
步骤1:构建线性方程组
把输入矩阵I的所有元素按行优先展开为向量 x(共M²个变量),输出矩阵O的元素展开为向量 b(共M²个方程),构建变换矩阵A(M²×M²),其中A[p][q]表示第p个方程中第q个变量的系数(即卷积核对应位置的值,若变量参与该方程计算则赋值,否则为0)。
// 输入:卷积输出O(MxM),卷积核K(NxN, N为奇数) // 输出:还原的原始矩阵I(MxM) vector<vector<int>> deconvolution(vector<vector<int>>& O, int M, vector<vector<int>>& K, int N) { int k = (N - 1) / 2; int var_count = M * M; int eq_count = M * M; // 构建增广矩阵:每行格式为 [A的一行] + [b的对应值] vector<vector<double>> aug(eq_count, vector<double>(var_count + 1, 0.0)); for (int p = 0; p < eq_count; p++) { int i = p / M; int j = p % M; aug[p][var_count] = O[i][j]; // 方程右侧的值 for (int dx = -k; dx <= k; dx++) { for (int dy = -k; dy <= k; dy++) { int x = i + dx; int y = j + dy; if (x >= 0 && x < M && y >= 0 && y < M) { int q = x * M + y; // 变量对应的索引 aug[p][q] = K[dx + k][dy + k]; // 系数为卷积核对应值 } } } } // 执行高斯消元求解 gauss_jordan(aug, var_count, eq_count); // 将解向量还原为矩阵 vector<vector<int>> I(M, vector<int>(M, 0)); for (int q = 0; q < var_count; q++) { int x = q / M; int y = q % M; I[x][y] = round(aug[q][var_count]); // 四舍五入还原整数 } return I; }
3. 高斯-约旦消元法(适配整数场景)
void gauss_jordan(vector<vector<double>>& aug, int var_count, int eq_count) { for (int col = 0; col < var_count; col++) { // 找到当前列绝对值最大的主元行 int pivot_row = col; for (int row = col; row < eq_count; row++) { if (abs(aug[row][col]) > abs(aug[pivot_row][col])) { pivot_row = row; } } // 交换主元行与当前行 swap(aug[col], aug[pivot_row]); // 归一化主元行,使主元为1 double pivot_val = aug[col][col]; if (fabs(pivot_val) < 1e-6) continue; // 主元为0,跳过(无解或无穷多解) for (int c = col; c <= var_count; c++) { aug[col][c] /= pivot_val; } // 消去其他行的当前列 for (int row = 0; row < eq_count; row++) { if (row != col && fabs(aug[row][col]) > 1e-6) { double factor = aug[row][col]; for (int c = col; c <= var_count; c++) { aug[row][c] -= factor * aug[col][c]; } } } } }
注意事项
- 只有卷积核对应的变换矩阵可逆时,才能得到唯一解。若变换矩阵不可逆,可能有无穷多解或无解(比如卷积核全零、存在线性相关行)。
- 由于处理整数矩阵,高斯消元后需四舍五入还原整数,若出现非整数解,说明卷积操作存在信息丢失或原始矩阵非整数。
- 极小矩阵(如3x3)可尝试暴力枚举:遍历原始矩阵元素的可能整数值,验证卷积结果是否匹配输出,但10x10矩阵不适用该方法。
内容的提问来源于stack exchange,提问作者oxheron
相关产品推荐
相关产品推荐

