【C++】图像模糊处理题目详解与实现



博客主页:[小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C++


文章目录



💯前言

  • 在C++程序设计学习中,处理二维数组与图像问题是一个重要的实践内容,能够帮助我们熟悉矩阵操作、边界条件处理以及浮点运算等核心技能。本篇文章将以一个图像模糊处理的题目为切入点,详细剖析题目背景、解题思路与两种代码实现(我的做法与老师的代码),并对两者进行深入比较与优化。同时,还将补充相关概念的详细解析,以期让读者对问题有全面而深入的理解。
    C++ 参考手册

💯题目描述

题目来源于一个二维矩阵的图像模糊处理问题,其具体要求如下:
B2108 图像模糊处理

题目内容

给定一个 nm 列的图像各像素点的灰度值,要求用如下方法对其进行模糊处理:

  1. 四周外围的像素点灰度值保持不变。
  2. 中间像素点新灰度值为该像素点及其上下左右相邻四个像素点灰度值的平均(包含到最近的整数)。

输入格式

  • 第一行包含两个整数 nm,表示图像像素点的行数和列数。 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 个整数,为模糊处理后的图像。相邻两个整数之间用单个空格隔开。

示例

输入:

plaintext 复制代码
4 5
100 100 100 100 50
50 50 50 50 50
50 50 100 200 200
100 100 50 50 100

输出:

plaintext 复制代码
100 100 100 100 50
50 80 80 60 50
50 80 90 90 200
100 100 50 50 100

💯题目分析

问题拆解

要解决这个问题,我们需要完成以下任务:

  1. 边界处理:外围像素点保持原始灰度值不变。
  2. 中间像素模糊处理
    • 计算公式为:
      模糊后的灰度值 = 当前像素点灰度值 + 上下左右相邻像素点灰度值 5 。 \text{模糊后的灰度值} = \frac{\text{当前像素点灰度值} + \text{上下左右相邻像素点灰度值}}{5}。 模糊后的灰度值=5当前像素点灰度值+上下左右相邻像素点灰度值。
    • 结果需"包含到最近的整数"。

💯我的做法

以下是我实现该题目的代码。

代码实现

cpp 复制代码
#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;	
} 

代码分析

  1. 输入部分
    • 通过两层循环读取矩阵的灰度值到 arr1 中。
  2. 模糊处理
    • 使用两层循环遍历矩阵的每一个像素点。
    • 边界点 :直接将原始值赋值到结果矩阵 arr2 中。
    • 中间点 :计算该点及其上下左右四个点的平均值,使用 round() 函数进行四舍五入,然后赋值到 arr2 中。
  3. 输出部分
    • 遍历 arr2 矩阵,将每行数据输出。

💯老师的做法

下面是老师的实现代码。

代码实现

cpp 复制代码
#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;
}

代码分析

  1. 边界初始化
    • 老师直接在输入矩阵时,将 arr1 的数据赋值给 arr2,实现了边界初始化。
  2. 模糊处理逻辑
    • 对中间像素点进行模糊计算时,将平均值的浮点结果直接加上 0.5,然后用强制类型转换 (int) 实现四舍五入。
  3. 输出部分
    • 同样使用两层循环输出结果矩阵 arr2

💯两种实现的对比

对比点 我的做法 老师的做法
边界处理 使用条件语句单独处理边界像素。 在输入时直接完成边界初始化。
模糊计算 使用 round() 函数实现四舍五入。 通过 + 0.5 与强制类型转换 (int) 实现四舍五入。
代码结构 边界处理与模糊处理分开,逻辑清晰但略显冗余。 将边界初始化与输入结合,更加简洁。
浮点运算 使用浮点除法后取整,增加了一些计算开销。 避免了额外函数调用,更高效。

💯相关概念拓展

1. 四舍五入的实现

两种方法:

  1. 使用数学库中的 round() 函数:
    • 直接返回最近的整数。
  2. 手动实现:
    • 对浮点数加 0.5,然后强制类型转换为整数。
    • 更高效,避免额外函数调用。

2. 二维数组的边界处理

在处理二维数组时,常见的边界条件有:

  • 边界像素点保持不变。
  • 超出边界时采取特殊值(例如零填充)。
  • 通过循环边界实现(例如,最后一行的邻居是第一行)。

💯优化建议

在已有代码的基础上,提出以下优化:

  1. 避免浮点运算

    • 使用整数除法和四舍五入的等效操作:

      cpp 复制代码
      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 的效果,且无需浮点运算。

  2. I/O 优化

    • 如果数据量较大,可以使用更高效的输入输出方法:

      cpp 复制代码
      ios::sync_with_stdio(false);
      cin.tie(nullptr);

💯小结


  • 通过本文对图像模糊处理问题的详解,我们不仅学习了如何处理二维数组,还深入对比了两种实现方式,掌握了边界处理、四舍五入、浮点运算优化等技巧。这些经验可迁移至其他矩阵操作类题目中,为复杂问题的求解提供清晰的思路和工具。希望这篇文章对你有所启发!


相关推荐
学习前端的小z1 天前
【C++】B2101 计算矩阵边缘元素之和
c
学习前端的小z2 天前
【C++】P1428 小鱼比可爱
c
学习前端的小z3 天前
【C++】深入理解C语言中的特殊字符处理与问题分析优化
c
XLYcmy3 天前
分布式练手:Client
c++·windows·分布式·网络安全·操作系统·c·实验源码
XLYcmy4 天前
分布式练手:Server
c++·windows·分布式·网络安全·操作系统·c·实验源码
学习前端的小z5 天前
【C++】B2089 数组逆序重存放
c
charlie1145141916 天前
如何使用 OpenCV 扫描图像、查找表和时间测量
c++·opencv·学习·计算机视觉·c·教程
charlie1145141916 天前
Linux Kernel Programming4
linux·c·makefile·内核开发·内核日志
学习前端的小z7 天前
【C++】2029:【例4.15】水仙花数
c