2019-08-26 09:24:18 weixin_38342946 阅读数 533
  • Java经典算法讲解

    在面试中,算法题目是必须的,通过算法能够看出一个程序员的编程思维,考察对复杂问题的设计与分析能力,对问题的严谨性都能够体现出来。一个算法的好坏,直接影响一个方法调用的性能,进而影响软件的整体性能。算法是学习所有编程语言的基础,在Java的学习过程中首先也会选择以算法起步,本次课程重点讲解Java开发中常用的基本算法。

    29947 人正在学习 去看看 张中强

1.《On the Effectiveness of Visible Watermarks》非常强大的去水印方法,https://watermark-cvpr17.github.io/,
2.不是作者开发的源码,但是已经实现其功能。https://github.com/rohitrango/automatic-watermark-detection,主是是调用到opencv里面的库,部分用到了tensorflow里面的函数,算法倒不是很复杂,都是些常用的一些算法。

2018-08-02 09:32:39 wsp_1138886114 阅读数 1763
  • Java经典算法讲解

    在面试中,算法题目是必须的,通过算法能够看出一个程序员的编程思维,考察对复杂问题的设计与分析能力,对问题的严谨性都能够体现出来。一个算法的好坏,直接影响一个方法调用的性能,进而影响软件的整体性能。算法是学习所有编程语言的基础,在Java的学习过程中首先也会选择以算法起步,本次课程重点讲解Java开发中常用的基本算法。

    29947 人正在学习 去看看 张中强

一、基本概念

1.1 图像分类

这里写图片描述

1.2 图像处理方法
模拟图像处理: 
    也称光学图像处理,它是利用光学透镜或光学照相方法对模拟图像进行的处理,其实时性强、速度快、 
    处理信息量大、分辨率高,但是处理精度低,灵活度差,难有判断功能 。 

数字图像处理: 
    即利用计算机对数字图像进行处理 ,它具有精度高、处理内容丰富、方法易变、灵活度高等优点。 
    但是它的处理速度受到计算机和数字器件的限制,一般也是串行处理,因此处理速度较慢。 

光电结合处理: 
    用光学方法完成运算量巨大的处理(如频谱变换等),而用计算机对光学处理结果(如频谱)进行分析判断等处理。 
    该方法是前两种方法的有机结合,它集结了二者的优点。光电结合处理是。 

这里写图片描述

1.3 颜色表示方法

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.4 图像的几何变换

这里写图片描述
这里写图片描述

仿射变换

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

2012-09-20 11:43:30 rabbit729 阅读数 5514
  • Java经典算法讲解

    在面试中,算法题目是必须的,通过算法能够看出一个程序员的编程思维,考察对复杂问题的设计与分析能力,对问题的严谨性都能够体现出来。一个算法的好坏,直接影响一个方法调用的性能,进而影响软件的整体性能。算法是学习所有编程语言的基础,在Java的学习过程中首先也会选择以算法起步,本次课程重点讲解Java开发中常用的基本算法。

    29947 人正在学习 去看看 张中强

  本系列文章将使用GPU实现图像处理中常用的算法,此处只给出代码,关于算法原理描述有很多资料,大家可以自行查找。不足之处请大家不吝赐教,共同提高。

/********************************
*  Author: rabbit729
*  E-mail: wlq_729@163.com
*  Date:   2012-09-20
*  Description: 图像的二值化
********************************/
#include <d3dx9.h>

//-----------------------------------------------------------------------------
// Desc: 全局变量
//-----------------------------------------------------------------------------
LPDIRECT3D9             g_pD3D                 = NULL;  //Direct3D对象
LPDIRECT3DDEVICE9       g_pd3dDevice           = NULL;  //Direct3D设备对象

LPDIRECT3DTEXTURE9      g_pTextureScreen        = NULL; //待处理图片

