图像处理中的卷积操作实现
[题目链接](https://www.nowcoder.com/practice/798b474486af4528b9722feacc39aafb)
思路
本题要求对灰度图像矩阵进行二维卷积操作,使用零填充(zero padding)处理边界。
核心步骤:
- 零填充:设卷积核尺寸为
,令
。在原始
图像的四周各填充
层零,得到
的填充矩阵。
- 逐像素卷积:对输出矩阵的每个位置
,从填充矩阵中取出以
为中心的
区域,与卷积核逐元素相乘后求和:
$$
- 格式化输出:每个结果用 Python 的
round(x, 2)保留两位小数,再转字符串输出(尾部多余的零会被去掉)。
以样例为例:
图像为 ,卷积核为
,
。零填充后变为
。
对位置 :取填充矩阵的
区域为
,与卷积核逐元素相乘求和 =
,与预期输出一致。
整个过程就是按定义直接模拟即可。
代码
#include <bits/stdc++.h>
using namespace std;
string fmt(double v) {
v = round(v * 100.0) / 100.0;
if (v == 0.0) v = 0.0;
char buf[64];
sprintf(buf, "%.2f", v);
string s(buf);
size_t dot = s.find('.');
if (dot != string::npos) {
size_t last = s.size() - 1;
while (last > dot + 1 && s[last] == '0') last--;
s = s.substr(0, last + 1);
}
return s;
}
int main() {
int m, n;
scanf("%d%d", &m, &n);
vector<vector<double>> img(m, vector<double>(n));
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
scanf("%lf", &img[i][j]);
int k;
scanf("%d", &k);
vector<vector<double>> ker(k, vector<double>(k));
for (int i = 0; i < k; i++)
for (int j = 0; j < k; j++)
scanf("%lf", &ker[i][j]);
int pad = k / 2;
int pm = m + 2 * pad, pn = n + 2 * pad;
vector<vector<double>> padded(pm, vector<double>(pn, 0.0));
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
padded[i + pad][j + pad] = img[i][j];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
double val = 0.0;
for (int di = 0; di < k; di++)
for (int dj = 0; dj < k; dj++)
val += padded[i + di][j + dj] * ker[di][dj];
if (j) printf(" ");
printf("%s", fmt(val).c_str());
}
printf("\n");
}
return 0;
}
import java.util.*;
public class Main {
static String fmt(double v) {
v = Math.round(v * 100.0) / 100.0;
if (v == 0.0) v = 0.0;
String s = String.format("%.2f", v);
int dot = s.indexOf('.');
if (dot >= 0) {
int last = s.length() - 1;
while (last > dot + 1 && s.charAt(last) == '0') last--;
s = s.substring(0, last + 1);
}
return s;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = sc.nextInt(), n = sc.nextInt();
double[][] img = new double[m][n];
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
img[i][j] = sc.nextDouble();
int k = sc.nextInt();
double[][] ker = new double[k][k];
for (int i = 0; i < k; i++)
for (int j = 0; j < k; j++)
ker[i][j] = sc.nextDouble();
int pad = k / 2;
int pm = m + 2 * pad, pn = n + 2 * pad;
double[][] padded = new double[pm][pn];
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
padded[i + pad][j + pad] = img[i][j];
StringBuilder sb = new StringBuilder();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
double val = 0.0;
for (int di = 0; di < k; di++)
for (int dj = 0; dj < k; dj++)
val += padded[i + di][j + dj] * ker[di][dj];
if (j > 0) sb.append(' ');
sb.append(fmt(val));
}
sb.append('\n');
}
System.out.print(sb);
}
}
import numpy as np
def main():
m, n = map(int, input().split())
image = []
for _ in range(m):
image.append(list(map(int, input().split())))
k = int(input())
kernel = []
for _ in range(k):
kernel.append(list(map(float, input().split())))
img = np.array(image, dtype=float)
ker = np.array(kernel, dtype=float)
pad = k // 2
padded = np.pad(img, pad, mode='constant', constant_values=0)
out = np.zeros((m, n))
for i in range(m):
for j in range(n):
region = padded[i:i+k, j:j+k]
out[i][j] = np.sum(region * ker)
for i in range(m):
row = []
for j in range(n):
row.append(str(round(out[i][j], 2)))
print(' '.join(row))
main()
复杂度分析
- 时间复杂度:
,对输出矩阵的每个位置都需要遍历整个卷积核。
- 空间复杂度:
,存储零填充后的矩阵。

京公网安备 11010502036488号