2019-03-17 01:28:24 qq_40061319 阅读数 204
  • 机器学习之概率与统计推断

    本课程讲解机器学习算法所需概率和统计推断知识。概率部分包括概率公理及推论、条件概率、贝叶斯公式、随机变量及其概率函数(CDF/pdf)、常用概率分布及其均值、方差;统计推断部分包括大数定律和中心极限定理、极大似然估计、贝叶斯估计,估计的评价、偏差-方差平衡。课程还会讲解假设检验的基本概念。

    20455 人正在学习 去看看 AI100讲师

数字图像处理 均值滤波器

自写函数

%%自写滤波
I = double(imread('Fig3.35(a).jpg'));
[m,n] = size(I);
A3 = zeros(m,n);
A5 = zeros(m,n);
for i = 3:m-3
    for j = 3:n-3
        A3(i,j) = ( I(i-1,j-1)+I(i-1,j)+I(i-1,j+1)+I(i,j-1)+I(i,j)+I(i,j+1)+I(i+1,j-1)+I(i+1,j)+I(i+1,j+1))/9;
        A5(i,j)= ( I(i-2,j-2)+I(i-2,j-1)+I(i-2,j)+I(i-2,j+1)+I(i-2,j+2)+...
               I(i-1,j-2)+I(i-1,j-1)+I(i-1,j)+I(i-1,j+1)+I(i-1,j+2)+...
               I(i,j-2)+I(i,j-1)+I(i,j)+I(i,j+1)+I(i,j+2)+...
               I(i+1,j-2)+I(i+1,j-1)+I(i+1,j)+I(i+1,j+1)+I(i+1,j+2)+...
               I(i+2,j-2)+I(i+2,j-1)+I(i+2,j)+I(i+2,j+1)+I(i+2,j+2))/25;
    end
end
subplot(1,3,1),imshow(uint8(I));title('原图像');
subplot(1,3,2),imshow(uint8(A3));title('3X3均值滤波器');
subplot(1,3,3),imshow(uint8(A5));title('5X5均值滤波器');`

在这里插入图片描述

系统函数

%%系统滤波
I = double(imread('Fig3.35(a).jpg'));
[m,n] = size(I);
A3 = zeros(m,n);
A5 = zeros(m,n);
H1 = fspecial('average',[3,3]);
H2 = fspecial('average',[5,5]);
A3 = imfilter(I,H1);
A5 = imfilter(I,H2);
subplot(1,3,1),imshow(uint8(I));title('原图像');
subplot(1,3,2),imshow(uint8(A3));title('3X3均值滤波器');
subplot(1,3,3),imshow(uint8(A5));title('5X5均值滤波器');

在这里插入图片描述

参考文件

题目:均值滤波和中值滤波 在自己的证件照中加入椒盐噪声、高斯白噪声。
分别用33、55、7*7的均值滤波器和中值滤波器进行滤波。
处理过程

  1. 用imnoise函数在图像中分别加入椒盐噪声和高斯白噪声;
  2. 均值滤波:用fspecial函数创建各模板大小的均值滤波器,并用imfilter函数进行滤波。
    中值滤波:直接用matlab提供的medfilt2中值滤波器进行滤波即可。
    处理结果 程序清单 (1)

%%均值滤波

rgb=imread('photo.jpg');
 J1=imnoise(rgb,'salt & pepper',0.02);  %%添加噪声
 J2=imnoise(J1,'gaussian',0,0.01);		%%添加噪声
  h1=fspecial('average',[3,3]); 		%%平均滤波算子
  h2=fspecial('average',[5,5]); 
  h3=fspecial('average',[7,7]); 
  rgb1=imfilter(J2,h1); 			    %% 用算子使用平均滤波
  rgb2=imfilter(J2,h2);
  rgb3=imfilter(J2,h3); figure; 
  subplot(2,3,1);imshow(rgb) title('原图像'); 
  subplot(2,3,2);imshow(J2) title('加入噪声后的图像'); 
  subplot(2,3,4);imshow(rgb1) title('3*3均值滤波图像'); 
  subplot(2,3,5);imshow(rgb2) title('5*5均值滤波图像'); 
  subplot(2,3,6);imshow(rgb3) title('7*7均值滤波图像'); 

%%(2)中值滤波

	 rgb=imread('photo.jpg'); 
	J1=imnoise(rgb,'salt & pepper',0.02);  
	J2=imnoise(J1,'gaussian',0,0.01);   
	J3=rgb2gray(J2);
    rgb1=medfilt2(J3,[3 3]);
	rgb2=medfilt2(J3,[5 5]); 
	rgb3=medfilt2(J3,[7 7]); 

2020-03-16 09:29:03 Ibelievesunshine 阅读数 263
  • 机器学习之概率与统计推断

    本课程讲解机器学习算法所需概率和统计推断知识。概率部分包括概率公理及推论、条件概率、贝叶斯公式、随机变量及其概率函数(CDF/pdf)、常用概率分布及其均值、方差;统计推断部分包括大数定律和中心极限定理、极大似然估计、贝叶斯估计,估计的评价、偏差-方差平衡。课程还会讲解假设检验的基本概念。

    20455 人正在学习 去看看 AI100讲师

一. 均值滤波简介和原理

        均值滤波,是图像处理中常用的手段,从频率域观点来看均值滤波是一种低通滤波器,高频信号将会去掉。均值滤波可以帮助消除图像尖锐噪声,实现图像平滑,模糊等功能。理想的均值滤波是用每个像素和它周围像素计算出来的平均值替换图像中每个像素。

        以3*3均值滤波器为例,均值滤波器算法原理如下图:

          

                          ↑


二. 用均值滤波器对椒盐噪声污染后的图像去噪

        python 源码:

import cv2

import numpy as np

# mean filter

def mean_filter(img, K_size=3):

    H, W, C = img.shape

    # zero padding

    pad = K_size // 2

    out = np.zeros((H + pad * 2, W + pad * 2, C), dtype=np.float)

    out[pad: pad + H, pad: pad + W] = img.copy().astype(np.float)

    tmp = out.copy()

    # filtering

    for y in range(H):

        for x in range(W):

            for c in range(C):

                out[pad + y, pad + x, c] = np.mean(tmp[y: y + K_size, x: x + K_size, c])

    out = out[pad: pad + H, pad: pad + W].astype(np.uint8)

    return out

# Read image

img = cv2.imread("../paojie_sp1.jpg")

# Mean Filter

out = mean_filter(img, K_size=5)

# Save result

cv2.imwrite("out.jpg", out)

cv2.imshow("result", out)

cv2.waitKey(0)

cv2.destroyAllWindows()


三. 实验结果:

          

                    原图  ↑

          

                    模板大小5*5,均值滤波后的图像 ↑

        可以看到,均值滤波后,图像中噪声虽然有所减弱,但是图像变模糊了。因为均值滤波器过滤掉了图像中的高频分量,所以图像的边缘都变模糊了。(去除一定量椒盐噪声,可以考虑使用中值滤波)


四. 参考内容:

        https://www.jianshu.com/p/8a507f44d68d

        https://www.cnblogs.com/wojianxin/p/12501891.html

2019-08-30 13:12:16 qq_17592003 阅读数 459
  • 机器学习之概率与统计推断

    本课程讲解机器学习算法所需概率和统计推断知识。概率部分包括概率公理及推论、条件概率、贝叶斯公式、随机变量及其概率函数(CDF/pdf)、常用概率分布及其均值、方差;统计推断部分包括大数定律和中心极限定理、极大似然估计、贝叶斯估计,估计的评价、偏差-方差平衡。课程还会讲解假设检验的基本概念。

    20455 人正在学习 去看看 AI100讲师

[Matlab]实现对图像的均值滤波

软件环境 matlab R2017a

搜了不少关于使用滤波器的文章,都是直接调用现有函数,我在这里简单实现了均值滤波器


问题背景:实现复杂明暗条件下的图像二值化

例如要把这张图片二值化,用于后续识别 使用全局的阈值划分,可能会得到以下结果 一个更极端的例子
在这里插入图片描述 左下角的区域被错误处理 在这里插入图片描述

显然,我们希望得到如下结果
在这里插入图片描述
要得出这样的结果就需要对暗处进行补偿、降低过曝处亮度,因此有了滤波器的方案


理论基础

均值滤波器相关理论

  1. 基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点的均值代替,让周围的像素值接近的真实值,从而消除孤立的噪声点
  2. 方法是用某种结构的二维滑动窗口,将板内像素均值设为中心点的值

方案实施

  1. 举一个使用3*3的正方形窗口的例子,中心点取整个窗口中所有点的均值,实际常用图片宽度的1/16作为窗口半径

关于边界点的均值,提供3种处理方法供参考

  • 可以将矩阵向外扩充一圈,其值可以由某种算法产生(例如全填0或者是通过当前边界已有的值计算出)
  • 可以只计算窗口内有值的像素
  • 不改变(如下图)
    在这里插入图片描述
  1. 对第一张灰度图片全部做如此运算后可以得到一个带有各区域明暗信息的图片
    在这里插入图片描述

  2. 如果我们对它取反,这个图片就成为了一个亮度补偿数据,与原图片相加,可以得到在这里插入图片描述
    至此,我们的目的基本达到了,后续只需做简单处理可得到对比度更高的图像


matlab代码

clear;clc;
I = im2double(rgb2gray(imread('C:\Users\Bob Xiao\Desktop\3.png')));
% I(1,1)
[rows, cols] = size(I);
add = floor(cols/16);
windowSize = add*2+1;
newImg = padarray(I, [add,add]);    %填充边界之后的图片

bgImg = zeros(rows,cols);
for i=add+1:add+rows
    for j=add+1:add+cols
        myWin = newImg(i-add:i+add,j-add:j+add);
        bgImg(i-add,j-add) = AvgWin(myWin);
    end
end

pImg = I + bgImg;
            
figure(1);
subplot(2,2,1);
imshow(I);
subplot(2,2,2);
imshow(newImg);
subplot(2,2,3);
imshow(bgImg);
subplot(2,2,4);
imshow(pImg);

function [M] = AvgWin(IN)
% 传入一个矩阵,求均值
avg = mean(mean(IN));
M = avg;
end

写在后面:这个算法的时间复杂度非常高,达O(mnp2),(其基本操作:求窗口均值,内部的时间复杂度为O(n^2)),因而不适合实际应用。
Note:另有积分图方法,只需遍历一次图片,时间复杂度仅为O(mn)。

2018-12-12 20:03:53 iefenghao 阅读数 3637
  • 机器学习之概率与统计推断

    本课程讲解机器学习算法所需概率和统计推断知识。概率部分包括概率公理及推论、条件概率、贝叶斯公式、随机变量及其概率函数(CDF/pdf)、常用概率分布及其均值、方差;统计推断部分包括大数定律和中心极限定理、极大似然估计、贝叶斯估计,估计的评价、偏差-方差平衡。课程还会讲解假设检验的基本概念。

    20455 人正在学习 去看看 AI100讲师

采用算数均值滤波器,几何均值滤波器,中值滤波,自适应滤波器对图像进行滤波操作,并输出图像。
首先放一下结果:
在这里插入图片描述
(1)算术均值滤波器
计算子窗口的和并求平均
在这里插入图片描述
程序中对图像边缘不处理。右图为加入椒盐噪声,左图为算数均值滤波图像。

在这里插入图片描述在这里插入图片描述
程序实现:

//算数均值滤波
void CImageRecoveryDlg::ArithAverFilter( Mat &src, Mat &dst) {
	if (src.channels() == 3)//彩色图像
	{
		for (int i = 1; i < src.rows; ++i) {
			for (int j = 1; j < src.cols; ++j) {
				if ((i - 1 >= 0) && (j - 1) >= 0 && (i + 1) < src.rows && (j + 1) < src.cols) {//边缘不进行处理
					dst.at<Vec3b>(i, j)[0] = (src.at<Vec3b>(i, j)[0] + src.at<Vec3b>(i - 1, j - 1)[0] + src.at<Vec3b>(i - 1, j)[0] + src.at<Vec3b>(i, j - 1)[0] +
						src.at<Vec3b>(i - 1, j + 1)[0] + src.at<Vec3b>(i + 1, j - 1)[0] + src.at<Vec3b>(i + 1, j + 1)[0] + src.at<Vec3b>(i, j + 1)[0] +
						src.at<Vec3b>(i + 1, j)[0]) / 9;
					dst.at<Vec3b>(i, j)[1] = (src.at<Vec3b>(i, j)[1] + src.at<Vec3b>(i - 1, j - 1)[1] + src.at<Vec3b>(i - 1, j)[1] + src.at<Vec3b>(i, j - 1)[1] +
						src.at<Vec3b>(i - 1, j + 1)[1] + src.at<Vec3b>(i + 1, j - 1)[1] + src.at<Vec3b>(i + 1, j + 1)[1] + src.at<Vec3b>(i, j + 1)[1] +
						src.at<Vec3b>(i + 1, j)[1]) / 9;
					dst.at<Vec3b>(i, j)[2] = (src.at<Vec3b>(i, j)[2] + src.at<Vec3b>(i - 1, j - 1)[2] + src.at<Vec3b>(i - 1, j)[2] + src.at<Vec3b>(i, j - 1)[2] +
						src.at<Vec3b>(i - 1, j + 1)[2] + src.at<Vec3b>(i + 1, j - 1)[2] + src.at<Vec3b>(i + 1, j + 1)[2] + src.at<Vec3b>(i, j + 1)[2] +
						src.at<Vec3b>(i + 1, j)[2]) / 9;
				}
				else {//边缘赋值
					dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
					dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
					dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
				}
			}
		}
	}
	if (src.channels() == 1) {//灰度图像
		for (int i = 0; i < src.rows; i++) {
			for (int j = 0; j < src.cols; j++) {
				if ((i - 1 >= 0) && (j - 1) >= 0 && (i + 1) < src.rows && (j + 1) < src.cols) {//边缘不进行处理
					dst.at<uchar>(i, j) = (src.at<uchar>(i, j) + src.at<uchar>(i - 1, j - 1) + src.at<uchar>(i - 1, j) + src.at<uchar>(i, j - 1) +
						src.at<uchar>(i - 1, j + 1) + src.at<uchar>(i + 1, j - 1) + src.at<uchar>(i + 1, j + 1) + src.at<uchar>(i, j + 1) +
						src.at<uchar>(i + 1, j)) / 9;
				}
				else {//边缘赋值
					dst.at<uchar>(i, j) = src.at<uchar>(i, j);
				}
			}
		}
	}
	imshow("arithAverFilter", dst);
}

(2)几何均值滤波
对子窗口的元素相乘(需要判断是否为零),并对乘积求1/m*n次幂。
在这里插入图片描述
程序中需要判断窗口中的元素是否为0,如果为0则去除该元素。
右图为加入椒盐噪声的图像,左图为几何均值滤波后图像。
在这里插入图片描述在这里插入图片描述
程序实现:

//几何均值滤波
void CImageRecoveryDlg::GeoAverFliter(const Mat &src, Mat &dst) {
	Mat _dst(src.size(), CV_32FC1);
	double power = 1.0 / 9;
	cout << "power:" << power << endl;
	double geo = 1;
	if (src.channels() == 1) {
		for (int i = 0; i < src.rows; i++) {
			for (int j = 0; j < src.cols; j++) {
				if ((i - 1) > 0 && (i + 1) < src.rows && (j - 1) > 0 && (j + 1) < src.cols) {
					if (src.at<uchar>(i, j) != 0) geo = geo * src.at<uchar>(i, j);
					if (src.at<uchar>(i+1, j+1) != 0) geo = geo * src.at<uchar>(i+1, j+1);
					if (src.at<uchar>(i+1, j) != 0) geo = geo * src.at<uchar>(i+1, j);
					if (src.at<uchar>(i, j+1) != 0) geo = geo * src.at<uchar>(i, j+1);
					if (src.at<uchar>(i+1, j-1) != 0) geo = geo * src.at<uchar>(i+1, j-1);
					if (src.at<uchar>(i-1, j+1) != 0) geo = geo * src.at<uchar>(i-1, j+1);
					if (src.at<uchar>(i-1, j) != 0) geo = geo * src.at<uchar>(i-1, j);
					if (src.at<uchar>(i, j-1) != 0) geo = geo * src.at<uchar>(i, j-1);
					if (src.at<uchar>(i-1, j-1) != 0) geo = geo * src.at<uchar>(i-1, j-1);					
					/*geo = src.at<uchar>(i, j)* src.at<uchar>(i + 1, j + 1)* src.at<uchar>(i + 1, j)* src.at<uchar>(i, j + 1)*
						src.at<uchar>(i + 1, j - 1)* src.at<uchar>(i - 1, j + 1)* src.at<uchar>(i - 1, j)*
						src.at<uchar>(i, j - 1)* src.at<uchar>(i - 1, j - 1);*/
					_dst.at<float>(i, j)= pow(geo, power);
					geo = 1;
					//if (i % 10 == 0&&j%10==0)
						//printf("_dst.at<float>(%d, %d)=%f\n", i, j, _dst.at<float>(i, j));
					

				}
				else
					_dst.at<float>(i, j) = src.at<uchar>(i, j);
			}
		}
	}
	_dst.convertTo(dst, CV_8UC1);

	//_dst.copyTo(dst);//拷贝
	imshow("geoAverFilter", dst);

}

(3)中值滤波
找出子窗口中的中值,将其赋值给中心点。
在这里插入图片描述
程序中Median为寻找中值的函数,参数为子窗口的元素值。
左图为加入椒盐噪声的图像,右图为中值滤波的图像。

在这里插入图片描述在这里插入图片描述
可以看出中值滤波对椒盐噪声有很好的滤波效果。
程序实现:

//返回中值
uchar Median(uchar n1, uchar n2, uchar n3, uchar n4, uchar n5,
	uchar n6, uchar n7, uchar n8, uchar n9) {
	uchar arr[9];
	arr[0] = n1;
	arr[1] = n2;
	arr[2] = n3;
	arr[3] = n4;
	arr[4] = n5;
	arr[5] = n6;
	arr[6] = n7;
	arr[7] = n8;
	arr[8] = n9;
	for (int gap = 9 / 2; gap > 0; gap /= 2)//希尔排序
		for (int i = gap; i < 9; ++i)
			for (int j = i - gap; j >= 0 && arr[j] > arr[j + gap]; j -= gap)
				swap(arr[j], arr[j + gap]);
	return arr[4];//返回中值
}
//中值滤波
void CImageRecoveryDlg::MedianFliter(const Mat &src, Mat &dst) {
	if (!src.data)return;
	Mat _dst(src.size(), src.type());
	if (src.channels() == 3) {
		for (int i = 0; i < src.rows; ++i) {
			for (int j = 0; j < src.cols; ++j) {
				if ((i - 1) > 0 && (i + 1) < src.rows && (j - 1) > 0 && (j + 1) < src.cols) {
					_dst.at<Vec3b>(i, j)[0] = Median(src.at<Vec3b>(i, j)[0], src.at<Vec3b>(i + 1, j + 1)[0],
						src.at<Vec3b>(i + 1, j)[0], src.at<Vec3b>(i, j + 1)[0], src.at<Vec3b>(i + 1, j - 1)[0],
						src.at<Vec3b>(i - 1, j + 1)[0], src.at<Vec3b>(i - 1, j)[0], src.at<Vec3b>(i, j - 1)[0],
						src.at<Vec3b>(i - 1, j - 1)[0]);
					_dst.at<Vec3b>(i, j)[1] = Median(src.at<Vec3b>(i, j)[1], src.at<Vec3b>(i + 1, j + 1)[1],
						src.at<Vec3b>(i + 1, j)[1], src.at<Vec3b>(i, j + 1)[1], src.at<Vec3b>(i + 1, j - 1)[1],
						src.at<Vec3b>(i - 1, j + 1)[1], src.at<Vec3b>(i - 1, j)[1], src.at<Vec3b>(i, j - 1)[1],
						src.at<Vec3b>(i - 1, j - 1)[1]);
					_dst.at<Vec3b>(i, j)[2] = Median(src.at<Vec3b>(i, j)[2], src.at<Vec3b>(i + 1, j + 1)[2],
						src.at<Vec3b>(i + 1, j)[2], src.at<Vec3b>(i, j + 1)[2], src.at<Vec3b>(i + 1, j - 1)[2],
						src.at<Vec3b>(i - 1, j + 1)[2], src.at<Vec3b>(i - 1, j)[2], src.at<Vec3b>(i, j - 1)[2],
						src.at<Vec3b>(i - 1, j - 1)[2]);
				}
				else
					_dst.at<Vec3b>(i, j) = src.at<Vec3b>(i, j);
			}
		}
	}
	if (src.channels() == 1) {
		for (int i = 0; i < src.rows; ++i) {
			for (int j = 0; j < src.cols; ++j) {
				if ((i - 1) > 0 && (i + 1) < src.rows && (j - 1) > 0 && (j + 1) < src.cols) {
					_dst.at<uchar>(i, j) = Median(src.at<uchar>(i, j), src.at<uchar>(i + 1, j + 1),
						src.at<uchar>(i + 1, j), src.at<uchar>(i, j + 1), src.at<uchar>(i + 1, j - 1),
						src.at<uchar>(i - 1, j + 1), src.at<uchar>(i - 1, j), src.at<uchar>(i, j - 1),
						src.at<uchar>(i - 1, j - 1));
		
				}
				else
					_dst.at<uchar>(i, j) = src.at<uchar>(i, j);
			}
		}
	}
	_dst.copyTo(dst);//拷贝
	imshow("mediaFilter", dst);
}

(4)自适应滤波
Zmin=Sxy中的最小灰度值;
Zmax=Sxy中的最大灰度值;
Zmed=Sxy中的中值;
Zxy=坐标(x,y)处的灰度值;
Smax=Sxy所允许的最大尺寸(在程序中,用kernal_size表示);
左图为加入椒盐噪声的图像,右图为自适应滤波的图像。
在这里插入图片描述在这里插入图片描述
可以看出自适应滤波效果最好,但计算时间比中值滤波长很多,有很长的时延。
程序实现:

#define CV_ROI_ELEM(src,vector,m,n,ks)  \
{                                      \
    uchar* kn;                         \
    int st0=src.step[0];\
    int st1=src.step[1];\
    for(int k=0;k<(ks);k++)            \
    {                                  \
        for(int s=0;s<(ks);s++)        \
        {                              \
            kn =src.data+(k+m)*st0+(s+n)*st1;   \
            vector.push_back(*kn);              \
        }                                       \
    }                                           \
}

#define CV_MAT_ELEM2(src,dtype,y,x) \
    (dtype*)(src.data+src.step[0]*(y)+src.step[1]*(x))
//自适应滤波
void selfAdaptiveFilter(Mat&src, Mat&dst, int kernal_size)
{
	CV_Assert(src.type() == CV_8UC1 || src.type() == CV_8U);
	if (dst.empty())
	{
		dst.create(src.rows, src.cols, CV_8UC1);
	}
	uchar* pdst = dst.data;
	uchar Zmin, Zmax, Zmed, Zxy;
	int step0 = src.step[0];
	int step1 = src.step[1];
	for (int i = kernal_size / 2; i < src.rows - kernal_size / 2; i++)
	{
		for (int j = kernal_size / 2; j < src.cols - kernal_size / 2; j++)
		{
			int ks = 3;//kernal_size;
			int count = 0;
			Zxy = *CV_MAT_ELEM2(src, uchar, i, j);//Sxy覆盖区域的中心点像素值,即锚点像素值
			vector<uchar> v;//将模板覆盖区域的像素,压入矢量v中
			do {
				if (count == 0)
				{//获取模板ks*ks覆盖区域的像素,压入矢量v中
					CV_ROI_ELEM(src, v, i - ks / 2, j - ks / 2, ks);
				}
				else
				{
					/****************下面的for循环,将外扩的四个边的像素添加到v中**************/
					uchar* p = src.data + (i - ks / 2)*step0 + (j - ks / 2)*step1;
					for (int u = 0; u < ks; u++)
					{
						v.push_back(*(p + u * step1));//向外扩展的四个边的上边
						v.push_back(*(p + (ks - 1)*step0 + u * step1));//向外扩展的四个边的下边
						if (u != 0 && u != ks - 1)
						{
							v.push_back(*(p + u * step0));//向外扩展的四个边的左边
							v.push_back(*(p + u * step0 + (ks - 1)*step1));//向外扩展的四个边的右边
						}
					}
				}

				//对v的元素排序
				//排序后,Sxy覆盖区域内,最大值为Zmax=v[v.size-1],最小值为Zmin=v[0]
				std::sort(v.begin(), v.end());
				Zmin = v[0], Zmax = v[v.size() - 1], Zmed = v[ks*ks / 2];
				pdst = CV_MAT_ELEM2(dst, uchar, i, j);
				if (Zmin < Zmed&&Zmed < Zmax)
				{
					if (Zmin < Zxy&&Zxy < Zmax)
					{
						*pdst = Zxy; break;
					}
					else
					{
						*pdst = Zmed; break;
					}
				}
				else
				{
					ks += 2;
				}
				count++;
			} while (ks <= kernal_size);

			*pdst = Zmed;
		}
	}
	imshow("selfAdaptiveFilter", dst);
}

(5)整体比较
算数均值滤波在去除椒盐噪声的同时,图像也变得模糊。
几何均值滤波去除噪声同时,相对于算数均值滤波锐化。
中值滤波相比于前两者效果最好,去除了噪声,且图像损失较小。
自适应滤波是四者中效果最好的,但是计算复杂,有很大的延迟。
在这里插入图片描述
程序为MFC对话框程序,对话框程序如下:

//显示图像
void CImageRecoveryDlg::showMat(Mat &image, int i, String name) {
	CRect pic_rect;
	int width, height;
	//CWnd  *pWnd = GetDlgItem(i);
	GetDlgItem(i)->GetClientRect(&pic_rect);
	width = pic_rect.right;
	height = pic_rect.bottom;
	resize(image, image, Size(width, height));
	imshow(name, image);
}
//打开图像按钮
void CImageRecoveryDlg::OnBnClickedOpenBtn()
{

	CFileDialog fileDlg(true, _T("png"), NULL, 0, _T("image Files(*.bmp; *.jpg;*.png;*.tif)|*.JPG;*.PNG;*.BMP;*.TIF|All Files (*.*) |*.*||"), this);
	fileDlg.DoModal();
	//获取图片路径和图片名称
	strFilePath = fileDlg.GetPathName();
	strFileName = fileDlg.GetFileName();
	//判断路径不为空
	if (strFilePath == _T(""))
	{
		return;
	}

	image.Load(strFilePath);
	CImageToMat(image, src_Mat);

	//cvtColor(src_Mat, gray_Mat, COLOR_BGR2GRAY);//将图像转换为灰度图像
	imshow("src_image", src_Mat);
	showImage(image, IDC_INPUT_PIC);//显示图像
}

//加入噪声函数
void CImageRecoveryDlg::OnBnClickedNoiseBtn()
{
	Mat temp;
	//salt_Mat = src_Mat.clone();
	src_Mat.copyTo(salt_Mat);
	salt(salt_Mat, 0.1);
	temp = salt_Mat.clone();
	showMat(temp, IDC_NOSIC_PIC, "salt_image");
}

//算数均值滤波
void CImageRecoveryDlg::OnBnClickedCouBtn()
{
	Mat temp;
	Mat ArithAver_Mat(salt_Mat.size(), salt_Mat.type());
	cout << "salt_Mat.channels= " << salt_Mat.channels() << endl;//第一个元素值
	ArithAverFilter(salt_Mat, ArithAver_Mat);
	temp = ArithAver_Mat.clone();
	showMat(temp, IDC_COU_MEAN, "arithAver_image");
}

//中值滤波按钮
void CImageRecoveryDlg::OnBnClickedMediaBtn()
{
	Mat temp;
	Mat MedianFilter_Mat(salt_Mat.size(), salt_Mat.type());
	MedianFliter(salt_Mat, MedianFilter_Mat);
	temp = MedianFilter_Mat.clone();
	showMat(temp, IDC_MEDIA_FILTER, "medianFilter_image");
}

//几何均值滤波按钮
void CImageRecoveryDlg::OnBnClickedGeoBtn()
{
	Mat temp;
	Mat GeoAverFilter_Mat(salt_Mat.size(), salt_Mat.type());
	GeoAverFliter(salt_Mat, GeoAverFilter_Mat);
	temp = GeoAverFilter_Mat.clone();
	showMat(temp, IDC_GEO_MEAN, "GeoAverFliter_image");
}

//自适应滤波按钮
void CImageRecoveryDlg::OnBnClickedAdapteBtn()
{
	Mat temp;
	Mat selfAdaptiveFilter_Mat(salt_Mat.size(), salt_Mat.type());
	selfAdaptiveFilter(salt_Mat, selfAdaptiveFilter_Mat, 7);
	temp = selfAdaptiveFilter_Mat.clone();
	showMat(temp, IDC_ADAPT_FILTER, "selfAdaptiveFliter_image");
}

其中下列变量为全局变量

#define	PI	3.141592
CString strFilePath;
CString strFileName;
CImage image;
Mat src_image, gray_image, src_Mat, gray_Mat;
Mat salt_Mat,ArithAver_Mat;

以上为四种滤波函数的对比。

2019-08-14 21:35:48 EngineerHe 阅读数 584
  • 机器学习之概率与统计推断

    本课程讲解机器学习算法所需概率和统计推断知识。概率部分包括概率公理及推论、条件概率、贝叶斯公式、随机变量及其概率函数(CDF/pdf)、常用概率分布及其均值、方差;统计推断部分包括大数定律和中心极限定理、极大似然估计、贝叶斯估计,估计的评价、偏差-方差平衡。课程还会讲解假设检验的基本概念。

    20455 人正在学习 去看看 AI100讲师

图像处理常见滤波器–均值滤波、方框滤波、高斯滤波(上)

滤波,是用来将信号中特定波段频率踢出的操作,而用在图像的处理之中,则便是将图像之中的像素点进行一系列的基本运算的结果,用来提取,或者说是展现隐藏在图像之中的数学信息的手段。

什么是线性滤波?

一个二维的滤波器矩阵(或者叫卷积核),一个需要处理的二维图像,对于二维图像的每一个像素点,计算它的邻域像素和滤波器矩阵的对应元素的乘积,然后加起来,作为该像素位置的值,就这样,完成了一次滤波过程。

滤波器的数学表达形式:

M×NM \times N 的图像 ff 上,使用 m×nm \times n 的滤波器
g(x,y)=s=aat=bbw(s,t)f(x+s,y+t) {\rm{g}}(x,y) = \sum\limits_{s = - a}^a {\sum\limits_{t = - b}^b {w(s,t)f(x + s,y + t)} }
其中,m=2a+1m=2a+1n=2b+1n=2b+1w(s,t)w(s,t) 是滤波器系数,f(x,y)f(x,y) 是图像值;

空间滤波器也可以写成简化的形式:
R=w1z1+w1z1+...+wmnzmn=i=1mnwizi R = w_1z_1 + w_1z_1 + ... + w_{mn}z_{mn} = \sum\limits_{i = 1}^{mn} w_iz_i
其中,ww 是滤波器系统,zz 是与该系数对应图像灰度值,mnmn 为滤波器中包含的像素点总数

均值滤波

均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素(以目标象素为中心的周围8个像素,构成一个滤波模板,即去掉目标像素本身),再用模板中的全体像素的平均值来代替原来像素值。均值滤波其实就是对目标像素及周边像素取平均值后再填会目标像素来实现滤波目的的方法。

不足之处:均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。

均值滤波的权重系数模板:
K=1Kw×Kh[111111111] K = \frac{1}{{{K_w} \times {K_h}}}\left[ {\begin{array}{ccc} 1&1& \cdots &1\\ 1&1& \cdots &1\\ \vdots & \vdots & \vdots & \vdots \\ 1&1& \cdots &1 \end{array}} \right]
因为模板的权值都是1,所以整个图像的滤波也可以表示成下面式子的样子:
g(x,y)=1Mf(x,y)(x,y)N g(x,y) = \frac{1}{M}\sum {{\rm{f}}(x,y)\begin{array}{ccc} {}&{(x,y) \in N} \end{array}}
式子中g(x,y)g(x,y)为均值滤波后的图像,f(x,y)f(x,y)为原始图像,MM为模板中包括当前像素在内的像素个数,NN 为模板领域像素点集合。下图也更好的解释了滤波的过程(其实就是卷积),即 40+107+5+198+226+223+37+68+1939\frac {40+107+5+198+226+223+37+68+193}{9}

在这里插入图片描述

话不多说,用代码实现以下,这个在opencv里面有相应的库函数,直接调用就可以了,但是为了更好的理解什么事平滑滤波,这里先使用自己写的代码实现以下,然后和opencv里的库函数做对比,以验证实现的是否正确。

代码

# -*- coding: utf-8 -*-
"""
Created on Wed Aug 14 11:05:54 2019

@author: shengzhanhe
@e-mail: shengzhanhe@gmail.com
"""

import cv2
import numpy as np

def mean_filter(img_path, kernel_size):
    k_w, k_h = kernel_size
    img = cv2.imread(img_path)
    img_w, img_h, channel = img.shape
    
    # 这里为了可以提取到边框的信息,并且保持和原图大小想到,采用边界补零的操作
    res_b = np.zeros([img_w+k_w-1, img_h+k_h-1])
    res_g = np.zeros([img_w+k_w-1, img_h+k_h-1])
    res_r = np.zeros([img_w+k_w-1, img_h+k_h-1])
    # 把图像中每一个通道分离出来,放在相应的地方
    res_b[(k_w-1)//2:(1-k_w)//2, (k_h-1)//2:(1-k_h)//2] = cv2.split(img)[0]
    res_g[(k_w-1)//2:(1-k_w)//2, (k_h-1)//2:(1-k_h)//2] = cv2.split(img)[1]
    res_r[(k_w-1)//2:(1-k_w)//2, (k_h-1)//2:(1-k_h)//2] = cv2.split(img)[2]
    
    # 对每一个通道滤波
    b = fileter(res_b, kernel_size)
    g = fileter(res_g, kernel_size)
    r = fileter(res_r, kernel_size)
    
    # 通道融合
    res_img = cv2.merge([b, g, r])
    
    return res_img
    
    
def fileter(img_mat, kernel_size):
    k_w, k_h = kernel_size
    # 定义均值滤波器的权值
    kernel = np.ones([k_w, k_h])/(k_w*k_h)
    w, h = img_mat.shape
    
    fileter_res = np.zeros([w-k_w+1, h-k_h+1])
    
    # 对图像中的每一个像素值进行滤波
    for i in range(h-k_h):
        for j in range(w-k_w):
            pix = np.sum(img_mat[j:j+k_w,i:i+k_h]*kernel)
            fileter_res[j,i] = int(pix)
    return  fileter_res.astype(np.uint8)
            

# opencv实现均值滤波
def opencv_blur(img_path):
    img = cv2.imread(img_path)
    result = cv2.blur(img, (3, 3))
    
    return result
    
if __name__ == "__main__":
    path = './lenaNoise.png'
    image = cv2.imread(path)

    # 手动实现,使用3*3的卷积核
    my_img = mean_filter(path, (3,3))
    # 使用opencv里的库函数
    opencv_img = opencv_blur(path)
    cv2.imshow("original", image)
    cv2.imshow('my_img', my_img)
    cv2.imshow('opencv', opencv_img)
    cv2.imwrite('my_img.png', my_img)
    cv2.imwrite('opencv.png', opencv_img)
    cv2.waitKey(0)

3 * 3滤波器的效果
在这里插入图片描述

5 * 5滤波器的效果
在这里插入图片描述
7 * 7滤波器
在这里插入图片描述
可以看出自己实现的结果和opencv库函数是一样的,从滤波器的大小上也可以得出,滤波器(卷积核)越大,图像越平滑,但也显得更模糊。

方框滤波

方框滤波和均值滤波核基本上是一致的,主要的区别是要不要归一化处理,如果使用归一化处理,方框滤波就是均值滤波。

方框滤波的权重系数模板
K=1α[111111111],α={1Kw×Kh,normalize=true1,normalize=false K = \frac{1}{\alpha }\left[ {\begin{array}{ccc} 1&1& \cdots &1\\ 1&1& \cdots &1\\ \vdots & \vdots & \vdots & \vdots \\ 1&1& \cdots &1 \end{array}} \right],\begin{array}{ccc} {}&{\alpha = \left\{ {\begin{array}{ccc} {\frac{1}{{{K_w} \times {K_h}}},\begin{array}{ccc} {}&{normalize = true} \end{array}}\\ {1,\begin{array}{ccc} {\begin{array}{ccc} {\begin{array}{ccc} {}&{} \end{array}}&{} \end{array}}&{normalize = false} \end{array}} \end{array}} \right.} \end{array}
可以看出让方框滤波不采用归一化的时候,使用卷积核操作很容易使得像素值溢出,即对应的像素值为255。

这里就直接使用opencv里面的库函数,然后要是自己需要写代码的话,把上面的代码里添加一个α\alpha的判定条件就可以啦

代码如下

# -*- coding: utf-8 -*-
"""
Created on Wed Aug 14 11:05:54 2019

@author: shengzhanhe
@e-mail: shengzhanhe@gmail.com
"""

import cv2

# 方框滤波进行归一化处理就和均值滤波一样
image = cv2.imread('./lenaNoise.png')
# -1表示与原始图像深度一致
# 归一化处理
res1 = cv2.boxFilter(image, -1, (5,5), normalize=1)
# 不进行归一化处理
res2 = cv2.boxFilter(image, -1, (5,5), normalize=0)
res3 = cv2.boxFilter(image, -1, (3,3), normalize=0)

cv2.imshow('res1', res1)
cv2.imshow('res2', res2)
cv2.imshow('res3', res3)

cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述
从图上可以看出来,做了归一化处理的方框滤波就是均值滤波,然后没有做归一化处理的,图上好多都变成了白色,特别是 5×55 \times 5 大小的卷积核,基本上都是白的,最右侧是 3×33 \times 3 的卷积核的效果。

高斯滤波

高斯滤波是一种线性滤波。就是对整幅图像进行加权平均的过程,每个像素点的值都由其本身和邻域内的其它像素值经过加权平均后得到。它是图像平滑的一种重要的方式,能有效地消除和抑制噪声,达到图像平滑的效果。同时,相比于平均模板而言,效果更加自然。更加自然的意思,实际上说相对于就是适当地降低平滑后的模糊程度。

一维高斯函数
g(x)=1σ2πe(xμ)22σ2 {\rm{g}}(x) = \frac{1}{{\sigma \sqrt {2\pi } }}{e^{\frac{{ - {{(x - \mu )}^2}}}{{2{\sigma ^2}}}}}
二维高斯函数
g(x,y)=1σ2πe(xμ)2+(yv)22σ2 {\rm{g}}(x,y) = \frac{1}{{\sigma \sqrt {2\pi } }}{e^{ - \frac{{{{(x - \mu )}^2} + {{(y - v)}^2}}}{{2{\sigma ^2}}}}}
这里把 μ=0,v=0,σ=0.5\mu=0, v=0, \sigma = 0.5,画出高斯函数的一维和二维图像
在这里插入图片描述

有了公式以后高斯滤波器的核要怎么计算呢?一般是以核的中心为原点建立坐标系,在图像计算中,以中心坐标为基准,所以$\mu=0, v=0 $; 以一个3*3的滤波核为例,分三步:1.画出坐标模板,2.计算每一个位置的值,3.归一化,然后以 σ=1.5\sigma = 1.5 为例

在这里插入图片描述
上图操作中,归一化的目的是让权重的和等于1,如果大于1的话,滤镜会使得图像偏亮,小于1的话会使得图像偏暗。还有这样解释的12归一化之后,通过卷积计算出来的模板中心像素被限制到了0-255的灰度区间中。假若某一邻域内所有像素的灰度值为255,利用该模板进行卷积之后,求得的模板中心像素灰度值仍然为255;假若计算出来的高斯模板参数之和小于1,那么通过该模板进行卷积之后,模板中心像素的灰度值将小于255,偏离了实际的灰度值,产生了误差。

如果对精度没有要求的话,常用的 σ=1\sigma=1 的模板有下面两个

在这里插入图片描述
对于上述模板,你如果更加上述的公式计算的话,可能会发现有所偏差,这里我搜到的一种解释是这样的12高斯模板实际上也就是模拟高斯函数的特征,具有对称性并且数值由中心向四周不断减小,这个模板刚好符合这样的特性,并且非常简单,容易被大家接受,于是就比较经典!

下面是具体代码的实现,包括使用自己手动实现,和opencv库函数(库函数就一句话,很简单),实现的过程中,主要是当 σ<=0\sigma<=0 的情况,这里我参考的opencv库函数的处理方法,公式如下:
σ=(σ21)×0.3+0.8 \sigma {\rm{ = (}}\frac{\sigma }{2}{\rm{ - }}1) \times 0.3 + 0.8
代码

# -*- coding: utf-8 -*-
"""
Created on Wed Aug 14 11:05:54 2019

@author: shengzhanhe
@e-mail: shengzhanhe@gmail.com
"""

import math
import numpy as np
import cv2

def gauss_func(x, y, sigma=0):
    res = 0
    # 高斯函数
    res = 1.0/(2*math.pi*sigma**2)*math.exp(-(x**2+y**2)/(2*sigma**2))
    
    return res

def create_gauss_kernel(kernel_size, sigma):
    w,h = kernel_size
    center_x, center_y = w//2, h//2
    
    # sigma是否是正数,不是正数的话,需要单独处理
    if sigma > 0:
        sigma = sigma
    else:
        sigma = 0.3*((w-1)*0.5-1) + 0.8
    
    # 计算高斯核中的每一个权值
    kernel = np.zeros((w,h))
    for i in range(h):
        for j in range(w):
            x = j - center_x
            y = center_y - i
            kernel[i, j] = gauss_func(x, y, sigma)
    # normalize
    kernel = kernel/np.sum(kernel)
    
    return kernel

def fileter(img_mat, kernel_size, sigma):
    k_w, k_h = kernel_size
    # 高斯滤波器
    kernel = create_gauss_kernel(kernel_size, sigma)
    w, h = img_mat.shape
    
    fileter_res = np.zeros([w-k_w+1, h-k_h+1])
    
    # 对图像中的每一个像素值进行滤波
    for i in range(h-k_h):
        for j in range(w-k_w):
            pix = np.sum(img_mat[j:j+k_w,i:i+k_h]*kernel)
            fileter_res[j,i] = int(pix)
    return  fileter_res.astype(np.uint8)

def gauss_filter(img_path, kernel_size, sigma):
    k_w, k_h = kernel_size
    img = cv2.imread(img_path)
    img_w, img_h, channel = img.shape
    
    # 这里为了可以提取到边框的信息,并且保持和原图大小想到,采用边界补零的操作
    res_b = np.zeros([img_w+k_w-1, img_h+k_h-1])
    res_g = np.zeros([img_w+k_w-1, img_h+k_h-1])
    res_r = np.zeros([img_w+k_w-1, img_h+k_h-1])
    # 把图像中每一个通道分离出来,放在相应的地方
    res_b[(k_w-1)//2:(1-k_w)//2, (k_h-1)//2:(1-k_h)//2] = cv2.split(img)[0]
    res_g[(k_w-1)//2:(1-k_w)//2, (k_h-1)//2:(1-k_h)//2] = cv2.split(img)[1]
    res_r[(k_w-1)//2:(1-k_w)//2, (k_h-1)//2:(1-k_h)//2] = cv2.split(img)[2]
    
    # 对每一个通道滤波
    b = fileter(res_b, kernel_size, sigma)
    g = fileter(res_g, kernel_size, sigma)
    r = fileter(res_r, kernel_size, sigma)
    
    # 通道融合
    res_img = cv2.merge([b, g, r])
    
    return res_img
    

if __name__ == '__main__':
    
    path = './lenaNoise.png'
    image = cv2.imread(path)
    # 调用opencv库函数
    opencv_img = cv2.GaussianBlur(image, (3,3), 0)
    # 手动实现高斯滤波
    my_img = gauss_filter(path, (3,3), 0)
    
    cv2.imshow("original", image)
    cv2.imshow('my_img', my_img)
    cv2.imshow('opencv_img', opencv_img)
    cv2.imwrite('opencv_gauss3.png', opencv_img)
    cv2.imwrite('gauss3.png', my_img)
    cv2.waitKey(0)

3 * 3 滤波器
在这里插入图片描述

5 * 5 滤波器
在这里插入图片描述
7 * 7的滤波器

在这里插入图片描述
从图上可以看出,高斯滤波不同卷积核去燥的效果不一样,卷积核越大图像越模糊,但是相对相对于均值滤波而言,高斯滤波去燥的同时,也尽可能的保存了边缘信息(可以理解为模糊程度没有那么大,但是也达到了去噪的效果)!

欢迎大家关注我的个人公众号,同样的也是和该博客账号一样,专注分享技术问题,我们一起学习进步
在这里插入图片描述


  1. https://blog.csdn.net/lz0499/article/details/54015150 ↩︎ ↩︎

  2. https://lps-683.iteye.com/blog/2251180 ↩︎ ↩︎

均值滤波器的常见应用是pinghu

博文 来自: u011620352
没有更多推荐了,返回首页