ID3DXEffect*            g_pEffect               = NULL;  //效果指针
//常量句柄
D3DXHANDLE              hTechScreen             = NULL;  //Effect句柄
D3DXHANDLE              hTexScreen              = NULL;  //纹理句柄
D3DXHANDLE              hViewPortWidthInv       = NULL;  //视口宽倒数句柄
D3DXHANDLE              hViewPortHeightInv      = NULL;  //视口高倒数句柄

LPDIRECT3DVERTEXBUFFER9 g_pScreenSpaceQuad      = NULL;  //背板VB

const int WIDTH  = 465;
const int HEIGHT = 669;

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_TEX1)

struct Vertex
{
	Vertex(){}
	Vertex(float x, float y, float z, float w)
	{
		_x = x;   _y = y;   _z = z; _w = w;
	}

	float _x, _y, _z, _w;

	static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZW;


//-----------------------------------------------------------------------------
// Desc: 设置世界矩阵
//-----------------------------------------------------------------------------
VOID SetWorldMatrix()
{
	//创建并设置世界矩阵
	D3DXMATRIXA16 matWorld, matRotateX, matRotateY;
	D3DXMATRIXA16 matScale;
	D3DXMatrixIdentity(&matScale);
	matScale._11 = matScale._22 = matScale._33 = 0.5f;

	D3DXMatrixIdentity(&matWorld);
	D3DXMatrixIdentity(&matRotateX);
	D3DXMatrixIdentity(&matRotateY);
	D3DXMatrixRotationX( &matRotateX, D3DX_PI / 3.0 );
	D3DXMatrixRotationY( &matRotateY, -D3DX_PI / 8.0 );
	D3DXMatrixMultiply(&matWorld, &matRotateX, &matRotateY);

	D3DXMatrixMultiply(&matWorld, &matScale, &matWorld);
	g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
}


//-----------------------------------------------------------------------------
// Desc: 设置观察矩阵和投影矩阵
//-----------------------------------------------------------------------------
VOID SetViewAndProjMatrix()
{
	//创建并设置观察矩阵
	D3DXVECTOR3 vEyePt( 0.0f, 0.0f,-250.0f );
	D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
	D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
	D3DXMATRIXA16 matView;
	D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
	g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

	//创建并设置投影矩阵
	D3DXMATRIXA16 matProj;
	D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
	g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}


//-----------------------------------------------------------------------------
// Desc: 初始化Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
	//创建Direct3D对象, 该对象用于创建Direct3D设备对象
	if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
		return E_FAIL;

	//设置D3DPRESENT_PARAMETERS结构, 准备创建Direct3D设备对象
	D3DPRESENT_PARAMETERS d3dpp; 
	ZeroMemory( &d3dpp, sizeof(d3dpp) );
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;

	//创建Direct3D设备对象
	if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&d3dpp, &g_pd3dDevice ) ) )
	{
		return E_FAIL;
	}

	//创建Effect
	ID3DXBuffer* errBuffer = NULL;
	if (FAILED(D3DXCreateEffectFromFile(g_pd3dDevice, L"erzhihua.fx", NULL, NULL, D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION, NULL, &g_pEffect, &errBuffer)))
	{
		if (errBuffer)
		{
			MessageBox(0, (LPCTSTR)errBuffer->GetBufferPointer(), 0, 0);
			errBuffer->Release();
		}
		return E_FAIL;
	}

	//获取常量句柄
	hTechScreen         = g_pEffect->GetTechniqueByName("Screen");
	hTexScreen          = g_pEffect->GetParameterByName(0, "TexScreen");
	hViewPortWidthInv   = g_pEffect->GetParameterByName(0, "viewport_inv_width");
	hViewPortHeightInv  = g_pEffect->GetParameterByName(0, "viewport_inv_height");

	//设置环境光
	g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff );

	//设置观察矩阵和投影矩阵
	SetViewAndProjMatrix();

	return S_OK;
}

