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

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

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

实验要求

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. 矢量中值滤波算法实验现象

在这里插入图片描述

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

写的什么石山代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值