当前位置:   article > 正文

【Emgu CV教程】6.2、图像平滑之最大值滤波

【Emgu CV教程】6.2、图像平滑之最大值滤波


前言

提示:Emgu CV中有很多滤波函数,但是偏偏没有最简单的最大值、最小值滤波。

今天讲最简单的最大值滤波,也就是像素点Point(X,Y)和周边的像素点进行比较,取最大的值替换掉Point(X,Y)的值。所以,最大值滤波,可以消除椒噪声,也就是去除暗斑,但会增强亮斑。


一、滤波核及原理

滤波核也叫滤波器,是Emgu CV中决定如何选择邻域像素点值判断的依据,滤波的过程称为卷积,这个在机器学习领域也是一个常见的操作,意思和这里一样。

滤波核包括两个概念:

  • 水平方向取值范围和垂直方向取值范围。
  • 每个邻域像素值的权重。

假如这里有一张原始图片,是单通道的灰度图,某个像素点P(x,y)值是66,见下图:
在这里插入图片描述
假如我的滤波核是15,也就是以66这个像素点为中心,水平方向取1个邻域,垂直方向取5个邻域,那么取出来的数据就是:
在这里插入图片描述
最大值滤波时,每个点像素值权重是1,很显然,这里的最大值就是226,目标图片中P(x,y)这个点的值就是226。
如果滤波核是3
3,那取出来的数据就是:
在这里插入图片描述
最大值滤波结果就变成了211,如果滤波核是5*5呢,结果就是254。这就能看出来几个问题:

选择不同的滤波核,有不同的结果。
滤波核越大,选取的范围越大,计算量也越大。
滤波核都是奇数,因为目标点是中心,左右的取值距离和上下的取值距离是相同的。

二、举例

1.原始素材

原始素材定义为srcMat,如下:
在这里插入图片描述
这是一个脸上长了雀斑的卡通人物,注意哈,雀斑颜色偏暗,最适合最大值滤波。

2.代码

C#内最大值滤波代码如下:

int ksizeX = 3;
int ksizeY = 3;
int width = srcMat.Cols;
int height = srcMat.Rows;
Mat dstMat = new Mat(new System.Drawing.Size(width, height), DepthType.Cv8U, 1);
Mat tempMat = srcMat.Clone();
Image<Bgr, int> dstImage = new Image<Bgr, int>(width, height);
Image<Bgr, int> tempImage = tempMat.ToImage<Bgr, int>();
int blueValue;
int greenValue;
int redValue;
int minX = 0 - (ksizeX / 2);
int maxX = (ksizeX / 2) + 1;
int minY = 0 - (ksizeY / 2);
int maxY = (ksizeY / 2) + 1;
for (int i = 0; i < height; i++)
{
    for (int j = 0; j < width; ++j)
    {
        blueValue = 0;
        greenValue = 0;
        redValue = 0;

        // 在邻域内查找
        for (int m = minY; m < maxY; m++)
        {
            for (int n = minX; n < maxX; n++)
            {
                if (i + m > -1 && j + n > -1 && i + m < height && j + n < width)
                {
                    if (tempImage.Data[i + m, j + n, 0] > blueValue)
                    {
                        blueValue = tempImage.Data[i + m, j + n, 0];
                    }

                    if (tempImage.Data[i + m, j + n, 1] > greenValue)
                    {
                        greenValue = tempImage.Data[i + m, j + n, 1];
                    }

                    if (tempImage.Data[i + m, j + n, 2] > redValue)
                    {
                        redValue = tempImage.Data[i + m, j + n, 2];
                    }
                }
            }
        }

        dstImage.Data[i, j, 0] = blueValue;
        dstImage.Data[i, j, 1] = greenValue;
        dstImage.Data[i, j, 2] = redValue;
    }
}

dstMat = dstImage.Mat;
dstMat.ConvertTo(dstMat, DepthType.Cv8U);
CvInvoke.Imshow("Max value fliter, " + dstMat.Size.ToString(), dstMat);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

代码很简单,原理如下:

1、滤波核是3*3,也就是以目标点为中心,要取到左上、上、右上、左、右、左下、下、右下共八个点和目标点进行比较。
2、按照原始图像的height和width进行遍历,计算目标图像的值。
3、ksizeX=3,因此minX = -1, maxX = 1。ksizeY=3,因此minY = -1, maxY = 1,假如正在计算Point(100,67),也就是第101行,68列。那么要再进行循环遍历,垂直方向是66,67,68,水平方向就是99,100,101,一共判断九个点,取各个通道的最大值。
4、if (i + m > -1 && j + n > -1 && i + m < height && j + n < width) 这个判断,就是让计算范围不能超过图像的上下左右边界。

3.运行结果

在这里插入图片描述
看一看,是不是脸上偏暗的黑点消失了。
这里还有一张图片,是利用上一篇的添加噪声的方法,分别添加了2000个黑色椒噪声和2000个白色盐噪声,如下图:
在这里插入图片描述
还是利用上述代码,只不过将让 int ksizeX = 5,int ksizeY = 5,输出结果就变成了这样:
在这里插入图片描述
是不是就像是我上面说的,最大值滤波去掉暗斑,但是会增强亮斑???


总结

最大值滤波很好理解,用起来效果也非常明显,但没有官方函数,只能自己写。读者们可以自己封装一个函数,方便以后直接调用,大概是这样就可以:

 public static void MaxValueFliter(
	IInputArray src,  // 输入目标图像
	IOutputArray dst, // 输出图像,与src具有相同大小和类型。
	int kernelX = 3, // X方向滤波核大小,默认是3
	int kernelY = 3 // Y方向滤波核大小,默认是3
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

原创不易,请勿抄袭。共同进步,相互学习。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/257686
推荐阅读
相关标签
  

闽ICP备14008679号