使用VC++设计程序实现K近邻中值滤波器(KNNMF)、最小均方差滤波器、矢量中值滤波算法进行滤波

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

获取源工程可访问gitee可在此工程的基础上进行学习。
该工程的其他文章:
01- 一元熵值、二维熵值
02- 图像平移变换,图像缩放、图像裁剪、图像对角线镜像以及图像的旋转
03-邻域平均平滑算法、中值滤波算法、K近邻均值滤波器
04-分段线性变换,直方图均衡化、锐化处理
05-基于拉普拉斯算子、Canny的边缘检测功能、实现Otsu分割方法
06-最近邻插值,双线性插值,立方卷积插值
07-全局固定阈值分割、自适应阈值分割

文章目录

  • VC++实现若干种图像滤波技术2
    • 实验要求
    • 一、K近邻中值滤波器(KNNMF)
      • 1. K近邻中值滤波器(KNNMF)原理
      • 2. K近邻中值滤波器(KNNMF)实验代码
      • 3. K近邻中值滤波器(KNNMF)实验现象
    • 二、 最小均方差滤波器
      • 1. 最小均方差滤波器原理
      • 2. 最小均方差滤波器实验代码
      • 3. 最小均方差滤波器实验现象
    • 彩色图像矢量中值滤波算法
      • 1. 矢量中值滤波算法原理
      • 2. 矢量中值滤波算法实验代码
      • 3. 矢量中值滤波算法实验现象

实验要求

B部分:
(1)包括A部分全部要求。
(2)使用VC++设计程序:对一幅256级灰度图像,分别使用K近邻中值滤波器(KNNMF)、最小均方差滤波器进行滤波。
(3)使用VC++设计程序:对一幅24位彩色图像,使用矢量中值滤波算法进行滤波。

一、K近邻中值滤波器(KNNMF)

1. K近邻中值滤波器(KNNMF)原理

KNNMF(K-Nearest Neighbors Mean Filter)是一种非线性滤波算法,它利用每个像素点周围的 K 个最近邻居的平均值进行图像平滑。与传统的平均滤波器不同,KNNMF选择最相似的像素进行平均,这有助于在滤波的同时更好地保留图像的细节。

以下是KNNMF的基本步骤:

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

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

  3. 计算邻居的相似度: 计算窗口内每个像素与中心像素的相似度,可以使用像素值之间的距离来衡量相似度。

  4. 选择相似度最高的 K 个邻居: 选择相似度最高的 K 个邻居进行平均。

  5. 更新像素值: 将该像素的值替换为相似度最高的 K 个邻居的平均值。

KNNMF算法相对于传统的平均滤波器,更注重选择相似度高的邻居进行平均,这有助于更好地保留图像的特征。在实际应用中,相似度的计算可以采用不同的度量方式,例如欧氏距离、余弦相似度等,具体取决于图像的特点和应用场景。

2. K近邻中值滤波器(KNNMF)实验代码

void CImageProcessingView::OnEnhanceDenoiseKNNMF()
{
 // 实验 图像平滑 256级灰度图像 KNNMF滤波
 // 参考 CImageProcessingView::OnEnhanceDenoiseAverage()
 //MessageBox("请在这里设计 256级灰度图像 KNNMF滤波 算法");
 
 // 获得当前文档对象
    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);
  
 //**********KNNMF滤波 算法**************//
 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;
     }
    }
   }

  int midgray = 0;//中值
  for (m = 1; m <= kNN/2 ; m++)
   midgray = grays[m];
  pDoc->m_pDibTest->SetPixelGray(i, j, midgray);
  }
 }

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

3. K近邻中值滤波器(KNNMF)实验现象

在这里插入图片描述

二、 最小均方差滤波器

1. 最小均方差滤波器原理

最小均方差滤波是一种图像处理中常用的滤波方法,其目标是通过在像素邻域内选择合适的权重,使得滤波后的像素值与邻域内的像素值之间的均方差最小。

