图形开发|图像处理常用算法GPU实现三(基于模板匹配的边缘检测)

上一篇文章给出了基于微分方法的边缘检测,该篇给出一个基于Prewitt算子的模板匹配检测算法。除了水平和垂直方向外,此处还给出了其他方向的检测,一共8个方向,算子如下:

代码如下:

/******************************** *Author: rabbit729 *E-mail: wlq_729@163.com *Date:2012-09-24 *Description: 图像的边缘检测 ********************************/ //#define DEBUG_PS// Uncomment this line to debug pixel shaders #include //----------------------------------------------------------------------------- // Desc: 全局变量 //----------------------------------------------------------------------------- LPDIRECT3D9g_pD3D= NULL; //Direct3D对象 LPDIRECT3DDEVICE9g_pd3dDevice= NULL; //Direct3D设备对象LPDIRECT3DTEXTURE9g_pTextureScreen= NULL; //待处理图片ID3DXEffect*g_pEffect= NULL; //效果指针 //常量句柄 D3DXHANDLEhTechScreen= NULL; //Effect句柄 D3DXHANDLEhTexScreen= NULL; //纹理句柄 D3DXHANDLEhViewPortWidthInv= NULL; //视口宽倒数句柄 D3DXHANDLEhViewPortHeightInv= NULL; //视口高倒数句柄LPDIRECT3DVERTEXBUFFER9 g_pScreenSpaceQuad= NULL; //背板VBconst 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; D3DDEVTYPE DeviceType = D3DDEVTYPE_HAL; #ifdef DEBUG_PS DeviceType = D3DDEVTYPE_REF; #endif //创建Direct3D设备对象 if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, DeviceType, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) ) { return E_FAIL; } DWORD dwShaderFlags = D3DXFX_NOT_CLONEABLE; //创建Effect ID3DXBuffer* errBuffer = NULL; if (FAILED(D3DXCreateEffectFromFile(g_pd3dDevice, L"edgedetect.fx", NULL, NULL, D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION, NULL, &g_pEffect, &errBuffer))) { if (errBuffer) { char* strErr = (char*)errBuffer->GetBufferPointer(); 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-24 ********************************///------------------------------ //顶点着色器 //------------------------------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 = ; }; //Prewitt算子,8个边缘方向的8种掩膜 const float4 samples[8][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, -2.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},{-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, 2.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},{-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, -2.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},{ -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, -2.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},{-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, 2.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},{-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, -2.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},{-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, -2.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},{-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, -2.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} }; float4 ps_mainPassScreen(float2 texCoord: TEXCOORD0) : COLOR { float4 col = float4(0, 0, 0, 0); float Intensity = 0.0; float maxDetect = 0.0; for(int k = 0; k < 8; k++) { float m = 0.0; for(int i = 0; i < 9; i++) { col = tex2D(TexMapScreen, texCoord + float2(samples[k][i].x*viewport_inv_width, samples[k][i].y*viewport_inv_height)); Intensity = 0.299*col.r + 0.587*col.g + 0.184*col.b; m += samples[k][i].w * Intensity; }maxDetect = max(m, maxDetect); } col = maxDetect; if(maxDetect > 1.0) col = 1.0; return col; }//------------------------------ //效果框架 //------------------------------technique Screen { pass P0 { VertexShader = compile vs_3_0 vs_mainPassScreen(); PixelShader= compile ps_3_0 ps_mainPassScreen(); } }


结果:
原图:

结果:
【图形开发|图像处理常用算法GPU实现三(基于模板匹配的边缘检测)】

    推荐阅读