//-----------------------------------------------------------------------------
// Desc: 创建场景图形
//-----------------------------------------------------------------------------
HRESULT InitGeometry()
{
	// 创建屏幕板
	g_pd3dDevice->CreateVertexBuffer(
		6 * sizeof(Vertex),
		D3DUSAGE_WRITEONLY,
		Vertex::FVF, 
		D3DPOOL_MANAGED,
		&g_pScreenSpaceQuad,
		0);

	Vertex* vertices;
	g_pScreenSpaceQuad->Lock(0, 0, (void**)&vertices, 0);

	vertices[0] = Vertex(-1.0f, 1.0f, 0.5f, 1.0f);
	vertices[1] = Vertex(1.0f,  1.0f, 0.5f, 1.0f);
	vertices[2] = Vertex( 1.0f, -1.0f, 0.5f, 1.0f);
	vertices[3] = Vertex(-1.0f, 1.0f, 0.5f, 1.0f);
	vertices[4] = Vertex( 1.0f, -1.0f, 0.5f, 1.0f);
	vertices[5] = Vertex( -1.0f, -1.0f, 0.5f, 1.0f);

	g_pScreenSpaceQuad->Unlock();

	//加载纹理
	HRESULT hr = D3DXCreateTextureFromFile(g_pd3dDevice, L"meinv.jpg", &g_pTextureScreen);
	if (FAILED(hr))
	{
		return E_FAIL;
	} 

	return S_OK;
}


//-----------------------------------------------------------------------------
// Desc: 释放创建的对象
//-----------------------------------------------------------------------------
VOID Cleanup()
{
	if (g_pScreenSpaceQuad != NULL)
	{
		g_pScreenSpaceQuad->Release();
	}

	if (g_pTextureScreen != NULL)
	{
		g_pTextureScreen->Release();
	}

	if (g_pEffect != NULL)
	{
		g_pEffect->Release();
	}

	//释放Direct3D设备对象
	if( g_pd3dDevice != NULL )
		g_pd3dDevice->Release();

	//释放Direct3D对象
	if( g_pD3D != NULL )
		g_pD3D->Release();
}

VOID RenderScreen()
{
	//将RenderTarget作为纹理
	g_pEffect->SetTexture(hTexScreen, g_pTextureScreen);

	float fWidthInv = 1.0f / WIDTH;
	float fHeightInv = 1.0f / HEIGHT;
	g_pEffect->SetFloat(hViewPortWidthInv, fWidthInv);
	g_pEffect->SetFloat(hViewPortHeightInv, fHeightInv);

	g_pd3dDevice->SetStreamSource(0, g_pScreenSpaceQuad, 0, sizeof(Vertex));
	g_pd3dDevice->SetFVF(Vertex::FVF);

	// 设置要使用的Technique
	g_pEffect->SetTechnique(hTechScreen);

	UINT numPasses = 0;
	g_pEffect->Begin(&numPasses, 0);

	for (int i = 0; i < numPasses; i++)
	{
		g_pEffect->BeginPass(i);

		g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);

		g_pEffect->EndPass();
	}
	g_pEffect->End();
}

//-----------------------------------------------------------------------------
// Desc: 渲染场景
//-----------------------------------------------------------------------------
VOID Render()
{    
	// 获取backbuffer
	LPDIRECT3DSURFACE9 pBackbuffer;
	g_pd3dDevice->GetRenderTarget(0, &pBackbuffer);

	//开始渲染场景
	if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
	{
		//设回backbuffer
		g_pd3dDevice->SetRenderTarget(0, pBackbuffer);
		RenderScreen();

		//场景渲染结束
		g_pd3dDevice->EndScene();
	}

	//在屏幕上显示场景
	g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}


//-----------------------------------------------------------------------------
// Desc: 窗口过程, 处理消息
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
	switch( msg )
	{
	case WM_DESTROY:
		Cleanup();
		PostQuitMessage( 0 );
		return 0;
	}

	return DefWindowProc( hWnd, msg, wParam, lParam );
}