滤波过程中,对于每个像素,通过选取邻域内的像素进行加权平均,其中每个像素的权重由该像素与中心像素之间的差异以及一个权重函数决定。权重函数通常是关于像素差异的一个单调递减函数,以便更重视与中心像素相似的像素。

最小均方差滤波的目标函数可以表示为:

E ( u , v ) = ∑ i = − N N ∑ j = − N N w [ i , j ] ( I ( u + i , v + j ) − T ( u , v ) ) 2 E(u,v) = \sum_{i=-N}^{N} \sum_{j=-N}^{N} w[i,j](I(u+i,v+j) - T(u,v))^2 E(u,v)=i=NNj=NNw[i,j](I(u+i,v+j)T(u,v))2

其中:

  • $ (u,v) $ 是滤波后图像中的像素位置。
  • $ (i,j) $ 是邻域内像素的偏移。
  • $ I(u+i,v+j) $ 是邻域内某个像素的灰度值。
  • $ T(u,v) $ 是中心像素的灰度值。
  • $ w(i,j) $ 是权重函数。

最小均方差滤波的目标是找到使得目标函数 ( E(u,v) ) 最小的滤波器系数。这通常通过最小化目标函数的导数为零来实现。

具体实现最小均方差滤波需要对权重函数、邻域大小等进行合理的选择,以适应不同的图像处理任务。

2. 最小均方差滤波器实验代码

//**********最小均方差滤波算法**************//
int templateWidth = 3;
int templateHeight = 3;

for (int i = templateWidth / 2; i < width - templateWidth / 2; i++)
{
 for (int j = templateHeight / 2; j < height - templateHeight / 2; j++)
 {
  double minMSE = DBL_MAX; // 最小均方差初始化为最大值
  int optimalGray = 0;

 // 尝试所有可能的灰度值
  for (int k = 0; k <= 255; k++)
  {
   double mse = 0.0;

   // 计算邻域内所有像素与当前灰度值的均方差
   for (int n = 0; n < templateHeight; n++)
   {
    for (int m = 0; m < templateWidth; m++)
    {
     BYTE pixelValue = pDoc->m_pDibInit->GetPixelGray(i - templateWidth / 2 + m, j - templateHeight / 2 + n);
     mse += pow(pixelValue - k, 2);
    }
   }

   mse /= (templateWidth * templateHeight); // 均方差

   // 更新最小均方差和对应的灰度值
   if (mse < minMSE)
   {
    minMSE = mse;
    optimalGray = k;
   }
  }

  // 将最小均方差对应的灰度值设置为新的像素值
  pDoc->m_pDibTest->SetPixelGray(i, j, optimalGray);
 }
}

3. 最小均方差滤波器实验现象

左:加入噪声的图像
右:进行滤波后的图像

在这里插入图片描述

彩色图像矢量中值滤波算法

1. 矢量中值滤波算法原理

矢量中值滤波算法是一种基于中值运算的图像平滑处理方法。其原理可以概括为以下几个步骤:

  1. 选择邻域: 对于图像中的每个像素,定义一个邻域,包含该像素及其周围的像素。邻域的大小由窗口大小确定。

  2. 构建邻域矩阵: 将邻域内的像素值按某种顺序排列,形成一个矢量。这个矢量包含了邻域内所有像素的灰度值。

  3. 中值运算: 对构建的矢量进行中值运算,即找到矢量中的中间值。这可以通过对矢量进行排序,然后选择排序后的中间值来实现。

  4. 更新像素值: 将中值作为原始像素的新值,用于替代原始像素的灰度值。这样,经过矢量中值滤波处理后,图像中的每个像素都会得到一个中值平滑的结果。

矢量中值滤波的优点在于对图像进行平滑处理的同时能有效抑制噪声,特别适用于去除图像中的椒盐噪声等离群点。这种滤波方法在一些图像处理任务中取得了较好的效果,但也需要根据具体应用场景选择合适的窗口大小和滤波算法。

