您的位置:首页 > 其它

图像处理常用算法GPU实现二:基于微分的边缘检测

2017-08-14 16:40 786 查看
[cpp] view
plain copy

/********************************

* Author: rabbit729

* E-mail: wlq_729@163.com

* Date: 2012-09-23

* 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"edgedetect.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代码:

[cpp] view
plain copy

/********************************

* Author: rabbit729

* E-mail: wlq_729@163.com

* Date: 2011-09-03

********************************/

//------------------------------

// 顶点着色器

//------------------------------

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>;

};

//Laplacian算子盒1

const float4 samples1[5] = {

0.0, 1.0, 0.0, -1.0,

-1.0, 0.0, 0.0, -1.0,

0.0, 0.0, 0.0, 4.0,

1.0, 0.0, 0.0, -1.0,

0.0, 1.0, 0.0, -1.0

};

//Laplacian算子盒2

const float4 samples2[9] = {

-1.0, -1.0, 0.0, -1.0,

0.0, -1.0, 0.0, -1.0,

1.0, 1.0, 0.0, -1.0,

-1.0, 0.0, 0.0, -1.0,

0.0, 0.0, 0.0, 8.0,

1.0, 0.0, 0.0, -1.0,

-1.0, 1.0, 0.0, -1.0,

0.0, 1.0, 0.0, -1.0,

1.0, 1.0, 0.0, -1.0

};

//Laplacian算子盒3

const float4 samples3[9] = {

-1.0, -1.0, 0.0, 1.0,

0.0, -1.0, 0.0, -2.0,

1.0, 1.0, 0.0, 1.0,

-1.0, 0.0, 0.0, -2.0,

0.0, 0.0, 0.0, 4.0,

1.0, 0.0, 0.0, -2.0,

-1.0, 1.0, 0.0, 1.0,

0.0, 1.0, 0.0, -2.0,

1.0, 1.0, 0.0, 1.0

};

float4 ps_mainPassScreen(float2 texCoord: TEXCOORD0) : COLOR

{

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

float4 col = float4(0, 0, 0, 0);

for(int i = 0; i < 5; i++)

{

col += samples1[i].w * tex2D(TexMapScreen, texCoord + float2(samples1[i].x*viewport_inv_width,

samples1[i].y*viewport_inv_height));

}

//为了突出显示,此处将结果乘2

return 2.0 * col;

}

//------------------------------

// 效果框架

//------------------------------

technique Screen

{

pass P0

{

VertexShader = compile vs_3_0 vs_mainPassScreen();

PixelShader = compile ps_3_0 ps_mainPassScreen();

}

}

结果:

原图:



处理结果1,采用Laplacin算子1



处理结果2,采用Laplacin算子2



处理结果3,采用Laplacin算子3



说明:

1.可以采用将图像先进行灰度化后再进行边缘检测;

2.关于边缘检测还有其他的算子盒,大家可以根据需要选取不同的算子盒,通过上面的实验可以看出,不同的算子盒适合不同的场景,结果也不同。
http://blog.csdn.net/rabbit729/article/details/8009218
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: