使用VC++设计程序使用邻域平均平滑算法、中值滤波算法、K近邻均值滤波器(KNNF)进行滤波

news2025/1/23 10:41:57

VC++实现若干种图像滤波技术

文章目录

  • VC++实现若干种图像滤波技术
    • 实验内容
    • 邻域平均平滑算法
      • 1. 原理
      • 2. 实验代码
      • 3. 实验现象
    • 中值滤波算法
      • 1. 原理
      • 2. 实验代码
      • 3.实验现象
    • K近邻均值滤波算法(KNNF)
      • 1. 原理
      • 2. 实验代码
      • 实验现象

实验内容

实验要求:
A部分:
(1)使用VC++设计程序:对一幅256级灰度图像,使用邻域平均平滑算法进行滤波。
(2)使用VC++设计程序:对一幅256级灰度图像,使用中值滤波算法进行滤波。
(3)使用VC++设计程序:对一幅256级灰度图像,使用K近邻均值滤波器(KNNF)进行滤波。

邻域平均平滑算法

1. 原理

邻域平均平滑算法是一种简单的图像平滑处理方法,它通过将每个像素的灰度值替换为其邻域内像素灰度值的平均值来实现。对于256级灰度图像,以下是一种简单的邻域平均平滑算法的步骤:
1.选择滤波器的大小: 确定邻域的大小,例如选择3x3或5x5的滤波器。
2.遍历图像像素: 对于图像中的每个像素,将其与邻域内的像素进行平均。
3.计算邻域平均值: 对于每个像素,计算邻域内像素的平均值。邻域可以是以该像素为中心的正方形区域,根据滤波器大小确定。
4.更新像素值: 将该像素的值替换为邻域平均值。

2. 实验代码

void CImageProcessingView::OnEnhanceDenoiseAverage()
{
 // 实验 图像平滑 256级灰度图像 邻域平均滤波
 
 // 获得当前文档对象
    CImageProcessingDoc* pDoc = GetDocument();
 if( pDoc->m_pDibInit->IsEmpty() )
 {
  MessageBox("图像未加载");
  return;
 }

 // 获得图像的基本信息
 int width = pDoc->m_pDibInit->GetWidth();
 int height = pDoc->m_pDibInit->GetHeight();
 int bitCount = pDoc->m_pDibInit->GetBitCount();
 // 程序只支持处理灰度图像
 if( bitCount!=8 )
 {
  MessageBox("目前只支持256级灰度图像");
  return;
 }
 // 将图像信息复制至 m_pDibTest
 pDoc->m_pDibTest->CloneDib(pDoc->m_pDibInit);
 // 设置去噪模板,这里使用一个3×3的去噪模板
 double templateDenoise[100] = 
  {1, 1, 1,
   1, 2, 1,
   1, 1, 1};
 int templateWidth = 3;
 int templateHeight = 3;
 int templateElementCnt = templateWidth*templateHeight;
 double sum1 = 0;
 
 // 归一化模板元素的值
 int i;
 for(i=0; i<templateElementCnt; i++)
  sum1 += templateDenoise[i];
 for(i=0; i<templateElementCnt; i++)
  templateDenoise[i] = templateDenoise[i]/sum1;

 // 定义临时变量 
 int j,m,n;
 BYTE gray;
 double value1;

 // 对图像里面的每一个像素进行 邻域
 // 为了方便,这里没有处理边界点
 for(i=templateWidth/2; i<pDoc->m_pDibInit->m_lpBMIH->biWidth-templateWidth/2; i++)
 {
  for(j=templateHeight/2; j<pDoc->m_pDibInit->m_lpBMIH->biWidth-templateHeight/2; j++)
  {
   // 当前的像素点是 (i, j) 。
   // 计算以 (i, j) 为中心,templateWidth为宽度,templateHeight为高度的矩形区域内,个个像素点颜色值的加权和。
   // 因为现在处理的是256色灰度图像,所以在 RGBQUAD结构中,Red、Green、Blue三个分量的值都肯定是相等的,
   // 所以只要处理Red分量,算出的结果也适用于Green分量和Blue分量
   value1 = 0;

   for(m=0; m<templateWidth; m++)
   {
    for(n=0; n<templateHeight; n++)
    {     
     gray = pDoc->m_pDibInit->GetPixelGray(i-templateWidth/2+m, j-templateHeight/2+n);
     
     value1 += gray * templateDenoise[n*templateWidth+m];
    }
   }
   pDoc->m_pDibTest->SetPixelGray(i, j, value1);
  }
 } 
 // 交换指针
 CDib* pTmpDib = pDoc->m_pDibTest;
 pDoc->m_pDibTest = pDoc->m_pDibInit;
 pDoc->m_pDibInit = pTmpDib;
 // 设置脏标记
 pDoc->SetModifiedFlag(TRUE);
 // 更新视图
 pDoc->UpdateAllViews(NULL);
}