举个例子说明一下
假设我们有一个3x3的邻域矩阵,其像素值如下:

[ 10 20 15 30 25 40 35 15 20 ] \begin{bmatrix} 10 & 20 & 15 \\ 30 & 25 & 40 \\ 35 & 15 & 20 \\ \end{bmatrix} 103035202515154020

现在我们要进行矢量中值滤波,按照步骤来进行处理:

  1. 选择邻域: 我们选择一个3x3的邻域,以中心像素25为例。

  2. 构建邻域矩阵: 将邻域内的像素值按顺序排列成矢量:

$ \text{矢量} = [10, 20, 15, 30, 25, 40, 35, 15, 20] $

  1. 中值运算: 对矢量进行排序,得到:
    $\text{矢量} = [10, 15, 15, 20, 20, 25, 30, 35, 40] $

中值是排序后的中间值,即 $\text{中值} = 20 $。

  1. 更新像素值: 将中值20作为原始像素25的新值。

这样,经过矢量中值滤波处理后,中心像素的值由原来的25变为20。这个过程对图像中的每个像素都进行,以达到平滑图像的目的。这种方法在处理一些椒盐噪声等离群点时具有较好的效果。

2. 矢量中值滤波算法实验代码

//**********矢量中值滤波算法**************//
 int templateWidth = 3;
 int templateHeight = 3;
 int templateElementCnt = templateWidth * templateHeight;
 
 int color_r[100][100] = { 0 };
 int color_g[100][100] = { 0 };
 int color_b[100][100] = { 0 };


 for (int i = templateWidth / 2; i < pDoc->m_pDibInit->m_lpBMIH->biWidth - templateWidth / 2; i++)
 {
  for (int j = templateHeight / 2; j < pDoc->m_pDibInit->m_lpBMIH->biWidth - templateHeight / 2; j++)
  {
   // 获取当前像素点邻域的颜色信息
   for ( n = 0; n < templateHeight; n++)
    for ( m = 0; m < templateWidth; m++)
    {
     RGBQUAD quad;
     quad = pDoc->m_pDibInit->GetPixelColor(i - templateWidth / 2 + m, j - templateHeight / 2 + n);
     color_r[n][m] = quad.rgbRed;
     color_g[n][m] = quad.rgbGreen;
     color_b[n][m] = quad.rgbBlue;
    }

   int sum_r = 0, sum_g = 0, sum_b = 0;
   for ( n = 0; n < templateHeight; n++)
    for ( m = 0; m < templateWidth; m++)
    {
     sum_r += color_r[n][m];
     sum_g += color_g[n][m];
     sum_b += color_b[n][m];
    }
   
   int avl_r = sum_r / templateElementCnt;
   int avl_g = sum_g / templateElementCnt;
   int avl_b = sum_b / templateElementCnt;

   float min = 255;  //最小的r
   RGBQUAD Quad;
   for ( n = 0; n < templateHeight; n++)
    for ( m = 0; m < templateWidth; m++)
    {
     // 计算中值
     float temp = (pow((color_r[n][m] - avl_r), 2) + pow((color_g[n][m] - avl_g), 2) + pow((color_b[n][m] - avl_b), 2)) / 2;
     if (temp < min)
     {
      Quad.rgbRed = color_r[n][m];
      Quad.rgbGreen = color_g[n][m];
      Quad.rgbBlue = color_b[n][m];
      min = temp;
     }
    }
   pDoc->m_pDibTest->SetPixelColor(i, j, &Quad);
  }
 }

3. 矢量中值滤波算法实验现象

在这里插入图片描述

左:添加噪声的灰度图
右:使用矢量中值滤波算法后

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大学程序员的养生之道

呀哈喽&#xff0c;我是结衣。 今天给大家带来的是大学程序员的养生之道&#xff01; 作为一名大学生还没有深刻的感受到未来的恐怖&#xff0c;但每当我看到这些对程序员的评价还是不禁感慨。 不要让自己的学习之路变成这样啊&#xff01;程序员的职业发展&#xff1a;某编程语…

微机原理——并行接口8255学习1

目录 并行接口特点 可编程并行接口芯片8255 8255端口地址 8255的三种工作方式 8255的两种命令&#xff08;方式命令和C端口命令&#xff09; 由用户扩展的并行接口8255的应用 声光报警器接口设计 步进电机控制接口设计 PA端口实现跑马灯 PB端口实现按键输入 并行接口特…

Python第三方库版本管理(管理虚拟环境)

序言 最近使用python发现会有使用不同项目时需要的三方包依赖版本不同&#xff0c;如果各个项目相互切换&#xff0c;那么会经常需要更新版本。比如numpy当前版本时1.26.2&#xff0c;需要它小于版本1.21&#xff0c;有没有像Java一样通过Maven依赖管理中的版本控制去管理这些…

Linguistic Steganalysis in Few-Shot Scenario论文阅读笔记

TIFS期刊 A类期刊 新知识点 Introduction Linguistic Steganalysis in Few-Shot Scenario模型是个预训练方法。 评估了四种文本加密分析方法&#xff0c;TS-CSW、TS-RNN、Zou、SeSy&#xff0c;用于分析和训练的样本都由VAE-Stego生产(编码方式使用AC编码)。 实验是对比在少样…

JavaWeb(二)

一、SQL简介 结构化查询语言&#xff0c;一门操作关系型数据库的编程语言。英文&#xff1a;Structured Query Language&#xff0c;简称 SQL。 二、Mysql和Oracle关于区分大小写 MySQL在Windows下都不区分大小写。 oracle中分为两种情况&#xff0c;单纯的sql语句不区分大小…

深入理解网络非阻塞 I/O:NIO

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

非标设计之螺纹螺丝选型二

目录 一、螺丝的表面处理工艺&#xff1a;镀锌工艺&#xff1a;渗锌工艺&#xff1a;热浸锌工艺&#xff1a;达克罗工艺&#xff1a;镀镍工艺&#xff1a;氧化&#xff08;发黑&#xff09;工艺&#xff1a;电泳黑工艺&#xff1a;不锈钢螺钉&#xff1a; 二、按照颜色分工艺&a…

掌握视频剪辑技巧,轻松自定义视频速率,打造个性化出彩视频

你是否曾经因为视频节奏平淡而缺乏吸引力而苦恼&#xff1f;现在&#xff0c;我们为你推荐一款视频批量剪辑工具&#xff0c;让你轻松自定义视频速率&#xff0c;实现出彩个性化视频。 首先第一步&#xff0c;我们要打开好简单批量智剪&#xff0c;并登录账号。 第二步&#x…

三十五、Seata的基本架构、部署TC服务、微服务集成Seata

目录 一、基本架构 1、Seata事务中的三个重要角色 2、四种不同的分布式事务解决方案&#xff1a; 二、TC的部署 三、微服务集成Seata 1、引入Seata相关依赖 2、配置yml文件 3、启动服务 一、基本架构 Seata是 2019 年 1 月份蚂蚁金服和阿里巴巴共同开源的分布式事务解决…

centos7 yum安装mysql5.7

1.获取源 wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm 2.安装源 yum -y install mysql57-community-release-el7-11.noarch.rpm 3.安装mysql yum -y install mysql-server 4.如果出现下面错误&#xff0c;没有错误就忽略 使用以下命令解决…

如何在Rocky Linux中安装nmon

一、环境基础 [rootlocalhost nmon16d]# cat /etc/redhat-release Rocky Linux release 9.2 (Blue Onyx) [rootlocalhost nmon16d]# uname -r 5.14.0-284.11.1.el9_2.x86_64 [rootlocalhost nmon16d]# 二、安装步骤 在Rocky Linux和AlmaLinux等基于RHEL 的发行版上&#xff…

