图像处理算法算法

2018-12-12 17:03:01 lengjiayi 阅读数 3511

一些基本数字图像处理算法

版权声明:本文为原创文章,未经博主允许不得用于商业用途。

所有的图像算法都在DIPAlgorithm类中,并且所有算法都为抽象成员函数。我已经按照java注释规范为所有方法添加使用说明注释,具体实现可见于DIPAlgorithm.java,这里只做算法说明。

1 图像扭曲

在这里插入图片描述
模仿PS的扭曲功能,通过建立一个三角形映射网格实现对图像的扭曲。

如上图,一共设置了45个控制点围成74个三角形网格

扭曲即形变处理其实是寻找一个函数,以所有网格顶点原始坐标为输入,扭曲后所有网格顶点坐标为输出。为了简化计算任务,采用控制栅格插值方法,对每个三角网格独立计算映射关系,如下图:

在这里插入图片描述
即求解矩阵MM满足MA=BMA = B,其中AA为原顶点的齐次矩阵:

A=[x1y11x2y21x3y31] A = \begin{bmatrix} x_{1} & y_{1} & 1 \\ x_{2} & y_{2} & 1 \\ x_{3} & y_{3} & 1 \\ \end{bmatrix}

B为形变后顶点的其次矩阵:

B=[x1x2x3y1y2y3] B = \lbrack\begin{matrix} x_{1}^{'} & x_{2}^{'} & x_{3}^{'} \\ y_{1}^{'} & y_{2}^{'} & y_{3}^{'} \\ \end{matrix}\rbrack

M即为2×32 \times 3的映射矩阵,且由于三角形三点不共线,因此A为可逆阵,

M=BA1 M = BA^{- 1}