3. 实验现象

左:灰度图原图
中:图片加入椒盐噪声
右:邻域平均平滑
在这里插入图片描述

中值滤波算法

1. 原理

中值滤波是一种非线性滤波算法,其原理是用窗口中像素的中值替代窗口中心像素的灰度值。这种方法对去除椒盐噪声(Salt-and-Pepper Noise)等脉冲性噪声效果较好。

中值滤波的基本步骤如下:

  1. 选择滤波器大小: 定义一个窗口,通常是正方形,大小为 n × n n \times n n×n,其中 n n n 为奇数,例如 3x3 或 5x5。

  2. 遍历图像像素: 对于图像中的每个像素,以其为中心取一个 n × n n \times n n×n的窗口。

  3. 排序窗口内像素值: 将窗口内的像素值按灰度值进行排序,找到中间值

  4. 更新像素值: 将该像素的值替换为窗口内像素值的中值。

这样,通过用窗口内像素的中值替代中心像素,可以有效地去除椒盐噪声等离群值,同时保留图像的边缘信息。

中值滤波相对于线性滤波,尤其是在存在脉冲性噪声的情况下,具有更好的去噪效果。然而,中值滤波也会导致图像细节的模糊,因此在应用中需要权衡滤波效果和细节保留。

2. 实验代码

void CImageProcessingView::OnEnhanceDenoiseMedian()
{
 // 实验 图像平滑 256级灰度图像 中值滤波
 // 参考 CImageProcessingView::OnEnhanceDenoiseAverage()
 //MessageBox("请在这里设计 256级灰度图像 中值滤波 算法");
 
 // 获得当前文档对象
    CImageProcessingDoc* pDoc = GetDocument();
 if( pDoc->m_pDibInit->IsEmpty() )
 {
  MessageBox("图像未加载");
  return;
 }

 // 获得图像的基本信息
 int width = pDoc->m_pDibInit->GetWidth();
 int height = pDoc->m_pDibInit->GetHeight();
 int bitCount = pDoc->m_pDibInit->GetBitCount();

 // 程序只支持处理灰度图像
 if( bitCount!=8 )
 {
  MessageBox("目前只支持256级灰度图像");
  return;
 }

 // 将图像信息复制至 m_pDibTest
 pDoc->m_pDibTest->CloneDib(pDoc->m_pDibInit);

 int i,j,m,n;
 BYTE grays[100];
 int graysSize = 100;
 int templateWidth = 3;
 int templateHeight = 3;
 int templateElementCnt = templateWidth*templateHeight;
 BYTE tempByte1;


 for(i=templateWidth/2; i<pDoc->m_pDibInit->m_lpBMIH->biWidth-templateWidth/2; i++)
 {
  for(j=templateHeight/2; j<pDoc->m_pDibInit->m_lpBMIH->biWidth-templateHeight/2; j++)
  {
   memset(grays, 0, graysSize*sizeof(BYTE));

   for(n=0; n<templateHeight; n++)
   {
    for(m=0; m<templateWidth; m++)
    {     
     grays[n*templateWidth+m] = pDoc->m_pDibInit->GetPixelGray(i-templateWidth/2+m, j-templateHeight/2+n);
    }
   }

   for(m=0; m<templateElementCnt-1; m++)
   {
    for(n=m+1; n<templateElementCnt; n++)
    {
     if( grays[m]>grays[n] )
     {
      tempByte1 = grays[m];
      grays[m] = grays[n];
      grays[n] = tempByte1;
     }
    }
   }

   pDoc->m_pDibTest->SetPixelGray(i, j, grays[templateElementCnt/2]);
  }
 }

 // 交换指针
 CDib* pTmpDib = pDoc->m_pDibTest;
 pDoc->m_pDibTest = pDoc->m_pDibInit;
 pDoc->m_pDibInit = pTmpDib; 
 
 // 设置脏标记
 pDoc->SetModifiedFlag(TRUE);
 
 // 更新视图
 pDoc->UpdateAllViews(NULL);
}

