文章目录
- 💯前言
- 💯题目描述
- 题目内容
- 输入格式
- 输出格式
- 示例
- 输入:
- 输出:
- 💯题目分析
- 问题拆解
- 💯我的做法
- 代码实现
- 代码分析
- 💯老师的做法
- 代码实现
- 代码分析
- 💯两种实现的对比
- 💯相关概念拓展
- 1. 四舍五入的实现
- 2. 二维数组的边界处理
- 💯优化建议
- 💯小结
💯前言
- 在C++程序设计学习中,处理二维数组与图像问题是一个重要的实践内容,能够帮助我们熟悉矩阵操作、边界条件处理以及浮点运算等核心技能。本篇文章将以一个图像模糊处理的题目为切入点,详细剖析题目背景、解题思路与两种代码实现(我的做法与老师的代码),并对两者进行深入比较与优化。同时,还将补充相关概念的详细解析,以期让读者对问题有全面而深入的理解。
C++ 参考手册
💯题目描述
题目来源于一个二维矩阵的图像模糊处理问题,其具体要求如下:
B2108 图像模糊处理
题目内容
给定一个 n
行 m
列的图像各像素点的灰度值,要求用如下方法对其进行模糊处理:
- 四周外围的像素点灰度值保持不变。
- 中间像素点新灰度值为该像素点及其上下左右相邻四个像素点灰度值的平均(包含到最近的整数)。
输入格式
- 第一行包含两个整数
n
和m
,表示图像像素点的行数和列数。 1 ≤ n , m ≤ 100 1 \leq n, m \leq 100 1≤n,m≤100。 - 接下来
n
行,每行包含m
个整数,表示图像像素的灰度值。 - 每个整数为 0 ∼ 255 0 \sim 255 0∼255 之间的值,相邻两个整数之间用单个空格隔开。
输出格式
n
行,每行m
个整数,为模糊处理后的图像。相邻两个整数之间用单个空格隔开。
示例
输入:
4 5
100 100 100 100 50
50 50 50 50 50
50 50 100 200 200
100 100 50 50 100
输出:
100 100 100 100 50
50 80 80 60 50
50 80 90 90 200
100 100 50 50 100
💯题目分析
问题拆解
要解决这个问题,我们需要完成以下任务:
- 边界处理:外围像素点保持原始灰度值不变。
- 中间像素模糊处理:
- 计算公式为:
模糊后的灰度值 = 当前像素点灰度值 + 上下左右相邻像素点灰度值 5 。 \text{模糊后的灰度值} = \frac{\text{当前像素点灰度值} + \text{上下左右相邻像素点灰度值}}{5}。 模糊后的灰度值=5当前像素点灰度值+上下左右相邻像素点灰度值。 - 结果需“包含到最近的整数”。
- 计算公式为:
💯我的做法
以下是我实现该题目的代码。
代码实现
#include <iostream>
#include <cmath>
using namespace std;int arr1[105][105];
int arr2[105][105];int main()
{int n, m;cin >> n >> m;for(int i = 0; i < n; i++){for(int j = 0; j < m; j++){cin >> arr1[i][j];}} for(int i = 0; i < n; i++){for(int j = 0; j < m; j++){if(i == 0 || i == n - 1 || j == 0 || j == m - 1)arr2[i][j] = arr1[i][j];else{double result = (arr1[i - 1][j] + arr1 [i + 1][j] + arr1[i][j - 1] + arr1[i][j + 1] + arr1[i][j]) / 5.0;arr2[i][j] = (int)round(result);}}} for(int i = 0; i < n; i++){for(int j = 0; j < m; j++){cout << arr2[i][j] << " ";}cout << endl;} return 0;
}
代码分析
- 输入部分:
- 通过两层循环读取矩阵的灰度值到
arr1
中。
- 通过两层循环读取矩阵的灰度值到
- 模糊处理:
- 使用两层循环遍历矩阵的每一个像素点。
- 边界点:直接将原始值赋值到结果矩阵
arr2
中。 - 中间点:计算该点及其上下左右四个点的平均值,使用
round()
函数进行四舍五入,然后赋值到arr2
中。
- 输出部分:
- 遍历
arr2
矩阵,将每行数据输出。
- 遍历
💯老师的做法
下面是老师的实现代码。
代码实现
#include <iostream>
using namespace std;const int N = 110;
int arr1[N][N]; // 旧数据
int arr2[N][N]; // 新数据
int n, m;int main() {cin >> n >> m;int i = 0;int j = 0;for (i = 0; i < n; i++) {for (j = 0; j < m; j++) {cin >> arr1[i][j];arr2[i][j] = arr1[i][j];}}for (i = 1; i < n - 1; i++) {for (j = 1; j < m - 1; j++) {arr2[i][j] = (arr1[i][j] + arr1[i - 1][j] + arr1[i + 1][j] + arr1[i][j - 1] + arr1[i][j + 1]) / 5.0 + 0.5;}}for (i = 0; i < n; i++) {for (j = 0; j < m; j++) {cout << arr2[i][j] << " ";}cout << endl;}return 0;
}
代码分析
- 边界初始化:
- 老师直接在输入矩阵时,将
arr1
的数据赋值给arr2
,实现了边界初始化。
- 老师直接在输入矩阵时,将
- 模糊处理逻辑:
- 对中间像素点进行模糊计算时,将平均值的浮点结果直接加上
0.5
,然后用强制类型转换(int)
实现四舍五入。
- 对中间像素点进行模糊计算时,将平均值的浮点结果直接加上
- 输出部分:
- 同样使用两层循环输出结果矩阵
arr2
。
- 同样使用两层循环输出结果矩阵
💯两种实现的对比
对比点 | 我的做法 | 老师的做法 |
---|---|---|
边界处理 | 使用条件语句单独处理边界像素。 | 在输入时直接完成边界初始化。 |
模糊计算 | 使用 round() 函数实现四舍五入。 | 通过 + 0.5 与强制类型转换 (int) 实现四舍五入。 |
代码结构 | 边界处理与模糊处理分开,逻辑清晰但略显冗余。 | 将边界初始化与输入结合,更加简洁。 |
浮点运算 | 使用浮点除法后取整,增加了一些计算开销。 | 避免了额外函数调用,更高效。 |
💯相关概念拓展
1. 四舍五入的实现
两种方法:
- 使用数学库中的
round()
函数:- 直接返回最近的整数。
- 手动实现:
- 对浮点数加
0.5
,然后强制类型转换为整数。 - 更高效,避免额外函数调用。
- 对浮点数加
2. 二维数组的边界处理
在处理二维数组时,常见的边界条件有:
- 边界像素点保持不变。
- 超出边界时采取特殊值(例如零填充)。
- 通过循环边界实现(例如,最后一行的邻居是第一行)。
💯优化建议
在已有代码的基础上,提出以下优化:
-
避免浮点运算:
- 使用整数除法和四舍五入的等效操作:
arr2[i][j] = (arr1[i][j] + arr1[i - 1][j] + arr1[i + 1][j] + arr1[i][j - 1] + arr1[i][j + 1] + 2) / 5;
+2
是为了模拟加0.5
的效果,且无需浮点运算。
- 使用整数除法和四舍五入的等效操作:
-
I/O 优化:
- 如果数据量较大,可以使用更高效的输入输出方法:
ios::sync_with_stdio(false); cin.tie(nullptr);
- 如果数据量较大,可以使用更高效的输入输出方法:
💯小结
通过本文对图像模糊处理问题的详解,我们不仅学习了如何处理二维数组,还深入对比了两种实现方式,掌握了边界处理、四舍五入、浮点运算优化等技巧。这些经验可迁移至其他矩阵操作类题目中,为复杂问题的求解提供清晰的思路和工具。希望这篇文章对你有所启发!