对于三角形中的点p(x, y)p\left( x,\ y \right),其映射后坐标p=M[xy1]p^{'} = M\begin{bmatrix} x \\ y \\ 1 \\ \end{bmatrix}

2 直方图计算

直方图计算实际上即求图像的概率密度函数PDF,只需遍历一次所有像素点即可获得。

3 直方图均衡化算法

对于连续图像直方图均衡化其实是种点运算f,
对不同灰度值做映射,使得所有像素频率相等。

对于点运算f,有如下性质:

DB=f(DA), HB(DB)ΔDB=HA(DA)ΔDA D_{B} = f\left( D_{A} \right),\ H_{B}\left( D_{B} \right)\Delta D_{B} = H_{A}\left( D_{A} \right)\Delta D_{A}

其中D为灰度值,H即为灰度值在图像中的频数,整理可得

HB(DB)=HA(DA)ΔDAΔDB=HA(DA)ΔDBΔDA=HA(DA)dDBdDA H_{B}\left( D_{B} \right) = \frac{H_{A}\left( D_{A} \right)\Delta D_{A}}{\Delta D_{B}} = \frac{H_{A}\left( D_{A} \right)}{\frac{\Delta D_{B}}{\Delta D_{A}}} = \frac{H_{A}\left( D_{A} \right)}{\frac{dD_{B}}{dD_{A}}}

=HA(DA)f(DA)=HA(f1(DB))f(f1(DB)) = \frac{H_{A}\left( D_{A} \right)}{f'(D_{A})} = \frac{H_{A}\left( f^{- 1}\left( D_{B} \right) \right)}{f'(f^{- 1}(D_{B}))}

即:

寻找函数f使得HB(D)H_{B}(D)为常数A0Dm,A0,Dm\frac{A_{0}}{D_{m}},A_{0},D_{m}

由(1)可知,KaTeX parse error: Undefined control sequence: \ at position 58: …\right)}{f'(D)}\̲ ̲\Rightarrow f^{…

f(D)=DmCDF(D)f\left( D \right) = D_{m}CDF(D),CDF即累积分布函数

因此只需求得直方图的前序和即可获得映射关系。

4 图像灰度化

目前比较符合人眼的灰度化权重为0.299、0.578和0.114,为了加速计算使用近似公式D=(3r+g+6b)/10D = (3r + g + 6b)/10

5 图像二值化

我使用的二值化算法为OSTU大律二值化算法。二值化操作即利用分割阈值u,将图片分为前景后景两部分。OSTU大律法认为使得前景像素和背景像素灰度方差g最大的阈值即为最佳分割阈值。

g=w0w1(u0u1)2 g = w_{0}w_{1}\left( u_{0} - u_{1} \right)^{2}

其中w0, w1w_{0},\ w_{1}为前景、后景在图像中的比例,KaTeX parse error: Undefined control sequence: \ at position 7: u_{0},\̲ ̲u_{1}为前景、后景的平均灰度。

在实现时,只需遍历所有灰度,利用CDF求出每种灰度的方差,取最大者作为阈值即可。

6 前景分离

目前主流的前景分离为深度学习算法。这里只使用了最基本的阈值分离法,分别为RGB三个通道设置不同阈值,将小于阈值的像素作为背景,大于阈值的作为前景。

7 滤波

我使用的滤波方法是高斯滤波和中值滤波,高斯滤波即使用二维高斯函数作为滤波函数,中值滤波即使用邻域的中位数作为滤波函数。

高斯滤波器为线性滤波器,可以有效消除高斯噪声。由于高斯函数离中值越近权重越大,因此相对于均值滤波器更加柔和,对边缘的保留效果更好。这里我使用的是如下矩阵做卷积:

[1232124642367632464212321] \begin{bmatrix} 1 & 2 & 3 & 2 & 1 \\ 2 & 4 & 6 & 4 & 2 \\ 3 & 6 & 7 & 6 & 3 \\ 2 & 4 & 6 & 4 & 2 \\ 1 & 2 & 3 & 2 & 1 \\ \end{bmatrix}

中值滤波器为非线性滤波器,可以有效的去除椒盐噪声和斑点噪声并且不会使图像变模糊。

8 形态学扩张和腐蚀

形态学腐蚀可记为AΘB\text{AΘB},其中A为输入图像,B为结构单元。对于二值图像,当且仅当当前像素点满足腐结构单元时才会被保留。对于灰度图像,则可类比为最小值,即

fΘb(x,y)=min{f(xx, yy)b(x,y)(x,yDb)} f\Theta b\left( x,y \right) = min\{ f\left( x - x^{'},\ y - y^{'} \right) - b(x^{'},y')|(x^{'},y^{'} \in D_{b})\}

形态学扩张可看作腐蚀的逆操作,记作ABA\bigoplus B,对于二值图像,将每个有效像素点的邻域结构单元置1,对于灰度图像则取最大值,即

fb(x,y)=max{f(xx, yy)b(x,y)(x,yDb)} f\bigoplus b\left( x,y \right) = max\{ f\left( x - x^{'},\ y - y^{'} \right) - b(x^{'},y')|(x^{'},y^{'} \in D_{b})\}

本程序将结构单元b统一设定为5*5矩形。

通过扩张和腐蚀的结合可实现结构开运算(AoB=(AΘB)BAoB = \left( \text{AΘB} \right)\bigoplus B)和结构闭运算(AoB=(AB)ΘBAoB = \left( A\bigoplus B \right)\text{ΘB})对图像进行粗化、细化、滤波等处理

9 傅里叶变换和滤波

变换公式

傅里叶变换可以将信号从时域转换到频域,因此可以看出许多时域中不明显的特征。二维傅里叶变换(CFT)公式如下:

F(u,v)=f(x,y)e2πj(ux+vy)dxdy F\left( u,v \right) = \iint_{}^{}{f\left( x,y \right)e^{- 2\pi\overrightarrow{j}(ux + vy)}}\text{dxdy}

其中j2=1,f,F{\overrightarrow{j}}^{2} = - 1,f,F,同样二维傅里叶逆变换公式如下:

f(x,y)=F(u,v)e2πj(ux+vy)dudv f\left( x,y \right) = \iint_{}^{}{F\left( u,v \right)e^{2\pi\overrightarrow{j}(ux + vy)}}\text{dudv}

对于离散函数,可以定义离散二维傅里叶变换(DFT)和逆变换:

G(m,n)=1MN0 i  M10<k<N1 g(i,k)e2πj(imM+jnN) G\left( m,n \right) = \frac{1}{\sqrt{\text{MN}}}\sum_{\begin{matrix} 0 \leq \ i\ \leq \ M - 1 \\ 0 < k < N - 1\ \\ \end{matrix}}^{}{g\left( i,k \right)e^{- 2\pi\overrightarrow{j}(\frac{\text{im}}{M} + \frac{\text{jn}}{N})}}

g(i,k)=1MN0 m  M10<n<N1 g(m,n)e2πj(imM+jnN) g\left( i,k \right) = \frac{1}{\sqrt{\text{MN}}}\sum_{\begin{matrix} 0 \leq \ m\ \leq \ M - 1 \\ 0 < n < N - 1\ \\ \end{matrix}}^{}{g\left( m,n \right)e^{2\pi\overrightarrow{j}(\frac{\text{im}}{M} + \frac{\text{jn}}{N})}}

DFT可以理解为对连续二维信号进行了频率为M,
N的采样,之后通过计算其和频域空间M*N个基向量的相关性(在该方向投影)将时域信号映射到频域。iDFT可以理解为通过M*N个基向量合成原始时域信号。

矩阵表示

傅里叶变换实际上是一种线性变换,因此在实际计算中常常将gg扩充为NNN*N方阵,此时DFT可以通过矩阵表示:G=W1gW,Wik=1Ne2πjikNG = \mathcal{W}^{- 1}g\mathcal{W},\mathcal{W}_{\text{ik}} = \frac{1}{N}e^{2\pi\overrightarrow{j}\frac{\text{ik}}{N}}

易知Wik=Wki\mathcal{W}_{\text{ik}} = \mathcal{W}_{\text{ki}},且为正交矩阵,因此W\mathcal{W}为酉矩阵,即W1=(W)T=W\mathcal{W}^{- 1} = \left( \mathcal{W}^{*} \right)^{T} = \mathcal{W}^{*}G=WgWG = \mathcal{W}^{*}g\mathcal{W},其中FFF^{*}F

由于傅里叶变换为酉变换,即Wt=W1\mathcal{W}^{t} = \mathcal{W}^{- 1}

图像的傅里叶变换

对于二维图片可以看作二维矩阵,因此可以进行DFT。二维图片经过DFT后获得的复矩阵的模矩阵可以表示每个频率信号的强度(也可看作先做自相关后再进行傅里叶变换),经过适当处理即可转化为灰度能量谱图片。

线性噪声在频域中通常为点或线,因此可以通过傅里叶变换后进行滤波再通过逆变换复原图片。

算法实现

在实际实现时,根据欧拉公式,ejt=costjsint, ejt=cost+jsinte^{- \overrightarrow{j}t} = cost - \overrightarrow{j}\text{sint},\ e^{\overrightarrow{j}t} = cost + \overrightarrow{j}\text{sint},因此傅里叶变换的核矩阵可以表示为Wik=cos(2πik)jsin(2πik)N\mathcal{W}_{\text{ik}} = \frac{\cos\left( 2\pi ik \right) - \overrightarrow{j}\sin\left( 2\pi ik \right)}{N},为方便运算将W\mathcal{W}分解为虚部系数Wlm\mathcal{W}_{\text{lm}}和实部系数Wre\mathcal{W}_{\text{re}},其中则W=Wre+jWlm\mathcal{W} = \mathcal{W}_{\text{re}} + \overrightarrow{j}\mathcal{W}_{\text{lm}}。变换结果同样分解为G=Gre+jGlmG = G_{\text{re}} + \overrightarrow{j}G_{\text{lm}},则DFT可以表示为:

G=WgW=(WrejWlm)g(Wre+jWlm)=WregWre+WlmgWlmj(WlmgWre+WregWlm) G = \mathcal{W}^{*}g\mathcal{W =}\left( \mathcal{W}_{\text{re}} - \overrightarrow{j}\mathcal{W}_{\text{lm}} \right)g\left( \mathcal{W}_{\text{re}} + \overrightarrow{j}\mathcal{W}_{\text{lm}} \right) = \mathcal{W}_{\text{re}}g\mathcal{W}_{\text{re}} + \mathcal{W}_{\text{lm}}g\mathcal{W}_{\text{lm}} - \overrightarrow{j}\left( \mathcal{W}_{\text{lm}}g\mathcal{W}_{\text{re}} + \mathcal{W}_{\text{re}}g\mathcal{W}_{\text{lm}} \right)

{Gre=WregWre+WlmgWlmGlm=WlmgWreWregWlm  \left\{ \begin{matrix} G_{\text{re}} = \mathcal{W}_{\text{re}}g\mathcal{W}_{\text{re}} + \mathcal{W}_{\text{lm}}g\mathcal{W}_{\text{lm}} \\ G_{\text{lm}} = - \mathcal{W}_{\text{lm}}g\mathcal{W}_{\text{re}} - \mathcal{W}_{\text{re}}g\mathcal{W}_{\text{lm}} \\ \end{matrix} \right.\

同理,iDFT可以表示为:

g=(Wre+jWlm)(Gre+jGlm)(WrejWlm) g = \left( \mathcal{W}_{\text{re}} + \overrightarrow{j}\mathcal{W}_{\text{lm}} \right)(G_{\text{re}} + {\overrightarrow{j}G}_{\text{lm}})\left( \mathcal{W}_{\text{re}} - \overrightarrow{j}\mathcal{W}_{\text{lm}} \right)

其中,为了将能量谱转化为可见的灰度图,为能量谱取对数值进行归一化。且由于在频域中两个维度频率都为0时(即W00\mathcal{W}_{00}处)为图像能量的总和,因此通过log(e+1)256log(W00+1)log(e + 1)*\frac{256}{\log\left( \mathcal{W}_{00} + 1 \right)}可以做进一步归一化。

算法代码可见github

2015-03-13 22:42:54 liuuze5 阅读数 14566

整理了一下网上一些公司对图像处理算法工程师的招聘要求:

                                                            图像处理算法工程师

 

职位要求

编程技能:

1、 具有较强的编程能力和良好的编程习惯, 精通c/c++编程,并熟练使用VS 或matlab开发环境;

2、 在计算机技术领域拥有扎实的技术功底,尤其在数据结构、算法和代码、软件设计方面功力深厚;

    对数据结构有一定的研究基础如链表、堆杖、树等,熟悉数据库编程;

3、 出色的算法分析能力,对某一特定算法可以做广泛的综述,有实际算法实现经验;

4、 熟悉面向对象编程思想,精于windows下的C/C++、VC++程序设计,熟悉MATLAB,对MFC有相对的了解和应用经验;

专业技能:

1、扎实的数学功底和分析技能,精通计算机视觉中的数学方法;

     高等数学(微积分)、线性代数(矩阵论)、随机过程、概率论、

     摄影几何、模型估计、数理统计、张量代数、数据挖掘、数值分析等;

2、具备模式识别、图像处理、机器视觉、信号处理和人工智能等基础知识;

     对图像特征、机器学习有深刻认识与理解;

3、精通图像处理基本概念和常用算法包括图像预处理算法和高级处理算法;

     常见的图像处理算法,包括增强、分割、复原、形态学处理等; 

     熟悉常见的模式识别算法,特别是基于图像的模式识别算法,掌握特征提取、特征统计和分类器设计; 
4、熟练使用OpenCV、Matlab、Halcon中的一种或一种以上工具库;

5、熟悉机器视觉系统的硬体选型,包括CCD相机,镜头及光源;熟悉相机与镜头搭配;

 

外语:

1. 英文熟练,能够熟练阅读和理解专业英文资料,有英文文献检索和阅读能力;
2. 良好的英语沟通能力

综合能力:

1.对工作认真负责,积极主动,勤奋踏实;

2.做事严谨,注重细节,有耐心,能够在压力下独立工作;

3.学习钻研能力强,有较强的理解能力和逻辑思维能力和良好的创新意识;

4.良好的协调沟通能力和团队合作精神; 

经验要求:

1.两年以上C/C++ 程序设计经验;

2.具有2年以上在Linux/Unix环境下用C/C++语言开发图像处理软件的经验。

3.数字图像处理、模式识别的理论知识和实践经验;

  有基于OpenCV开发项目经验,机器视觉行业经验;

  具有图像处理算法设计和开发经验;

  参与过机器视觉系统分析和设计;

4. 在Matlab 或其它数学软件上开发算法的经验;

 

视觉算法经验:请提供实现的算法列表

    目标识别、图像配准、三维测量、标定和重建、手势识别; 

    表面缺陷检测;尺寸测量;特征识别;

    图像去噪、滤波、融合算法
    3A算法:如自动曝光、自动对焦、自动白平衡


【工作内容】: 


1.为解决实际问题而进行探索性研究和创新,设计与模式识别、图像/视频智能分析处理相关的算法。

  图形图像处理、计算机视觉相关算法的研发以及应用程序的编写;

  参与核心软件项目算法设计及算法实现;研究图像处理算法,开发和调试算法原型

  软件算法研发:算法的代码实现、优化以及移植及其测试;

  负责机器视觉系统图象处理、分析及识别算法的设计、实现及调试;

  参与图象算法视觉应用软件的设计与实现。参与图象处理技术研究与设计;

2、对已有的计算机视觉算法进行实用化开发和优化研究;
   精益求精,将算法做到极致,使算法真正实用化;

  参与预研性的算法分析和论证,为产品开发提供基础研究及论证;


岗位职责:

1、 协助工程师进行算法的测试.;C++语言验证、测试算法;

2、编写算法规格说明;
3、相关专业文献的查阅; 
4、将部分matlab程序转为C或C++语言程序。 

1) 辅助图像处理工作
2) 大规模图像搜集与分类 
3) 与开发人员等进行沟通,跟踪产品的体验效果并改进;
4)负责公司的机器视觉与传感器项目的技术支持(如项目可行性评估、现场DEMO、装机、培训等)

   和 维护工作;

 

岗位职责:

1、负责计算机视觉中的图像采集,处理面阵和线扫描相机的成像和控制 ;
2、针对特定的计算机视觉问题,设计目标识别与快速定位与检测算法的实现,并进行优化;
3、对彩色图像和灰度图像实现物体表面的污点划痕检测算法设计和实现;
4、处理三维物体表面数据获取和实现三维测量算法的实现;
5、处理点激光和线激光源的成像,散斑噪声滤波和轮廓检测;
6、负责算法与软件GUI开发工程师接口;
7、完成上级领导交办的其他的工作。




 

图像算法工程师三重境界



一、传统图像算法工程师: 
主要涉及图形处理,包括形态学、图像质量、相机成像之3A算法、去雾处理、颜色空间转换、滤镜等,主要在安防公司或者机器视觉领域,包括缺陷检测;

二、现代图像算法工程师: 
涉及模式识别,主要表现的经验为AdaboostSVM的研究与应用,特征选取与提取,包括智能驾驶的研究与应用、行人检测、人脸识别;

三、人工智能时代图像算法工程师: 
深度学习,主要在大型互联网公司或者研究所机构,具体体现在TensorFlow等开源库的研究与应用,包括机器人的研、基于深度学习的人脸识别;







2016-08-07 16:14:35 jia20003 阅读数 11375

在二值图像处理特别是OCR识别与匹配中,都要通过对字符进行细化以便获得图像的骨架,通过zhang-suen细化算法获得图像,作为图像的特征之一,常用来作为识别或者模式匹配。

一:算法介绍

Zhang-Suen细化算法通常是一个迭代算法,整个迭代过程分为两步:

Step One:循环所有前景像素点,对符合如下条件的像素点标记为删除:

1.      2 <= N(p1) <=6

2.      S(P1) = 1

3.      P2 * P4 * P6 = 0

4.      P4 * P6 * P8 = 0

其中N(p1)表示跟P1相邻的8个像素点中,为前景像素点的个数

S(P1)表示从P2 ~ P9 ~ P2像素中出现0~1的累计次数,其中0表示背景,1表示前景

完整的P1 ~P9的像素位置与举例如下:


其中 N(p1) = 4, S(P1) = 3, P2*P4*P6=0*0*0=0, P4*P6*P8=0*0*1=0, 不符合条件,无需标记为删除。

Step Two:跟Step One很类似,条件1、2完全一致,只是条件3、4稍微不同,满足如下条件的像素P1则标记为删除,条件如下:

1.      2 <= N(p1) <=6

2.      S(P1) = 1

3.      P2 * P4 * P8 = 0

4.      P2 * P6 * P8 = 0

循环上述两步骤,直到两步中都没有像素被标记为删除为止,输出的结果即为二值图像细化后的骨架。

二:代码实现步骤

1.      二值化输入图像,初始化图像像素对应的标记映射数组

                BufferedImage binaryImage = super.process(image);
		int width = binaryImage.getWidth();
		int height = binaryImage.getHeight();
		int[] pixels = new int[width*height];
		int[] flagmap = new int[width*height];
		getRGB(binaryImage, 0, 0, width, height, pixels);
		Arrays.fill(flagmap, 0);

2.      迭代细化算法(Zhang-Suen)

a.      Step One

	private boolean step1Scan(int[] input, int[] flagmap, int width, int height) {
		boolean stop = true;
		int bc = 255 - fcolor;
		int p1=0, p2=0, p3=0;
		int p4=0, p5=0, p6=0;
		int p7=0, p8=0, p9=0;
		int offset = 0;
		for(int row=1; row<height-1; row++) {
			offset = row*width;
			for(int col=1; col<width-1; col++) {
				p1 = (input[offset+col]>>16)&0xff;
				if(p1 == bc) continue;
				p2 = (input[offset-width+col]>>16)&0xff;
				p3 = (input[offset-width+col+1]>>16)&0xff;
				p4 = (input[offset+col+1]>>16)&0xff;
				p5 = (input[offset+width+col+1]>>16)&0xff;
				p6 = (input[offset+width+col]>>16)&0xff;
				p7 = (input[offset+width+col-1]>>16)&0xff;
				p8 = (input[offset+col-1]>>16)&0xff;
				p9 = (input[offset-width+col-1]>>16)&0xff;
				// match 1 - 前景像素  0 - 背景像素
				p1 = (p1 == fcolor) ? 1 : 0;
				p2 = (p2 == fcolor) ? 1 : 0;
				p3 = (p3 == fcolor) ? 1 : 0;
				p4 = (p4 == fcolor) ? 1 : 0;
				p5 = (p5 == fcolor) ? 1 : 0;
				p6 = (p6 == fcolor) ? 1 : 0;
				p7 = (p7 == fcolor) ? 1 : 0;
				p8 = (p8 == fcolor) ? 1 : 0;
				p9 = (p9 == fcolor) ? 1 : 0;
				
				int con1 = p2+p3+p4+p5+p6+p7+p8+p9;
				String sequence = "" + String.valueOf(p2) + String.valueOf(p3) + String.valueOf(p4) + String.valueOf(p5) +
						String.valueOf(p6) + String.valueOf(p7) + String.valueOf(p8) + String.valueOf(p9) + String.valueOf(p2);
				int index1 = sequence.indexOf("01");
				int index2 = sequence.lastIndexOf("01");
				
				int con3 = p2*p4*p6;
				int con4 = p4*p6*p8;
				
				if((con1 >= 2 && con1 <= 6) && (index1 == index2) && con3 == 0 && con4 == 0) {
					flagmap[offset+col] = 1;
					stop = false;
				}

			}
		}
		return stop;
	}
b.      Step Two

	private boolean step2Scan(int[] input, int[] flagmap, int width, int height) {
		boolean stop = true;
		int bc = 255 - fcolor;
		int p1=0, p2=0, p3=0;
		int p4=0, p5=0, p6=0;
		int p7=0, p8=0, p9=0;
		int offset = 0;
		for(int row=1; row<height-1; row++) {
			offset = row*width;
			for(int col=1; col<width-1; col++) {
				p1 = (input[offset+col]>>16)&0xff;
				if(p1 == bc) continue;
				p2 = (input[offset-width+col]>>16)&0xff;
				p3 = (input[offset-width+col+1]>>16)&0xff;
				p4 = (input[offset+col+1]>>16)&0xff;
				p5 = (input[offset+width+col+1]>>16)&0xff;
				p6 = (input[offset+width+col]>>16)&0xff;
				p7 = (input[offset+width+col-1]>>16)&0xff;
				p8 = (input[offset+col-1]>>16)&0xff;
				p9 = (input[offset-width+col-1]>>16)&0xff;
				// match 1 - 前景像素  0 - 背景像素
				p1 = (p1 == fcolor) ? 1 : 0;
				p2 = (p2 == fcolor) ? 1 : 0;
				p3 = (p3 == fcolor) ? 1 : 0;
				p4 = (p4 == fcolor) ? 1 : 0;
				p5 = (p5 == fcolor) ? 1 : 0;
				p6 = (p6 == fcolor) ? 1 : 0;
				p7 = (p7 == fcolor) ? 1 : 0;
				p8 = (p8 == fcolor) ? 1 : 0;
				p9 = (p9 == fcolor) ? 1 : 0;
				
				int con1 = p2+p3+p4+p5+p6+p7+p8+p9;
				String sequence = "" + String.valueOf(p2) + String.valueOf(p3) + String.valueOf(p4) + String.valueOf(p5) +
						String.valueOf(p6) + String.valueOf(p7) + String.valueOf(p8) + String.valueOf(p9) + String.valueOf(p2);
				int index1 = sequence.indexOf("01");
				int index2 = sequence.lastIndexOf("01");
				
				int con3 = p2*p4*p8;
				int con4 = p2*p6*p8;
				
				if((con1 >= 2 && con1 <= 6) && (index1 == index2) && con3 == 0 && con4 == 0) {
					flagmap[offset+col] = 1;
					stop = false;
				}

			}
		}
		return stop;
	}
c.      检查如果上述两部没有任何像素被标记,则停止迭代,否则继续执行a, b

3.      返回细化后的图像,并显示

三:运行效果


四:完整的Zhang-suen算法代码实现:

import java.awt.image.BufferedImage;
import java.util.Arrays;

public class ZhangSuenThinFilter extends BinaryFilter {
	private int fcolor;
	public ZhangSuenThinFilter() {
		fcolor = 0;
	}

	public int getFcolor() {
		return fcolor;
	}


	public void setFcolor(int fcolor) {
		this.fcolor = fcolor;
	}
	
	@Override
	public BufferedImage process(BufferedImage image) {
		BufferedImage binaryImage = super.process(image);
		int width = binaryImage.getWidth();
		int height = binaryImage.getHeight();
		int[] pixels = new int[width*height];
		int[] flagmap = new int[width*height];
		getRGB(binaryImage, 0, 0, width, height, pixels);
		Arrays.fill(flagmap, 0);
		
		
		// 距离变化
		boolean stop = false;
		while(!stop) {
			// step one
			boolean s1 = step1Scan(pixels, flagmap, width, height);
			deletewithFlag(pixels, flagmap);
			Arrays.fill(flagmap, 0);
			// step two
			boolean s2 = step2Scan(pixels, flagmap, width, height);
			deletewithFlag(pixels, flagmap);
			Arrays.fill(flagmap, 0);
			if(s1 && s2) {
				stop = true;
			}
		}

		// 结果
		BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
		setRGB(bi, 0, 0, width, height, pixels);
		return bi;
	}
	
	private void deletewithFlag(int[] pixels, int[] flagmap) {
		int bc = 255 - fcolor;
		for(int i=0; i<pixels.length; i++) {
			if(flagmap[i] == 1) {
				pixels[i] = (0xff << 24) | ((bc&0xff) << 16) | ((bc&0xff) << 8) | (bc&0xff);
			}
		}
		
	}

	private boolean step1Scan(int[] input, int[] flagmap, int width, int height) {
		boolean stop = true;
		int bc = 255 - fcolor;
		int p1=0, p2=0, p3=0;
		int p4=0, p5=0, p6=0;
		int p7=0, p8=0, p9=0;
		int offset = 0;
		for(int row=1; row<height-1; row++) {
			offset = row*width;
			for(int col=1; col<width-1; col++) {
				p1 = (input[offset+col]>>16)&0xff;
				if(p1 == bc) continue;
				p2 = (input[offset-width+col]>>16)&0xff;
				p3 = (input[offset-width+col+1]>>16)&0xff;
				p4 = (input[offset+col+1]>>16)&0xff;
				p5 = (input[offset+width+col+1]>>16)&0xff;
				p6 = (input[offset+width+col]>>16)&0xff;
				p7 = (input[offset+width+col-1]>>16)&0xff;
				p8 = (input[offset+col-1]>>16)&0xff;
				p9 = (input[offset-width+col-1]>>16)&0xff;
				// match 1 - 前景像素  0 - 背景像素
				p1 = (p1 == fcolor) ? 1 : 0;
				p2 = (p2 == fcolor) ? 1 : 0;
				p3 = (p3 == fcolor) ? 1 : 0;
				p4 = (p4 == fcolor) ? 1 : 0;
				p5 = (p5 == fcolor) ? 1 : 0;
				p6 = (p6 == fcolor) ? 1 : 0;
				p7 = (p7 == fcolor) ? 1 : 0;
				p8 = (p8 == fcolor) ? 1 : 0;
				p9 = (p9 == fcolor) ? 1 : 0;
				
				int con1 = p2+p3+p4+p5+p6+p7+p8+p9;
				String sequence = "" + String.valueOf(p2) + String.valueOf(p3) + String.valueOf(p4) + String.valueOf(p5) +
						String.valueOf(p6) + String.valueOf(p7) + String.valueOf(p8) + String.valueOf(p9) + String.valueOf(p2);
				int index1 = sequence.indexOf("01");
				int index2 = sequence.lastIndexOf("01");
				
				int con3 = p2*p4*p6;
				int con4 = p4*p6*p8;
				
				if((con1 >= 2 && con1 <= 6) && (index1 == index2) && con3 == 0 && con4 == 0) {
					flagmap[offset+col] = 1;
					stop = false;
				}

			}
		}
		return stop;
	}
	
	private boolean step2Scan(int[] input, int[] flagmap, int width, int height) {
		boolean stop = true;
		int bc = 255 - fcolor;
		int p1=0, p2=0, p3=0;
		int p4=0, p5=0, p6=0;
		int p7=0, p8=0, p9=0;
		int offset = 0;
		for(int row=1; row<height-1; row++) {
			offset = row*width;
			for(int col=1; col<width-1; col++) {
				p1 = (input[offset+col]>>16)&0xff;
				if(p1 == bc) continue;
				p2 = (input[offset-width+col]>>16)&0xff;
				p3 = (input[offset-width+col+1]>>16)&0xff;
				p4 = (input[offset+col+1]>>16)&0xff;
				p5 = (input[offset+width+col+1]>>16)&0xff;
				p6 = (input[offset+width+col]>>16)&0xff;
				p7 = (input[offset+width+col-1]>>16)&0xff;
				p8 = (input[offset+col-1]>>16)&0xff;
				p9 = (input[offset-width+col-1]>>16)&0xff;
				// match 1 - 前景像素  0 - 背景像素
				p1 = (p1 == fcolor) ? 1 : 0;
				p2 = (p2 == fcolor) ? 1 : 0;
				p3 = (p3 == fcolor) ? 1 : 0;
				p4 = (p4 == fcolor) ? 1 : 0;
				p5 = (p5 == fcolor) ? 1 : 0;
				p6 = (p6 == fcolor) ? 1 : 0;
				p7 = (p7 == fcolor) ? 1 : 0;
				p8 = (p8 == fcolor) ? 1 : 0;
				p9 = (p9 == fcolor) ? 1 : 0;
				
				int con1 = p2+p3+p4+p5+p6+p7+p8+p9;
				String sequence = "" + String.valueOf(p2) + String.valueOf(p3) + String.valueOf(p4) + String.valueOf(p5) +
						String.valueOf(p6) + String.valueOf(p7) + String.valueOf(p8) + String.valueOf(p9) + String.valueOf(p2);
				int index1 = sequence.indexOf("01");
				int index2 = sequence.lastIndexOf("01");
				
				int con3 = p2*p4*p8;
				int con4 = p2*p6*p8;
				
				if((con1 >= 2 && con1 <= 6) && (index1 == index2) && con3 == 0 && con4 == 0) {
					flagmap[offset+col] = 1;
					stop = false;
				}

			}
		}
		return stop;
	}

}
觉得不错请支持一下!
2019-06-12 23:19:38 weixin_40300585 阅读数 3668
      版权声明:转载本博客文章,请附上链接,否则违版必究。          https://blog.csdn.net/weixin_42346564/article/details/83894235        </div>
        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-cd6c485e8b.css">
                          <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-cd6c485e8b.css">
      <div class="htmledit_views" id="content_views">
        <blockquote>

图像算法工程师三重境界 :


一、传统图像算法工程师: 
主要涉及图形处理,包括形态学、图像质量、相机成像之3A算法、去雾处理、颜色空间转换、滤镜等,主要在安防公司或者机器视觉领域,包括缺陷检测;

二、现代图像算法工程师
涉及模式识别,主要表现的经验为Adaboost、SVM的研究与应用,特征选取与提取,包括智能驾驶的研究与应用、行人检测、人脸识别;

三、人工智能时代图像算法工程师: 
深度学习,主要在大型互联网公司或者研究所机构,具体体现在TensorFlow等开源库的研究与应用,包括机器人的研究、基于深度学习的人脸识别;

 首先!!!算法工程师包括:

  • 音/视频算法工程师(通常统称为语音/视频/图形开发工程师)

  • 图像处理算法工程师

  • 计算机视觉算法工程师

  • 通信基带算法工程师

  • 信号算法工程师

  • 射频/通信算法工程师

  • 自然语言算法工程师

  • 数据挖掘算法工程师

  • 搜索算法工程师

  • 控制算法工程师(云台算法工程师,飞控算法工程师,机器人控制算法)

  • 导航算法工程师

  • 其他【其他一切需要复杂算法的行业】

图像处理算法工程师

相关术语:
(1) OCR:OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文字的过程
(2) Matlab:商业数学软件;
(3) CUDA: (Compute Unified Device Architecture),是显卡厂商NVIDIA推出的运算平台(由ISA和GPU构成)。 CUDA™是一种由NVIDIA推出的通用并行计算架构,该架构使GPU能够解决复杂的计算问题
(4) OpenCL: OpenCL是一个为异构平台编写程序的框架,此异构平台可由CPU,GPU或其他类型的处理器组成。
(5) OpenCV:开源计算机视觉库;OpenGL:开源图形库;Caffe:是一个清晰,可读性高,快速的深度学习框架。
(6) CNN:(深度学习)卷积神经网络(Convolutional Neural Network)CNN主要用来识别位移、缩放及其他形式扭曲不变性的二维图形。
(7) 开源库:指的是计算机行业中对所有人开发的代码库,所有人均可以使用并改进代码算法。

1必备技能总结

职位要求

编程技能:

1、 具有较强的编程能力和良好的编程习惯, 精通c/c++编程,并熟练使用VS 或matlab开发环境;

2、 在计算机技术领域拥有扎实的技术功底,尤其在数据结构、算法和代码、软件设计方面功力深厚;

    对数据结构有一定的研究基础如链表、堆杖、树等,熟悉数据库编程;

3、 出色的算法分析能力,对某一特定算法可以做广泛的综述,有实际算法实现经验;

4、 熟悉面向对象编程思想,精于windows下的C/C++、VC++程序设计,熟悉MATLAB,对MFC有相对的了解和应用经验;

 

专业技能:

1、扎实的数学功底和分析技能,精通计算机视觉中的数学方法;

     高等数学(微积分)、线性代数(矩阵论)、随机过程、概率论、

     摄影几何、模型估计、数理统计、张量代数、数据挖掘、数值分析等;

2、具备模式识别、图像处理、机器视觉、信号处理和人工智能等基础知识;

     对图像特征、机器学习有深刻认识与理解;

3、精通图像处理基本概念和常用算法包括图像预处理算法和高级处理算法;

     常见的图像处理算法,包括增强、分割、复原、形态学处理等; 

     熟悉常见的模式识别算法,特别是基于图像的模式识别算法,掌握特征提取、特征统计和分类器设计; 
4、熟练使用OpenCV、Matlab、Halcon中的一种或一种以上工具库;
5、熟悉机器视觉系统的硬体选型,包括CCD相机,镜头及光源;熟悉相机与镜头搭配;

 

外语:

1. 英文熟练,能够熟练阅读和理解专业英文资料,有英文文献检索和阅读能力;
2. 良好的英语沟通能力

综合能力:

1.对工作认真负责,积极主动,勤奋踏实;

2.做事严谨,注重细节,有耐心,能够在压力下独立工作;

3.学习钻研能力强,有较强的理解能力和逻辑思维能力和良好的创新意识;

4.良好的协调沟通能力和团队合作精神; 

 

视觉算法经验:请提供实现的算法列表

    目标识别、图像配准、三维测量、标定和重建、手势识别; 

    表面缺陷检测;尺寸测量;特征识别;

    图像去噪、滤波、融合算法
    3A算法:如自动曝光、自动对焦、自动白平衡

 

岗位职责:

1、负责计算机视觉中的图像采集,处理面阵和线扫描相机的成像和控制 ;
2、针对特定的计算机视觉问题,设计目标识别与快速定位与检测算法的实现,并进行优化;
3、对彩色图像和灰度图像实现物体表面的污点划痕检测算法设计和实现;
4、处理三维物体表面数据获取和实现三维测量算法的实现;
5、处理点激光和线激光源的成像,散斑噪声滤波和轮廓检测;
6、负责算法与软件GUI开发工程师接口;
7、完成上级领导交办的其他的工作。

 

2面试题大全

 

1-图像基础知识:

1.常用的图像空间。

2.简述你熟悉的聚类算法并说明其优缺点。

3.请描述以下任一概念:SIFT/SURF  LDA/PCA

4.请说出使用过的分类器和实现原理。

5. Random Forest的随机性表现在哪里。

6. Graph-cut的基本原理和应用。

7. GMM的基本原理和应用。

8.用具体算法举例说明监督学习和非监督学习的区别。

 

2-笔试

大概有: 
1.表示图像的特征有哪些? 
纹理,频率,梯度这种 
2.写出canny边缘提取算法的原理
3.图像插值方法 
4.自己设计一个OCR引擎 
5.写出Kmeans程序,并在一个设计环境中怎样使用 
6.中值滤波
7.static的作用 
8.写一个c++宏
9.二分查找 

整数翻转,如何处理越界问题

C++多态,静态联编和动态联编,虚函数表

模型融合如何做

提升树的思想,随机森林和提升树的区别

SVM推导,对偶性的作用,核函数有哪些,有什么区别

python两个每行都是数字的文件合并,去重。

shell编程,编辑文件。

进程与线程的区别

卷积神经网络介绍

SVM的推导

大文件求交集,如何解决哈希之后小文件还是放不进内存

堆排序代码

连续和最大问题,如何证明?

bp算法介绍,梯度弥散问题。

svm介绍,优缺点是什么,lr介绍,区别是什么

lr与线性回归的区别

如果要预测房价,用什么模型

如果要预测房价,并且知道一个房间的房型信息,如何构建模型

sigmoid 函数的应用有哪些,为什么?

列举十种常用的神经网络模型

语音识别模型有哪些

如何识别一个人在喝酒,需要几个模型

卷积神经网络中卷积如何实现,激活函数的意义,损失函数有哪些,初始化参数如何选择

用过哪些深度学习框架,TensorFlow中的session是什么,session和interactivesession的区别

如何实现卷积层权值共享

如何保存模型,读取已有的模型

用过哪些深度学习模型,区别是什么。

了解哪些寻优算法

softmax损失函数作用是

c++ 的 const,static作用

强制类型转换cast之间的区别

svm推导,核函数的体现,常用的核函数有哪些

alexnet介绍

过拟合的原因,有哪些避免过拟合的trick

1G的文本统计词频,输出频率最高的1000个词

手写topk的代码,快排。代码还能如何优化,如果要上线的话还需要做哪些处理

如果分类样本的标签只有一定的概率可信,如何处理

如何设置负样本

过拟合的原因,有哪些防止过拟合的方法

模型评价如何做,其中存在哪些问题

决策树算法有哪些,随机森林和GBDT的区别

降维方法,PCA原理

哈夫曼树在机器学习中的应用

文本挖掘算法了解哪些

人流量预测系统如何设计

profession笔试:最优的进程调度算法,至少用多少个cpu

英语自我介绍,口语渣猝不及防

联想研究院 模式识别研究员 offer

异常值的影响,如何消除

所有了解的机器学习算法有哪些,框架性讲述

梯度下降算法了解哪些,优劣势是什么

二叉树中序遍历,递归和非递归

linux操作指令了解哪些,文本处理指令有哪些

一亿个数的文件,如何分成两个文件a,b,使得a文件的数都小于b,同时文件大小要差不多。

均匀分布如何生成正态分布

SVM原理,支撑向量越多越好还是越少越好

二叉树深度遍历,时间复杂度和空间复杂度

二维排序矩阵搜索

项目中的长时间推广问题,如何考虑样本之间非独立的影响。

编程题,矩阵中的最短路,有门有钥匙。动态规划加状态向量。

贝叶斯公式,实际如何计算,如何解决精度问题。

字符串转数字

svm核函数有哪些,如何选取,手写表达式

降维方法介绍

c的虚函数,虚函数指针和虚函数表存在哪儿

Linux 文件权限修改,参数介绍

模型的比较如何做

随机森林和提升树

卷积神经网络原理

如何避免网络的过拟合

如何网络调优

Python 的数据结构有哪些

tuple 和set的区别,set的底层实现

hash表的算法有哪些

svm推导,一直到序列最小化求解。核函数如何体现,有哪些类型。

构建分类器的整个流程是什么

数据清洗方法,缺失值处理方法,降维方法

pca原理推导

决策树算法的介绍

二维排序数组搜索

如何构建欺诈交易识别的模型?

不均衡的数据如何分类

归并排序,二维排序数组搜索,中序遍历重构二叉树

svm推导,为什么要用拉格朗日乘数法,对偶问题是什么

KKT条件都有什么,如何求解svm的最优化问题

数据不均衡如何解决,抽样得到的分类准确率如何转换为原准确率。

逻辑回归原理,推导求解方法。

为什么选用对数极大似然函数作为优化目标,用平方损失有什么问题。

逻辑回归对特征有什么要求,是否需要做离散化,离散化的好处与坏处。

…………

……


原文:https://blog.csdn.net/litongwei7601/article/details/80132679 

2018-05-03 16:07:12 weixin_42026802 阅读数 73849
要学习高斯模糊我们首先要知道一些基本概念:

线性滤波与卷积的基本概念

      线性滤波可以说是图像处理最基本的方法,它可以允许我们对图像进行处理,产生很多不同的效果。做法很简单。首先,我们有一个二维的滤波器矩阵(有个高大上的名字叫卷积核)和一个要处理的二维图像。然后,对于图像的每一个像素点,计算它的邻域像素和滤波器矩阵的对应元素的乘积,然后加起来,作为该像素位置的值。这样就完成了滤波过程。

      对图像和滤波矩阵进行逐个元素相乘再求和的操作就相当于将一个二维的函数移动到另一个二维函数的所有位置,这个操作就叫卷积或者协相关。卷积和协相关的差别是,卷积需要先对滤波矩阵进行180的翻转,但如果矩阵是对称的,那么两者就没有什么差别了。

      Correlation 和 Convolution可以说是图像处理最基本的操作,但却非常有用。这两个操作有两个非常关键的特点:它们是线性的,而且具有平移不变性shift-invariant。平移不变性指我们在图像的每个位置都执行相同的操作。线性指这个操作是线性的,也就是我们用每个像素的邻域的线性组合来代替这个像素。这两个属性使得这个操作非常简单,因为线性操作是最简单的,然后在所有地方都做同样的操作就更简单了。

      实际上,在信号处理领域,卷积有广泛的意义,而且有其严格的数学定义,但在这里不关注这个。

      2D卷积需要4个嵌套循环4-double loop,所以它并不快,除非我们使用很小的卷积核。这里一般使用3x3或者5x5。而且,对于滤波器,也有一定的规则要求:

      1)滤波器的大小应该是奇数,这样它才有一个中心,例如3x3,5x5或者7x7。有中心了,也有了半径的称呼,例如5x5大小的核的半径就是2。

      2)滤波器矩阵所有的元素之和应该要等于1,这是为了保证滤波前后图像的亮度保持不变。当然了,这不是硬性要求了。

      3)如果滤波器矩阵所有元素之和大于1,那么滤波后的图像就会比原图像更亮,反之,如果小于1,那么得到的图像就会变暗。如果和为0,图像不会变黑,但也会非常暗。

      4)对于滤波后的结构,可能会出现负数或者大于255的数值。对这种情况,我们将他们直接截断到0和255之间即可。对于负数,也可以取绝对值。

