图像处理中的卷积操作实现

[题目链接](https://www.nowcoder.com/practice/798b474486af4528b9722feacc39aafb)

思路

本题要求对灰度图像矩阵进行二维卷积操作,使用零填充(zero padding)处理边界。

核心步骤:

  1. 零填充:设卷积核尺寸为 ,令 。在原始 图像的四周各填充 层零,得到 的填充矩阵。
  1. 逐像素卷积:对输出矩阵的每个位置 ,从填充矩阵中取出以 为中心的 区域,与卷积核逐元素相乘后求和:

$$

  1. 格式化输出:每个结果用 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()

复杂度分析

  • 时间复杂度,对输出矩阵的每个位置都需要遍历整个卷积核。
  • 空间复杂度,存储零填充后的矩阵。