3.实验现象

左:添加椒盐噪声的灰度图像
右:使用中值滤波后
在这里插入图片描述

K近邻均值滤波算法(KNNF)

1. 原理

K近邻均值滤波(KNNF)是一种非线性滤波算法,它通过计算像素点周围的K个邻居的平均值来实现图像平滑。相比于传统的平均滤波,KNNF更加灵活,能够在一定程度上保留图像的边缘信息。

KNNF的基本步骤如下:

  1. 选择邻居数量 K K K 和滤波器大小: 确定每个像素点周围邻居的数量 K K K,同时选择一个滤波器的大小,通常是一个 n × n n \times n n×n 的窗口,其中 n n n 为奇数。

  2. 遍历图像像素: 对于图像中的每个像素,以其为中心取一个 n × n n \times n n×n 的窗口。

  3. 计算邻居的平均值: 计算窗口内邻居的平均值。

  4. 更新像素值: 将该像素的值替换为邻居的平均值。

这种滤波方法能够在一定程度上去除图像中的噪声,同时保留图像的整体结构和边缘信息。

在实现中,可以通过计算像素点间的距离来确定邻居,选择距离最近的K个像素进行平均。这个方法在一定程度上能够提高滤波的效果。

2. 实验代码

int i,j,m,n;
 BYTE grays[100];
 int graysSize = 100;
 int templateWidth = 3;
 int templateHeight = 3;
 int templateElementCnt = templateWidth*templateHeight;
 BYTE tempByte1;
 int kNN = 3;

 for(i=templateWidth/2; i<pDoc->m_pDibInit->m_lpBMIH->biWidth-templateWidth/2; i++)
 {
  for(j=templateHeight/2; j<pDoc->m_pDibInit->m_lpBMIH->biWidth-templateHeight/2; j++)
  {    
   memset(grays, 0, graysSize*sizeof(BYTE));

   for(n=0; n<templateHeight; n++)
   {
    for(m=0; m<templateWidth; m++)
    {    
     grays[n*templateWidth+m] = pDoc->m_pDibInit->GetPixelGray(i-templateWidth/2+m, j-templateHeight/2+n);
    }
   }
   
   BYTE centerGray = pDoc->m_pDibInit->GetPixelGray(i, j);

   for(m=0; m<templateElementCnt-1; m++)
   {
    for(n=m+1; n<templateElementCnt; n++)
    {
     if( abs(grays[m]-centerGray) > abs(grays[n]-centerGray) )
     {
      tempByte1 = grays[m];
      grays[m] = grays[n];
      grays[n] = tempByte1;
     }
    }
   }

   double avgGray = 0;
   for(m=0; m<kNN; m++)
   {
    avgGray += grays[m];
   }
   avgGray /= kNN; 

   pDoc->m_pDibTest->SetPixelGray(i, j, avgGray);
  }
 }