神奇的卷积核

      上面说到,对图像的滤波处理就是对图像应用一个小小的卷积核,那这个小小的卷积核到底有哪些魔法。下面我们一起来领略下一些简单但不简单的卷积核的魔法。

 

1、啥也不做

 

      哈哈,大家可以看到啥了吗?这个滤波器啥也没有做,得到的图像和原图是一样的。因为只有中心点的值是1。邻域点的权值都是0,对滤波后的取值没有任何影响。

 

 

      下面我们动点真格的。

 

2、图像锐化滤波器Sharpness Filter

 

      图像的锐化和边缘检测很像,首先找到边缘,然后把边缘加到原来的图像上面,这样就强化了图像的边缘,使图像看起来更加锐利了。这两者操作统一起来就是锐化滤波器了,也就是在边缘检测滤波器的基础上,再在中心的位置加1,这样滤波后的图像就会和原始的图像具有同样的亮度了,但是会更加锐利。

 

 

      我们把核加大,就可以得到更加精细的锐化效果

 

 

      另外,下面的滤波器会更强调边缘:

 

 

      主要是强调图像的细节。最简单的3x3的锐化滤波器如下:

 

                                      

 

      大家应该也看出来了,锐化滤波器实际上就是计算当前点和周围点的差别,然后将这个差别加到原来的位置上。

 