//-----------------------------------------------------------------------------
// Desc: 入口函数
//-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
	//注册窗口类
	WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, 
		GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
		L"ClassName", NULL };
	RegisterClassEx( &wc );

	//创建窗口
	HWND hWnd = CreateWindow( L"ClassName", L"图像二值化", 
		WS_OVERLAPPEDWINDOW, 200, 100, WIDTH, HEIGHT,
		GetDesktopWindow(), NULL, wc.hInstance, NULL );

	//初始化Direct3D
	if( SUCCEEDED( InitD3D( hWnd ) ) )
	{ 
		//创建场景图形
		if( SUCCEEDED( InitGeometry() ) )
		{
			//显示窗口
			ShowWindow( hWnd, SW_SHOWDEFAULT );
			UpdateWindow( hWnd );

			//进入消息循环
			MSG msg; 
			ZeroMemory( &msg, sizeof(msg) );
			while( msg.message!=WM_QUIT )
			{
				if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
				{
					TranslateMessage( &msg );
					DispatchMessage( &msg );
				}
				else
				{
					Render();  //渲染场景
				}
			}
		}
	}

	UnregisterClass( L"ClassName", wc.hInstance );
	return 0;
}


Effect代码如下:

/********************************
*  Author: rabbit729
*  E-mail: wlq_729@163.com
*  Date:   2011-09-20
********************************/

//------------------------------
//  顶点着色器
//------------------------------

float viewport_inv_width;
float viewport_inv_height;
struct VS_OUTPUTSCREEN {
   float4 Pos: POSITION;
   float2 texCoord: TEXCOORD0;
};

VS_OUTPUTSCREEN vs_mainPassScreen(float4 Pos: POSITION){
   VS_OUTPUTSCREEN Out;

   Out.Pos = float4(Pos.xy, 0, 1);

   Out.texCoord.x = 0.5 * (1 + Pos.x - viewport_inv_width);
   Out.texCoord.y = 0.5 * (1 - Pos.y - viewport_inv_height);

   return Out;
}

//------------------------------
//  像素着色器
//------------------------------
Texture2D TexScreen;

sampler2D TexMapScreen {
    Texture = <TexScreen>;
};

float4 ps_mainPassScreen(float2 texCoord: TEXCOORD0) : COLOR 
{
   float4 col = tex2D(TexMapScreen,  texCoord);
   float Intensity;

   // 灰度化
   // I = 0.299*R + 0.587*G + 0.184*B
   Intensity = 0.299*col.r + 0.587*col.g + 0.184*col.r;
   
   // 阈值为0.5,关于怎么选取阈值有好多方法,大家可以自行查阅
   if(Intensity > 0.5)
      Intensity = 0.5f;
   else
      Intensity = 0.1f;

   return float4(Intensity.xxx,col.a);
}

technique Screen
{
   pass P0
   {
      VertexShader = compile vs_3_0 vs_mainPassScreen();
      PixelShader  = compile ps_3_0 ps_mainPassScreen();
   }
}


 结果:

原始图片:

二值化后结果:

2013-09-26 23:21:17 F_SUNNY 阅读数 2165
  • Java经典算法讲解

    在面试中,算法题目是必须的,通过算法能够看出一个程序员的编程思维,考察对复杂问题的设计与分析能力,对问题的严谨性都能够体现出来。一个算法的好坏,直接影响一个方法调用的性能,进而影响软件的整体性能。算法是学习所有编程语言的基础,在Java的学习过程中首先也会选择以算法起步,本次课程重点讲解Java开发中常用的基本算法。

    29947 人正在学习 去看看 张中强

     从事图像处理这个行当也已经有一段时间了,对于一个自动化毕业的本科生,确实是磕磕绊绊的走到现在了,前期的基础图像处理还基本上能够轻松上手,越到后面的机器学习算法,用到的数学知识也就越深了,所以越到后面会越困难的。现在回想下之前的图像处理基础算法,其实是可以归纳到数学各个领域的。下面简单介绍下一些基础图像处理算法,当然主要是讲自己对其的归类理解,有不对的之处,大伙一起探讨。如果想要这些算法的具体实现,给推荐几个博客(百度的),我也是从这些类似的博客起步的:

