1 条题解

  • 0
    @ 2025-4-7 19:54:39

    题意分析

    本题要求对给定的二值图像进行形态学处理,具体包括两种基本操作:腐蚀和膨胀,并利用这两种操作分别实现图像的开运算和闭运算。

    输入一个大小为 m×n 的二值图像,用字符串数组表示,每个字符为 ' * '(表示前景像素)或 '.'(表示背景像素)。

    结构元素 B,其大小为 (2s+1)×(2s+1),同样用字符串数组表示,其中 ' * ' 表示参与操作的像素点,'.' 表示不考虑的位置。

    相关操作:

    腐蚀:对于图像中每个像素 (i, j),将结构元素 B 放置到以 (i, j) 为中心的区域,如果 B 中所有为' * ' 的位置在原图像中对应位置也均为 ' * ',则输出图像 (i, j) 位置为 ' * ';否则输出为 '.'。注意边界处可能因结构元素超出图像范围而直接判定为背景。

    膨胀:对于图像中每个像素 (i, j),若该像素为 ' * ',则将结构元素 B 放置到图像上(即对 B 中每个 ' * ' 所在位置,将 (i+bi-s, j+bj-s) 处设为 ' * ',前提是该位置在图像范围内)。

    开运算:对原图像进行腐蚀,再对腐蚀后的图像进行膨胀。主要用于去除噪点,同时保持图像的主要结构。

    闭运算:对原图像进行膨胀,再对膨胀后的图像进行腐蚀。主要用于填充图像中的小空洞,同时保持主要结构不变。

    题解思路

    1、数据预处理:

    读取图像的尺寸 m 和 n,以及结构元素半径 s(实际结构元素大小为 2*s+1)。

    分别读入图像 A 和结构元素 B。

    2、腐蚀操作:

    对于图像中每个像素 (i, j),将结构元素 B 中每个 ' * ' 的位置对应到原图像上,判断映射后的坐标 (i + bi - s, j + bj - s) 是否在图像范围内且为 ' * '。

    若存在任一位置不满足上述条件(即越界或原图像中对应位置为背景 '.'),则当前点 (i, j) 在腐蚀结果中设为 '.';否则设为 ' * '。

    3、膨胀操作:

    遍历原图像中所有像素 (i, j),若该像素为 ' * ',则将结构元素 B 中每个 ' * ' 对应的位置 (i + bi - s, j + bj - s) 置为 ' * '(前提是该位置在图像范围内)。

    由于多个前景像素可能会影响同一个位置,所以只要有一次赋值 ' * ',该位置在输出图像中即为 ' * '。

    4、开运算:

    首先对原图像 A 调用腐蚀操作得到腐蚀图像;然后对腐蚀图像调用膨胀操作,得到开运算结果。

    5、闭运算:

    首先对原图像 A 调用膨胀操作得到膨胀图像;然后对膨胀图像调用腐蚀操作,得到闭运算结果。

    本题代码

    #include <iostream>
    #include <vector>
    #include <string>
    #include <algorithm>
    using namespace std;
    
    vector<string> erosion(const vector<string>& img, const vector<string>& B, int m, int n, int s) {
        int bs = 2 * s + 1;
        vector<string> out(m, string(n, '.'));
        int i, j, bi, bj;
        for (i = 0; i < m; i++) {
            for (j = 0; j < n; j++) {
                bool ok = true;
                for (bi = 0; bi < bs && ok; bi++) {
                    for (bj = 0; bj < bs && ok; bj++) {
                        if (B[bi][bj] == '*') {
                            int ii = i + bi - s;
                            int jj = j + bj - s;
                            if (ii < 0 || ii >= m || jj < 0 || jj >= n || img[ii][jj] == '.') {
                                ok = false;
                            }
                        }
                    }
                }
                if (ok)
                    out[i][j] = '*';
                else
                    out[i][j] = '.';
            }
        }
        return out;
    }
    
    vector<string> dilation(const vector<string>& img, const vector<string>& B, int m, int n, int s) {
        int bs = 2 * s + 1;
        vector<string> out(m, string(n, '.'));
        int i, j, bi, bj;
        for (i = 0; i < m; i++) {
            for (j = 0; j < n; j++) {
                if (img[i][j] == '*') {
                    for (bi = 0; bi < bs; bi++) {
                        for (bj = 0; bj < bs; bj++) {
                            if (B[bi][bj] == '*') {
                                int ii = i + bi - s;
                                int jj = j + bj - s;
                                if (ii >= 0 && ii < m && jj >= 0 && jj < n)
                                    out[ii][jj] = '*';
                            }
                        }
                    }
                }
            }
        }
        return out;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(NULL);
        
        int m, n, s;
        int caseNum = 1;
        bool firstCase = true;
        while(cin >> m >> n >> s) {
            if(m == 0 && n == 0 && s == 0)
                break;
            
            int i;
            vector<string> A(m);
            for(i = 0; i < m; i++){
                cin >> A[i];
            }
            
            
            int bs = 2 * s + 1;
            vector<string> B(bs);
            for(i = 0; i < bs; i++){
                cin >> B[i];
            }
            
            vector<string> eroded = erosion(A, B, m, n, s);
            vector<string> openImg = dilation(eroded, B, m, n, s);
            
            vector<string> dilated = dilation(A, B, m, n, s);
            vector<string> closeImg = erosion(dilated, B, m, n, s);
            if(!firstCase)
                cout << string(75, '=') << "\n";
            firstCase = false;
            cout << "Case " << caseNum++ << "\n\n";
            for(i = 0; i < m; i++){
                cout << openImg[i] << "\n";
            }
            cout << "\n";
            for(i = 0; i < m; i++){
                cout << closeImg[i] << "\n";
            }
            cout << "\n";
        }
        return 0;
    }
    
    • 1

    信息

    ID
    1716
    时间
    10000ms
    内存
    64MiB
    难度
    10
    标签
    递交数
    5
    已通过
    1
    上传者