把握生成式AI新机遇,亚马逊云科技助力下一位独角兽

文章目录 前言亚马逊云科技生成式AI创业热潮向应用与工具链集中生成式AI初创生而全球化 赛道更细分、布局更广阔后记 前言 DoNews11月20日消息&#xff0c;当一项新技术出现&#xff0c;并成为行业主流甚至是变革的“敲门砖”时&#xff0c;企业应该如何应对&#xff1f; 202…

Zookeeper 安装与部署

Zookeeper官网 目录 1 配置文件参数解读2 Zookeeper 单点安装3 Zookeeper 分布式安装 1 配置文件参数解读 Zookeeper 中的配置文件 zoo.cfg 中参数含义解读如下&#xff1a; &#xff08;1&#xff09;tickTime 2000&#xff1a;通信心跳数&#xff0c;Zookeeper 服务器与客户…

Shutdown Signal: channel error; protocol method: #method<channel.close>

完整异常信息&#xff1a; Shutdown Signal: channel error; protocol method: #method<channel.close>(reply-code404, reply-textNOT_FOUND - no exchange fanoutExchange in vhost /, class-id60, method-id40) 意思是找不到名字是 fanoutExchange 的虚拟机 就是虚拟机…

增强现实技术革新零售业:提升购物体验的未来技术

增强现实&#xff08;AR&#xff09;技术正在改变零售业的面貌&#xff0c;为消费者提供了全新的购物体验。本文将探讨AR技术在零售行业中的应用&#xff0c;以及它如何改变传统的购物方式。 首先&#xff0c;AR技术允许消费者在现实世界中查看虚拟的产品展示。在服装和家具行业…

基于51单片机的交通灯_紧急开关+黄灯倒计时+可调时间

51单片机交通灯_紧急开关黄灯倒计时可调时间 开题报告系统硬件设计主控制器选择系统硬件结构图时钟及复位电路指示灯及倒计时模块 倒计时模块&#xff1a;程序软件主流程框架main函数 设计报告资料清单资料下载链接 基于51单片机交通灯_紧急开关黄灯倒计时可调时间 仿真图prote…

【DPDK】Trace Library

概述 跟踪是一种用于了解运行中的软件系统中发生了什么的技术。用于跟踪的软件被称为跟踪器&#xff0c;在概念上类似于磁带记录器。记录时&#xff0c;放置在软件源代码中的特定检测点会生成保存在巨大磁带上的事件&#xff1a;跟踪文件。稍后可以在跟踪查看器中打开跟踪文件…

【U8+】用友U8删除固定资产卡片,提示:当前卡片不是本月录入的卡片,不能删除。

【问题描述】 用友U8软件&#xff0c;参照已有账套新建账套的时候&#xff0c;选择结转期初余额。 例如&#xff1a;参照已有账套的2022年新建2023年的账套。 结转期初的时候勾选了固定资产模块&#xff0c; 建立成功后登录23年新的账套后&#xff0c;删除固定资产卡片&#xf…

17.字符串处理函数——字符串比较函数

文章目录 前言一、题目描述 二、解题 程序运行代码 总结 前言 本系列为字符串处理函数编程题&#xff0c;点滴成长&#xff0c;一起逆袭。 一、题目描述 二、解题 程序运行代码 #include<stdio.h> #include<string.h> int main() {char *str1 "hello wo…

【C++ regex】C++正则表达式

文章目录 前言一、正则表达式是什么&#xff1f;二、<regex>库的基础使用2.1 第一个示例2.1 <regex>库的函数详解std::regex_matchstd::regex_searchregex_search 和 regex_match 的区别std::regex_replacestd::regex_iterator 和 std::sregex_iterator&#xff1a…