http://www.cnblogs.com/drizzlecrj/archive/2008/02/25/1077494.html

http://blog.csdn.net/xizero00/article/details/6631209

     主要的基础图像处理算法有:灰度化,二值化,投影法,差影法,图像采样,增强,分割,边缘提取,匹配等。

    下面讲讲这些算法最基础实现时按照数学知识归类:

     1. 初等代数类:

  ①.灰度化:一般灰度化是用加权平均的,这个在我们小学都可以解决了,f(i,j)=0.30R(i,j)+0.59G(i,j)+0.11B(i,j));

②二值化:其实二值化就是一个分段的0-1函数;

③差影法:这类的帧差发,前景提取法,都是一个减法,当然如果有背景建模之类的,那就背景建模的算法就属于高等代数或者概率统计的知识了;

④图像锐化:一般的图像锐化算法也是相邻像素点之间的初等代数运算,运算如下:

设f(i,j)像素为(r1, g1, b1) , f(i-1,j-1)像素为(r2,g2,b2), g(i,j)像素为(r,g,b),则
r = r1 + 0.25 * |r1 - r2|
g = g1 + 0.25 * |g1 - g2|
b = b1 + 0.25 * |b1 - b2|

⑤图像的叠加,浮雕效果等也都是属于初等代数的;

    2.概率统计类:

①.投影法:像直方图统计之类的,是属于统计类的;

②.匹配算法:当然匹配算法也可以用线性代数,高等代数做,但是像方差匹配之类是属于概统的;

③图像采样:一听采样就知道是概统的,其中有图像区域采样,随机采样,分布采样,上/下采样;但是一般的采样算法都要结合代数知识进行应用,比如对图像感兴趣区域进行提取,可能还要用到插值算法进行归一化之类的;

     3.高等代数:

①边缘提取:这主要用到的是一阶二阶微分,卷积等知识,这些都是高等代数中的基础;

②图像滤波:卷积滤波,高通滤波;

这有一片关于图像卷积实现方法的文章,讲的很好:

http://blog.sina.com.cn/s/blog_4bdb170b01019atv.html

     4.几何学:

这部分主要是在于图像中物体的形态特征的描述,像圆,直线,曲线,方形等几何图形的特征描述算子,了解这些可以进行物体的特征提取判别;

还有就是角度,使用正余弦定理结合线性代数,可以进行图像线性匹配;

     5. 线性代数:

其实个人认为线性代数也是属于高等代数,线代的矩阵问题也是可以转换为高等代数的方程计算的,当然高等数学的方程,转换为矩阵的话,计算起来会更加形象化,还会有很多简化算法;

①PCA降维:这个是基础的人脸识别算法,很好的引用了矩阵的特征值,特征向量等知识,是经典算法;

②匹配:结合几何等特征,可以对图像进行线性匹配;

③非线性的线性化,通过类hogh等变换,可以将高维非线性数据,线性化进行处理,这样可以提高效率,简化算法。


在图像基础处理算法中很多其实是各种数学知识的综合,要灵活应用各种数学知识才能更加高效率的对图像数据进行处理。这也足见数学知识对于图像处理的重要性,但是一些很简单的图像处理算法,其实用很简单的数学知识就能解决,所以学起来也要有信心,从简单到困难,一步一步脚踏实地的来。

以上属于个人的一点看法,如果不对,请各位武林高手指正补充。