实验现象

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1214635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入了解域名与SSL证书的关系

在如今数字化的世界里&#xff0c;网络安全成为我们关注的重要议题之一。为了确保数据在网络上传输的安全性&#xff0c;我们通常会采取各种安全措施&#xff0c;其中最常用的就是SSL证书。然而&#xff0c;很多人并不了解SSL证书是如何与域名相互关联的。 首先&#xff0c;我…

TensorFlow案例学习:图片风格迁移

准备 官方教程&#xff1a; 任意风格的快速风格转换 模型下载地址&#xff1a; https://tfhub.dev/google/magenta/arbitrary-image-stylization-v1-256/2 学习 加载要处理的内容图片和风格图片 # 用于将图像裁剪为方形def crop_center(image):# 图片原始形状shape image…

基于风驱动算法优化概率神经网络PNN的分类预测 - 附代码

基于风驱动算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于风驱动算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于风驱动优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络…

Java排序算法之归并排序

图解 归并排序是一种效率比较高的分治排序算法&#xff0c;主要分为两个步骤&#xff0c;分别为“分”和“并”。 分&#xff1a;将序列不断二分&#xff0c;直到每个子序列只有一个元素为止。 并&#xff1a;将相邻两个子序列进行合并&#xff0c;合并时比较两个子序列的元素…

Vue3:给表格的单元格增加超链接功能(点击单元格可以跳转到新的页面)

一、目的 在Vue3项目中&#xff0c;给表格某个字段下的全部单元格添加超链接功能&#xff0c;点击对应的单元格可以进入对应的页面 二、定义单元格内容 使用ElementPlus的el-table组件来实现表格 1、代码 <template> <el-table :data"dataAll"> &…

LabVIEW进行MQTT通信及数据解析

需求&#xff1a;一般通过串口的方式进行数据的解析&#xff0c;但有时候硬件的限制&#xff0c;没法预留串口&#xff0c;那么如何通过网络的方式特别是MQTT数据的通信及解析 解决方式&#xff1a; 1.MQTT通信控件&#xff1a; 参考开源的mqtt-LabVIEW https://github.com…

TCP连接保活机制

在TCP连接中有一个保活机制&#xff0c;叫做Keep-Alive&#xff0c;用语言描述就是如下&#xff1a; 在保活时间内&#xff0c;如果没有任何连接相关的活动&#xff0c;TCP 保活机制会开始作用&#xff0c;每隔一个时间间隔&#xff08;保活时间间隔&#xff09;&#xff0c;发…

YOLOV8部署Android Studio安卓平台NCNN

下载Android Studio&#xff0c;配置安卓开发环境&#xff0c;这个过程比较漫长。 安装cmake&#xff0c;注意安装的是cmake3.10版本。 根据手机安卓版本选择相应的安卓版本&#xff0c;我的是红米K30Pro&#xff0c;安卓12。 使用腾讯开源的ncnn&#xff0c;这是一个为手机端极…

vue3实现数据大屏内数据向上滚动,鼠标进入停止滚动 vue3+Vue3SeamlessScroll

1.效果图 2.npm下载依赖及main.js文件配置 npm install vue3-seamless-scroll --saveimport vue3SeamlessScroll from vue3-seamless-scroll;app.use(vue3SeamlessScroll) 3.html代码 <!-- scrollFlag为true时再渲染,vue3只要涉及到传值子页面需要加flag判断&#xff0c;否…

阿里云今年服务器是真便宜,看看哪些云服务器值得买!

2023年双十一&#xff0c;阿里云推出了一项令人惊喜的独家优惠活动&#xff01;在这次活动中&#xff0c;阿里云开放了老用户购买权限&#xff0c;以超低的价格购买云服务器ECS经济型e实例。这款服务器配置了2核2G内存、3M固定带宽和40G ESSD entry系统盘。而且&#xff0c;更棒…

PDF文件中更改 PDF 文本颜色的最有效解决方案