3、边缘检测Edge Detection

 

      我们要找水平的边缘:需要注意的是,这里矩阵的元素和是0,所以滤波后的图像会很暗,只有边缘的地方是有亮度的。

 

 

      为什么这个滤波器可以寻找到水平边缘呢?因为用这个滤波器卷积相当于求导的离散版本:你将当前的像素值减去前一个像素值,这样你就可以得到这个函数在这两个位置的差别或者斜率。下面的滤波器可以找到垂直方向的边缘,这里像素上和下的像素值都使用:

 

 

      再下面这个滤波器可以找到45度的边缘:取-2不为了什么,只是为了让矩阵的元素和为0而已。

 

 

      那下面这个滤波器就可以检测所有方向的边缘:

 

                                      

 

      为了检测边缘,我们需要在图像对应的方向计算梯度。用下面的卷积核来卷积图像,就可以了。但在实际中,这种简单的方法会把噪声也放大了。另外,需要注意的是,矩阵所有的值加起来要是0.

 

                                       

 

4、浮雕Embossing Filter

 

      浮雕滤波器可以给图像一种3D阴影的效果。只要将中心一边的像素减去另一边的像素就可以了。这时候,像素值有可能是负数,我们将负数当成阴影,将正数当成光,然后我们对结果图像加上128的偏移。这时候,图像大部分就变成灰色了。

 

      下面是45度的浮雕滤波器

 

 

      我们只要加大滤波器,就可以得到更加夸张的效果了

 

 

      这种效果非常的漂亮,就像是将一副图像雕刻在一块石头上面一样,然后从一个方向照亮它。它和前面的滤波器不同,它是非对称的。另外,它会产生负数值,所以我们需要将结果偏移,以得到图像灰度的范围。

 

 

 

                                                      A:原图像。B:锐化。C:边缘检测。D:浮雕

 