2018-06-21 20:28:04 zx520113 阅读数 462
  • Java经典算法讲解

    在面试中,算法题目是必须的,通过算法能够看出一个程序员的编程思维,考察对复杂问题的设计与分析能力,对问题的严谨性都能够体现出来。一个算法的好坏,直接影响一个方法调用的性能,进而影响软件的整体性能。算法是学习所有编程语言的基础,在Java的学习过程中首先也会选择以算法起步,本次课程重点讲解Java开发中常用的基本算法。

    29947 人正在学习 去看看 张中强

        5、图像滤波(平滑)

        图像滤波(平滑),即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接影响到后续图像处理和分析的有效性和可靠性。

        常用的图像滤波算法高斯滤波、均值滤波、中值滤波、双边滤波等。

        卷积的定义:假设被卷积的图像为I,卷积核为K。

        

        I与K的二维离散卷积计算步骤如下:

        首先将K翻转成,然后用K沿着I的每一个位置相乘求和,得到full卷积,,从filter和image刚相交开始做卷积。


        valid卷积:

        当filter全部在image里面的时候,进行卷积运算。

        same卷: 

        当filter的中心(K)与image的边角重合时,开始做卷积运算。

        在OpenCV中通过调用signal.convolve2d()实现卷积。

 

        高斯滤波:高斯滤波(高斯平滑)是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。

        高斯卷积算子的构建:

        首先计算高斯矩阵:

        

        再计算高斯矩阵的和:

        最后用高斯矩阵除以本身的和,即归一化,得到高斯卷积算子:

         

        在OpenCV中,通过调用cv2.getGaussianKernel(ksize,sigma,ktype)实现一维水平方向上的高斯平滑,再进行一维垂直方向上的高斯平滑。

 

        均值平滑:均值滤波,是最简单的一种线性滤波操作,输出图像的每一个像素是核窗口内输入图像对应图像像素的平均值。其算法比较简单,计算速度快,但是均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在去除噪声的同时,也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。但均值滤波对周期性的干扰噪声有很好的抑制作用。

        均值平滑:

        利用矩阵积分,计算出矩阵中任意矩形区域内的和,快速均值平滑:

        

        在OpenCV中,通过调用cv2.blur()实现均值滤波。

 

        中值滤波:中值滤波法是一种非线性平滑技术,将图像的每个像素用邻域 (以当前像素为中心的正方形区域)像素的中值代替 ,常用于消除图像中的椒盐噪声。中值滤波对脉冲噪声有良好的滤除作用,特别是在滤除噪声的同时,能够保护信号的边缘,使之不被模糊,但它会洗去均匀介质区域中的纹理。

        再OpenCV中,通过调用cv2.medianBlur()实现中值滤波。

 

        双边滤波:双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的,具有简单、非迭代、局部的特点,能够对低频信息进行较好的额滤波。双边滤波器的好处是可以做边缘保存,这个特点对于一些图像模糊来说很有用。

        双边滤波根据每个位置的领域,对应该位置构建不同的权重模板,首先,构建winH*winW的空间距离权重模板,与构建高斯卷积核的过程类似,winH*winW均为奇数,0<=h<winH,0<=w<winW。

        

        然后,构建winH*winW的相似权重模板,是通过(r,c)处的值与其领域值得差值的指数衡量。

        

        最后将closenessWeight和similarityWeight的对应位置相乘,然后进行归一化,便可得到改位置的权重模板,将所得到的权重模板和该位置领域的对应位置相乘求和,最后就得到该位置的输出值。

        在OpenCV中,通过调用cv2.bilateralFilter()实现双边滤波。

        联合双边滤波与双边滤波不同之处在于,双边滤波是根据原图对每一个位置,通过该位置和其领域的灰度值的差的指数来估计相似性;而联合双边滤波是首先对原图进行高斯平滑,根据平滑的结果,用当前的位置及其领域的值得差来估计相似性权重模板。

没有更多推荐了,返回首页