PDF 是最常用的文档类型之一&#xff0c;也是商业中使用的首选文档。在工作中&#xff0c;我们经常需要修改PDF的文本内容&#xff0c;转换格式&#xff08;如PDF转Word&#xff0c;PDF转Excel等&#xff09;&#xff0c;合并PDF&#xff0c;以达到更好的工作效果。 然而&…

Docker 容器中的网络优化与 DNS 缓存清理

在使用Docker 18.03.1-ce版本在Ubuntu 18.04 LTS上运行多个Docker容器时&#xff0c;我发现当使用requests库发送请求到某个主机名时&#xff0c;响应速度非常慢。在本例中&#xff0c;每个容器都有自己的CherryPy服务器&#xff0c;并通过requests.get(http://main:8083)或req…

.NetCore手写一个 API 限流组件

首先如果APP 拥有游客模式&#xff0c;用户模式以及其他特殊权限。那就意味着需要 IP 限流、用户限流以及特殊权限的情况。 那我们直接实操一下&#xff0c;以 IP 限流作为参考案例&#xff0c;当然要以组件的形式编写&#xff0c;支持扩展。 首先我们创建一个抽象类接口&…

门禁管理超级麻烦,你方式用对了吗?

随着社会的不断进步和科技的飞速发展&#xff0c;安全管理成为我们日常生活和工作中至关重要的一环。在这个背景下&#xff0c;门禁监控系统逐渐崭露头角&#xff0c;成为保障各类场所安全的关键工具。 客户案例 企业办公楼 在现代企业中&#xff0c;保护办公场所的安全至关重…

线程锁的应用与示例代码

为了解决这个问题&#xff0c;可以使用线程锁来确保在提取zip文件中的每个文件时&#xff0c;同一时间只有一个线程可以访问文件。这样可以避免多个线程同时访问和写入文件&#xff0c;从而解决race condition的问题。以下是修改后的示例代码&#xff1a; python import reque…

<C++> 反向迭代器

我们知道正向迭代器的设计&#xff1a;begin迭代器指向第一个数据&#xff0c;end迭代器指向最后一个数据的下一个位置 。移向下一个数据&#xff0c;解引用得到数据的值&#xff0c;并根据容器储存方式的不同&#xff0c;容器有不同类型的迭代器。 注意&#xff1a;rbegin迭代…

Python Flask: 构建轻量级、灵活的Web应用

Flask是一个流行的Python Web框架&#xff0c;以其轻量级、灵活和易学的特性受到开发者的喜爱。本文将深入探讨Flask框架的各个方面&#xff0c;通过详实的示例代码&#xff0c;帮助大家更全面地了解和掌握这一强大的工具。 1. 安装与基本用法 首先&#xff0c;需要安装Flask。…

使用requests库解决Session对象设置超时的问题

在requests库的IRC频道中&#xff0c;提出了一个问题&#xff0c;即Session对象在requests库中没有一个可以全局设置的timeout属性&#xff0c;而是需要为每个请求传递timeout值&#xff0c;或者创建一个自定义子类来实现。 为了解决这个问题&#xff0c;可以向Session对象添加…

docker中怎么启动容器

1、首先在linux中使用以下命令来启动 Docker 服务&#xff1a; sudo systemctl start docker2、然后下面的命令显示所有的容器列表&#xff0c;包括正在运行和已停止的容器。 docker ps -a然后找到容器ID 3、使用 docker start 启动一个已停止的容器&#xff1a; docker s…

2024 年如何成为一名成功的漏洞赏金猎人?成长总结以及相关资料推荐

2024 年如何成为一名成功的漏洞赏金猎人?成长总结以及相关资料推荐。 很多狂热的黑客新手都很好奇,如何才能成为一名黑客。其实黑客也有黑帽、白帽、灰帽或红帽之类的称呼。黑帽黑客,指的是专门制造病毒木马、通过操作系统寻找漏洞牟取暴利,并且以个人意志为出发点,肆意攻…