5、运动模糊Motion Blur

      运动模糊可以通过只在一个方向模糊达到,例如下面9x9的运动模糊滤波器。注意,求和结果要除以9。

 

      这个效果就好像,摄像机是从左上角移动的右下角。

 

  看了一些好玩的滤波器后我们可以进入主题了,首先来看均值模糊:

均值模糊Box Filter (Averaging)

 

      我们可以将当前像素和它的四邻域的像素一起取平均,然后再除以5,或者直接在滤波器的5个地方取0.2的值即可,如下图:

 

 

      可以看到,这个模糊还是比较温柔的,我们可以把滤波器变大,这样就会变得粗暴了:注意要将和再除以13.

 

 

      所以,如果你想要更模糊的效果,加大滤波器的大小即可。或者对图像应用多次模糊也可以。

 

 

 

 

 

 

 

高斯模糊

      其实模糊滤波器就是对周围像素进行加权平均处理,均值模糊很简单,周围像素的权值都相同,所以不是很平滑。高斯模糊就有这个优点,所以被广泛用在图像降噪上。特别是在边缘检测之前,都会用来移除细节。那么下面我们就看看高斯模糊的权值是如何分配的。

 

正态分布的权重
  正态分布显然是一种可取的权重分配模式。在图形上,正态分布是一种钟形曲线,越接近中心,取值越大,越远离中心,取值越小。计算平均值的时候,我们只需要将"中心点"作为原点,其他点按照其在正态曲线上的位置,分配权重,就可以得到一个加权平均值。
高斯函数
  上面的正态分布是一维的,图像都是二维的,所以我们需要二维的正态分布
正态分布的密度函数叫做"高斯函数"(Gaussian function)。它的一维形式是:
一维形式
  其中,μ是x的均值,σ是x的标准差。因为计算平均值的时候,中心点就是原点,所以μ等于0。即:
进一步推导
  根据一维高斯函数,可以推导得到二维高斯函数:
二维高斯函数
  有了这个函数 ,就可以计算每个点的权重了。
  假定中心点的坐标是(0,0),那么距离它最近的8个点的坐标如下:
权重矩阵
  更远的点以此类推。下面就是5*5的高斯滤波器和平滑效果: