Search

2012年11月16日 星期五

Visual CAPTCHA Detection

    幾個禮拜前上課寫個去除背景的demo給人看後沒有在碰了,所以就放上來等哪天想改就有,對於圖形驗證碼感覺上如果背景夠複雜,去除背景的演算法複雜度就很高,至於雜訊一些去除線條的演算法或者濾波可以容易去除常見的雜訊,文字本身扭曲的話可以讓Tesseract之類的OCR Library辨識率降低(即使背景、雜訊完整去除),而一些方法的閾值也是要看情況調整,總結來說個人感覺是背景複雜求平均值不容易,而且可能得將背景分區快去除,但針對設計應該是還是可以去除大部分只是複雜度的問題,但如果文字扭曲變形到一定程度似乎常見OCR Library辨識也不易,所以感覺上文字扭曲是必須的,當然最好還是不要用同系列工具生產的驗證圖片,最好混和多種系列使用,不過沒有試過用ML訓練萬筆樣本測試是否能有效提昇辨識度就是了,這裡和這裡有對驗證碼類型的分析。

extractor.h


#ifndef __EXTRACTOR__
#define __EXTRACTOR__

#include<cv.h>
#include<cxcore.h>
#include<highgui.h>

#include <iostream>
#include <map>

class Extractor
{
   public:
      Extractor(char*);
      long Average(); //It depends
      void BackgroundErase(); //It depends
      void ColorFull();
      void NoiseClear(); //It depends
      void Cut();
   private:
      long avg;
      IplImage *image;
};

#endif


extractor.cpp


#include "extractor.h"

Extractor::Extractor(char *name)
{
   image = cvLoadImage(name,1);
}

long Extractor::Average()
{
   cvSmooth(image,image,CV_BLUR);

   avg = 0;

   for(int y = 0;y < 3;++y){
      for(int x = 0;x < 3;++x){
long temp = 0;
temp += image->imageData[y * image->widthStep + (x * 3)] + image->imageData[y * image->widthStep + (x * 3) + 1] + image->imageData[y * image->widthStep + (x * 3) + 2];
avg += temp / 3;
      }
   }


   for(int y = image->height - 1;y > image->height - 4;--y){
      for(int x = 0;x < 3;++x){
long temp = 0;
temp += image->imageData[y * image->widthStep + (x * 3)] + image->imageData[y * image->widthStep + (x * 3) + 1] + image->imageData[y * image->widthStep + (x * 3) + 2];
avg += temp / 3;
      }
   }

   for(int y = 0;y < 3;++y){
      for(int x = image->width - 1;x > image->width - 4;--x){
long temp = 0;
temp += image->imageData[y * image->widthStep + (x * 3)] + image->imageData[y * image->widthStep + (x * 3) + 1] + image->imageData[y * image->widthStep + (x * 3) + 2];
avg += temp / 3;
      }
   }

   for(int y = image->height - 1;y > image->height - 4;--y){
      for(int x = image->width - 1;x > image->width - 4;--x){
long temp = 0;
temp += image->imageData[y * image->widthStep + (x * 3)] + image->imageData[y * image->widthStep + (x * 3) + 1] + image->imageData[y * image->widthStep + (x * 3) + 2];
avg += temp / 3;
      }
   }

   avg /= 36;


   return avg ;
}

void Extractor::BackgroundErase()
{
   long range = 20;

   for(int y = 0;y < image->height;++y){
      for(int x = 0;x < image->widthStep;++x){
long temp = (image->imageData[y * image->widthStep + x] +
      image->imageData[y * image->widthStep + x + 1] +
      image->imageData[y * image->widthStep + x + 2]) / 3;
if(temp  < (avg + range) && temp > (avg - range)){
   image->imageData[y * image->widthStep + x] = image->imageData[y * image->widthStep + x + 1] = image->imageData[y * image->widthStep + x + 2] = 255;
}
      }
   }
}

void Extractor::ColorFull()
{
   for(int y = 0;y < image->height;++y){
      for(int x = 0;x < image->widthStep - 3;x += 3){
long temp = (image->imageData[y * image->widthStep + x] +
      image->imageData[y * image->widthStep + x + 1] +
      image->imageData[y * image->widthStep + x + 2]) / 3;
if(temp > 0){
   image->imageData[y * image->widthStep + x] = image->imageData[y * image->widthStep + x + 1] = image->imageData[y * image->widthStep + x + 2] = 0;
}
      }
   }
}

void Extractor::NoiseClear()
{
   int range = 20;
   IplImage *itemp = cvCreateImage(cvGetSize(image),IPL_DEPTH_8U,3);
   cvCopy(image,itemp);

   for(int y = 0;y < itemp->height;++y){
      for(int x = 0;x < itemp->widthStep - 3;x += 3){
long temp = (itemp->imageData[y * itemp->widthStep + x] +
      itemp->imageData[y * itemp->widthStep + x + 1] +
      itemp->imageData[y * itemp->widthStep + x + 2]) / 3;

long ref =  (itemp->imageData[(y - 1) * itemp->widthStep + x] +
      itemp->imageData[(y - 1) * itemp->widthStep + x + 1] +
      itemp->imageData[(y - 1) * itemp->widthStep + x + 2] / 3)
   +
   (itemp->imageData[(y + 1) * itemp->widthStep + x]  +
    itemp->imageData[(y + 1) * itemp->widthStep + x + 1] +
    itemp->imageData[(y + 1) * itemp->widthStep + x + 1] / 3)
   +
   (itemp->imageData[y * itemp->widthStep + (x + 3)] +
    itemp->imageData[y * itemp->widthStep + (x + 3) + 1] +
    itemp->imageData[y * itemp->widthStep + (x + 3) + 2] / 3)
   +
   (itemp->imageData[y * itemp->widthStep + (x - 3)] +
    itemp->imageData[y * itemp->widthStep + (x - 3) + 1] +
    itemp->imageData[y * itemp->widthStep + (x - 3) + 2] / 3)
   +
   (itemp->imageData[(y + 1) * itemp->widthStep + (x - 3)]  +
    itemp->imageData[(y + 1) * itemp->widthStep + (x - 3) + 1] +
    itemp->imageData[(y + 1) * itemp->widthStep + (x - 3) + 1] / 3)
   +
   (itemp->imageData[(y + 1) * itemp->widthStep + (x + 3)]  +
    itemp->imageData[(y + 1) * itemp->widthStep + (x + 3) + 1] +
    itemp->imageData[(y + 1) * itemp->widthStep + (x + 3) + 1] / 3)
   +
   (itemp->imageData[(y - 1) * itemp->widthStep + (x + 3)] +
    itemp->imageData[(y - 1) * itemp->widthStep + (x + 3) + 1] +
    itemp->imageData[(y - 1) * itemp->widthStep + (x + 3) + 2] / 3)
   +
   (itemp->imageData[(y - 1) * itemp->widthStep + (x - 3)] +
    itemp->imageData[(y - 1) * itemp->widthStep + (x - 3) + 1] +
    itemp->imageData[(y - 1) * itemp->widthStep + (x - 3) + 2] / 3)
   ;

ref /= 8;

if((temp + range) < ref){
   image->imageData[y * image->widthStep + x] = image->imageData[y * image->widthStep + x + 1] = image->imageData[y * image->widthStep + x + 2] = 255;
}
      }
   }
}

void Extractor::Cut()
{
   IplImage *gray = cvCreateImage(cvSize(image->width,image->height),IPL_DEPTH_8U ,1);
   cvCvtColor(image,gray,CV_RGB2GRAY);

   cvCanny(gray,gray,30,90);
   cvSmooth(gray,gray,CV_BLUR);
   cvSmooth(gray,gray,CV_BLUR);
   cvSmooth(gray,gray,CV_BLUR);

   std::multimap<int,CvRect> list;

   CvMemStorage* storage = cvCreateMemStorage( 0 );
   CvSeq* contours = NULL;
   cvFindContours(gray, storage, &contours, sizeof( CvContour ), CV_RETR_LIST,CV_CHAIN_APPROX_NONE);
   for( ; contours != NULL; contours = contours->h_next ){
      CvRect rect = cvBoundingRect( contours, 0 );
      //cvRectangle(image, cvPoint( rect.x, rect.y ),cvPoint( rect.x + rect.width, rect.y + rect.height ), cvScalar(0,0,255), 0 );
      list.insert(std::make_pair(rect.width * rect.height,rect));
   }

   //cvSaveImage("find.jpg",image);

 
   int captcha_numbers = 5;
   std::multimap<int,CvRect> result;
   std::multimap<int,CvRect>::reverse_iterator rit = list.rbegin();
   for(int i = 0;rit != list.rend() && i < captcha_numbers;++rit,++i){
      result.insert(std::make_pair(rit->second.x,rit->second));
   }

   char name[] = "1.jpg";
   std::multimap<int,CvRect>::iterator it = result.begin();
   for(;it != result.end();++it){
      cvSetImageROI(image,it->second);
      cvSaveImage(name,image);
      name[0] += 1;
      //std::cout << it->first << std::endl;
   }
}


main.cpp


#include "extractor.h"

int main(int argc,char**argv)
{
   char *name = argv[1];

   if(name){

      Extractor extractor(name);

      /*************pipeline*************/

      extractor.Average();

      extractor.BackgroundErase();

      extractor.ColorFull();

      extractor.NoiseClear();

      extractor.Cut();
   }
   return 0;
}




針對的樣本:

(這組失敗,7和8被當成同範圍)










2012年11月6日 星期二

累人...

  感覺最近又再重複做去年同樣這個時間在做的事,一直覺得太規律的事情不適合我做,工作也好學校也好太規律就渾身不自在啊啊...前些日子把很久以前寫的繪圖引擎改寫之後先試著做2D ACT遊戲引擎驗證,如果把怪物AI跟物理部分獨立出來用LUA之類的腳本個別設計就可以做任何ACT,等有時間再慢慢來寫另一個3D RPG引擎驗證。



  在沒屋頂買了一個很有趣的東西叫VFD管,整個很漂亮等找人弄到Driver IC再來設計PCB弄個時鐘。



  還有很多東西要學要研究偏偏時間很難把握,其實我自己對時間管理不是很擅長希望到過年前能完成大部分。

2012年10月13日 星期六

wxWidgets With DirectX9 HLSL

    今天翻到以前用MFC+D3D9寫練習用的繪圖引擎,想改寫成wxWidgets版本,只要用wxWindow的GetHandle得到該平台的Handle就可以Create D3D Device了,還有一個是GetHWND意思一樣,要Create D3D10 Device也一樣,然後設定Vertex Shader or Pixel Shader就是D3D Device的事了。

render_data.h


#ifndef __RENDER_DATA__
#define __RENDER_DATA__

#define SAFE_RELEASE(x) if (x){x->Release();x = NULL;}

struct VertexTexture
{
float Position[3];
float Texcoord[2];
};

VertexTexture quad[4] =
{
{{-1.0f, -1.0f, 0.0f},{0.0f, 1.0f}},
{{ 1.0f, -1.0f, 0.0f},{1.0f, 1.0f}},
{{-1.0f,  1.0f, 0.0f},{0.0f, 0.0f}},
{{ 1.0f,  1.0f, 0.0f},{1.0f, 0.0f}}
};

#endif


shader.hlsl


sampler2D Sampler;

uniform float4x4 world_view_proj_matrix : register(c0);

struct VS_INPUT
{
float3 Position : POSITION;
float2 Texcoord : TEXCOORD;
};

struct VS_OUTPUT
{
float4 Position : POSITION;
float2 Texcoord : TEXCOORD0;
};

VS_OUTPUT VS(VS_INPUT In)
{
VS_OUTPUT Out;

Out.Position = mul(world_view_proj_matrix,float4(In.Position, 1.0f));
Out.Texcoord = In.Texcoord;

return Out;
}

float4 PS(VS_OUTPUT In) : COLOR
{
float4 color = tex2D(Sampler, In.Texcoord);

return color;
}



wxDirectX9.h


#ifndef __WX_DIRECT_X__
#define __WX_DIRECT_X__

#include <wx/wx.h>

#include <D3D9.h>
#include <D3DX9.h>

#include "render_data.h"

namespace{
HWND g_hwnd = NULL;

LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pD3DDevice = NULL;
D3DPRESENT_PARAMETERS g_pD3DPresent;
LPDIRECT3DTEXTURE9 g_pTexture = NULL;

LPDIRECT3DVERTEXSHADER9 g_pVertexShaderDX9 = NULL;
LPDIRECT3DPIXELSHADER9  g_pPixelShaderDX9 = NULL;
}

class App:public wxApp
{
public:

bool OnInit();
int OnExit();
};

class Viewport:public wxPanel
{
public:

Viewport(wxWindow*,wxSize);
~Viewport();
void Reset(wxSizeEvent&);
void Updata(wxIdleEvent&);
void Render(wxEraseEvent&);
void InitDX9State();

private:

D3DXVECTOR3 eye;
D3DXVECTOR3 lookat;
D3DXVECTOR3 up;

D3DXMATRIX world_matrix;
D3DXMATRIX view_matrix;
D3DXMATRIX projection_matrix;

static const unsigned long fps = 60;
unsigned long begin,last;

float angle;

DECLARE_EVENT_TABLE()
};

class Frame:public wxFrame
{
public:

Frame(const wxString&,wxSize);
~Frame();

void OnExit(wxCommandEvent&);

bool InitD3D9Device();
void ReleaseD3D9Device();
LPDIRECT3DVERTEXSHADER9 LoadVertexShaderDX9(const wxString&,const wxString&,const wxString&);
LPDIRECT3DPIXELSHADER9 LoadPixelShaderDX9(const wxString&,const wxString&,const wxString&);

void CreateUI();

private:
Viewport *viewport;

DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE(Viewport,wxPanel)
EVT_IDLE(Viewport::Updata)
EVT_ERASE_BACKGROUND(Viewport::Render)
EVT_SIZE(Viewport::Reset)
END_EVENT_TABLE()

BEGIN_EVENT_TABLE(Frame,wxFrame)
EVT_MENU(wxID_EXIT,Frame::OnExit)
END_EVENT_TABLE()

IMPLEMENT_APP(App)
DECLARE_APP(App)

#endif


wxDirectX9.cpp


#include "wxDirectX9.h"

bool App::OnInit()
{
Frame *frame = new Frame(wxT("wxDirectX9"),wxSize(512,512));

frame->Show(true);

return true;
}

int App::OnExit()
{
return wxApp::OnExit();
}

Frame::Frame(const wxString &title,wxSize size):wxFrame(NULL,wxID_ANY,title,wxDefaultPosition,size)
{
viewport = new Viewport(this,size);
g_hwnd = (HWND)viewport->GetHandle();

InitD3D9Device();

g_pVertexShaderDX9 = LoadVertexShaderDX9(wxT("shader.hlsl"),wxT("VS"),wxT("vs_3_0"));
g_pPixelShaderDX9 = LoadPixelShaderDX9(wxT("shader.hlsl"),wxT("PS"),wxT("ps_3_0"));

viewport->InitDX9State();

CreateUI();
}

Frame::~Frame()
{
ReleaseD3D9Device();
}

void Frame::CreateUI()
{
wxMenu *file = new wxMenu;
file->Append(wxID_EXIT,wxT("E&xit\tAlt-q"),wxT("Exit"));

wxMenuBar *bar = new wxMenuBar;
bar->Append(file,wxT("File"));
SetMenuBar(bar);
}

void Frame::OnExit(wxCommandEvent &event)
{
Close();
}

bool Frame::InitD3D9Device()
{
if(g_hwnd == NULL){
return false;
}

RECT rect;
GetWindowRect(g_hwnd,&rect);

float width = rect.right - rect.left;
float height = rect.bottom - rect.top;
if ( width == 0 || height == 0 ){
return false;
}

if( NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) ){
return false;
}

ZeroMemory(&g_pD3DPresent, sizeof(g_pD3DPresent));
g_pD3DPresent.Windowed = TRUE;
g_pD3DPresent.SwapEffect = D3DSWAPEFFECT_DISCARD;
g_pD3DPresent.BackBufferFormat = D3DFMT_UNKNOWN;
g_pD3DPresent.BackBufferCount = 1;
g_pD3DPresent.EnableAutoDepthStencil = TRUE;
g_pD3DPresent.AutoDepthStencilFormat = D3DFMT_D24S8;
g_pD3DPresent.MultiSampleType = (D3DMULTISAMPLE_TYPE)0;
g_pD3DPresent.hDeviceWindow = g_hwnd;

bool device_initialized = false;

const int device_types = 4;

struct sDeviceType
{
D3DDEVTYPE type;
DWORD behavior;
};

sDeviceType device_type[device_types] =
{
{D3DDEVTYPE_HAL,D3DCREATE_HARDWARE_VERTEXPROCESSING},
{D3DDEVTYPE_HAL,D3DCREATE_MIXED_VERTEXPROCESSING},
{D3DDEVTYPE_HAL,D3DCREATE_SOFTWARE_VERTEXPROCESSING},
{D3DDEVTYPE_REF,D3DCREATE_SOFTWARE_VERTEXPROCESSING}
};

for (int type=0;type < device_types;++type)
{
if(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,device_type[type].type,g_hwnd,device_type[type].behavior,&g_pD3DPresent,&g_pD3DDevice) == D3D_OK)
{
device_initialized = true;
break;
}
}

return device_initialized;
}

void Frame::ReleaseD3D9Device()
{
SAFE_RELEASE(g_pD3DDevice);
SAFE_RELEASE(g_pD3D);
SAFE_RELEASE(g_pVertexShaderDX9);
SAFE_RELEASE(g_pPixelShaderDX9);
SAFE_RELEASE(g_pTexture);
}

LPDIRECT3DVERTEXSHADER9 Frame::LoadVertexShaderDX9(const wxString &filename,const wxString &entry,const wxString &profile)
{
LPD3DXBUFFER shader = NULL;
LPD3DXBUFFER error_msg = NULL;
DWORD flags = 0;

HRESULT result = D3DXCompileShaderFromFile(filename.wc_str(),NULL,NULL,entry.mb_str(),profile.mb_str(),flags,&shader,&error_msg,NULL);

if(result != S_OK){return NULL;}

LPDIRECT3DVERTEXSHADER9 vertex_shader = NULL;
result = g_pD3DDevice->CreateVertexShader((DWORD*)shader->GetBufferPointer(),&vertex_shader);

if(result != S_OK){return NULL;}

shader->Release();

return vertex_shader;
}

LPDIRECT3DPIXELSHADER9 Frame::LoadPixelShaderDX9(const wxString &filename,const wxString &entry,const wxString &profile)
{
LPD3DXBUFFER shader = NULL;
LPD3DXBUFFER error_msg = NULL;
DWORD flags = 0;

HRESULT result = D3DXCompileShaderFromFile(filename.wc_str(),NULL,NULL,entry.mb_str(),profile.mb_str(),flags,&shader,&error_msg,NULL);

if(result != S_OK){return NULL;}

LPDIRECT3DPIXELSHADER9 pixel_shader = NULL;
result = g_pD3DDevice->CreatePixelShader((DWORD*)shader->GetBufferPointer(),&pixel_shader);

if(result != S_OK){return NULL;}

shader->Release();

return pixel_shader;
}

Viewport::Viewport(wxWindow *parent,wxSize size):wxPanel(parent,wxID_ANY,wxDefaultPosition,size),eye(0.0f, 3.0f, 3.0f),lookat(0.0f, 0.0f, 0.0f),up(0.0f, -1.0f, 0.0f)
{
begin = last = 0;
angle = 0.0f;
}

Viewport::~Viewport()
{
}

void Viewport::InitDX9State()
{
int width,height;
GetSize(&width,&height);
float aspect = (float)height / (float)width;

D3DXMatrixPerspectiveFovRH(&projection_matrix,45.0f * (3.141592654f/180.0f),aspect,0.1f,10.0f);

D3DXMatrixLookAtRH(&view_matrix,&eye,&lookat,&up);

D3DXMatrixIdentity(&world_matrix);

D3DXMATRIX world_view_proj_matrix = world_matrix * view_matrix * projection_matrix;

g_pD3DDevice->SetVertexShaderConstantF(0,(float*)&world_view_proj_matrix,4);

g_pD3DDevice->SetSamplerState(0,  D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_pD3DDevice->SetSamplerState(0,  D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_pD3DDevice->SetSamplerState(0,  D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

g_pD3DDevice->SetSamplerState(0,  D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
g_pD3DDevice->SetSamplerState(0,  D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

g_pD3DDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

D3DXCreateTextureFromFileEx(g_pD3DDevice,L"lena.bmp",
D3DX_DEFAULT,D3DX_DEFAULT,D3DX_DEFAULT,0,D3DFMT_UNKNOWN,
D3DPOOL_MANAGED,D3DX_DEFAULT,
D3DX_DEFAULT,0,NULL, NULL,
&g_pTexture);
}

void Viewport::Updata(wxIdleEvent &event)
{
begin = wxGetLocalTimeMillis().ToLong();
if(begin - last > (1000 / fps)){
static float angle = 0.0f;
angle += 0.01f;
D3DXMatrixRotationZ(&world_matrix,angle);
D3DXMATRIX world_view_proj_matrix =  world_matrix * view_matrix * projection_matrix;
g_pD3DDevice->SetVertexShaderConstantF(0,(float*)&world_view_proj_matrix,4);
}
Refresh();
}

void Viewport::Reset(wxSizeEvent &event)
{
RECT rect;
GetWindowRect(g_hwnd, &rect);

g_pD3DPresent.BackBufferWidth = 0;
g_pD3DPresent.BackBufferHeight = 0;
g_pD3DPresent.BackBufferCount = 1;
g_pD3DDevice->Reset(&g_pD3DPresent);

int width,height;
GetSize(&width,&height);
float aspect = (float)height / (float)width;

D3DXMatrixPerspectiveFovRH(&projection_matrix,45.0f * (3.141592654f/180.0f),aspect,0.1f,10.0f);

D3DXMatrixLookAtRH(&view_matrix,&eye,&lookat,&up);

D3DXMATRIX world_view_proj_matrix = world_matrix * view_matrix * projection_matrix;

g_pD3DDevice->SetVertexShaderConstantF(0,(float*)&world_view_proj_matrix,4);
}

void Viewport::Render(wxEraseEvent &event)
{
g_pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_ARGB(0, 0, 0, 0),1.0f,0);

g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

g_pD3DDevice->BeginScene();

g_pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1);

g_pD3DDevice->SetVertexShader(g_pVertexShaderDX9);
g_pD3DDevice->SetPixelShader(g_pPixelShaderDX9);

g_pD3DDevice->SetTexture(0, g_pTexture);

g_pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,2,quad,sizeof(VertexTexture));

g_pD3DDevice->EndScene();

g_pD3DDevice->Present(NULL,NULL,NULL,NULL);
}







2012年9月26日 星期三

wxWidgets+OpenGL+OpenCV

    也可以結合Arduino做有趣又簡單的應用,當然還是寫成Multi Thread會比較順暢。


render_data.h

#ifndef __RENDER_DATA__
#define __RENDER_DATA__

typedef struct
{
   float vertex[3];
   float texcoord[2];
}VertexTexture;

VertexTexture vertex[4] = {
   {{-0.5f,-0.5f,0.0f},{0.0f,1.0f}},
   {{0.5f,-0.5f,0.0f},{1.0f,1.0f}},
   {{-0.5f,0.5f,0.0f},{0.0f,0.0f}},
   {{0.5f,0.5f,0.0f},{1.0f,0.0f}}
};

#endif

wxGLCV.h

#ifndef __WX_GLCV__
#define __WX_GLCV__

#include <wx/wx.h>
#include <wx/glcanvas.h>

#include <cv.h>
#include <highgui.h>

#include "render_data.h"

class wxGL;

class App:public wxApp
{
   public:

   bool OnInit();
};

class Frame:public wxFrame
{
   public:

      Frame(const wxString&);
      ~Frame();

      void OnExit(wxCommandEvent&);

      void CreateUI();
      void Render(wxTimerEvent&);
      void Capture();

   private:

      wxGL *gl;
      wxTimer timer;
      wxSlider *angle[3];
      wxImage *image;
      static const unsigned long fps = 25;
      unsigned long begin,last;

      CvCapture *camera;
      IplImage *frame;
      IplImage *temp;

      DECLARE_EVENT_TABLE();
};

class wxGL:public wxGLCanvas
{
   public:

      wxGL(wxWindow*,wxWindowID,
   const wxPoint&,
   const wxSize&,
   long,const wxString);
      ~wxGL();

      void OnSize(wxSizeEvent&);

      void InitGL();
      void Render(wxImage*);
      void SetAngleXYZ(int x,int y,int z){angleX = x;angleY = y,angleZ = z;};

   private:

      bool init;
      float angleX,angleY,angleZ;
      GLuint texture_id;

      DECLARE_EVENT_TABLE();
};

enum{
   RENDER_TIMER = 1000
};

DECLARE_APP(App)
IMPLEMENT_APP(App)

BEGIN_EVENT_TABLE(wxGL,wxGLCanvas)
   EVT_SIZE(wxGL::OnSize)
END_EVENT_TABLE()

BEGIN_EVENT_TABLE(Frame,wxFrame)
   EVT_MENU(wxID_EXIT,Frame::OnExit)
   EVT_TIMER(RENDER_TIMER,Frame::Render)
END_EVENT_TABLE()

#endif

wxGLCV.cpp

#include "wxGLCV.h"

bool App::OnInit()
{
   Frame *frame = new Frame(wxT("wxGL"));

   frame->Show(true);

   return true;
}

Frame::Frame(const wxString &title):wxFrame(NULL,wxID_ANY,title,wxDefaultPosition,wxSize(800,600)),timer(this,RENDER_TIMER)
{
   CreateUI();

   begin = 0;
   last = 0;

   camera = cvCaptureFromCAM(-1);

   timer.Start(10);
}

void Frame::CreateUI()
{
   wxMenu *file = new wxMenu;
   file->Append(wxID_EXIT,wxT("E&xit\tAlt-q"),wxT("Exit"));

   wxMenuBar *bar = new wxMenuBar;
   bar->Append(file,wxT("File"));
   SetMenuBar(bar);

   wxBoxSizer *top = new wxBoxSizer(wxVERTICAL);
   this->SetSizer(top);

   wxBoxSizer *screen_box = new wxBoxSizer(wxVERTICAL);
   top->Add(screen_box,0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);

   wxPanel *panel = new wxPanel(this,wxID_ANY,wxDefaultPosition,wxSize(380,380));
   screen_box->Add(panel,0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);
 
   for(int i = 0;i < 3;++i){
      angle[i] = new wxSlider(this,wxID_ANY,0,0,360,wxDefaultPosition,wxSize(300,-1),wxSL_HORIZONTAL | wxSL_AUTOTICKS | wxSL_LABELS);
      screen_box->Add(angle[i],0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);
   }

   gl = new wxGL(panel,wxID_ANY,wxDefaultPosition,wxSize(380,380),0,wxT("wxGL"));

   CreateStatusBar(2);
   SetStatusText(wxDateTime::Now().Format());

}

void Frame::Render(wxTimerEvent &event){

   begin = wxGetLocalTimeMillis().ToLong();

   gl->SetAngleXYZ(angle[0]->GetValue(),angle[1]->GetValue(),angle[2]->GetValue());

   if(begin - last > (1000 / fps)){
      last = begin;
      Capture();
      gl->Render(image);
   }

}

void Frame::Capture()
{
   frame = cvQueryFrame(camera);
   temp = cvCreateImage(cvSize(frame->width,frame->height),8,3);
   cvZero(temp);

   cvConvertImage(frame,temp,CV_CVTIMG_SWAP_RB);

   unsigned char *data;
   cvGetRawData(temp,&data);

   if(image){
      delete image;
      image = new wxImage(temp->width,temp->height,data,true);
   }
   else{
      image = new wxImage(temp->width,temp->height,data,true);
   }
}

Frame::~Frame()
{
   if(frame){
      cvReleaseImage(&frame);
   }
   if(temp){
      cvReleaseImage(&temp);
   }
   if(camera){
      cvReleaseCapture(&camera);
   }
   timer.Stop();
}

void Frame::OnExit(wxCommandEvent &event)
{
   Close();
}

wxGL::wxGL(wxWindow *paraent,wxWindowID id = wxID_ANY,
      const wxPoint &pos = wxDefaultPosition,
      const wxSize &size = wxDefaultSize,
      long style = 0,const wxString name = wxT("wxGL")):
   wxGLCanvas(paraent,(wxGLCanvas*)NULL,id,pos,size,style | wxFULL_REPAINT_ON_RESIZE,name)
{
   wxInitAllImageHandlers();
   texture_id = 0;
   init = false;
}

void wxGL::InitGL()
{
   SetCurrent();
 
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(60.0f,1.0f,0.1f,100.0f);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(0.0f,0.0f,2.0f,
0.0f,0.0f,0.0f,
0.0f,-1.0f,0.0f);

   for(int i = 0;i < 4;++i){
      vertex[i].texcoord[1] = 1.0f - vertex[i].texcoord[1];
   }

   glEnable(GL_DEPTH_TEST);
   //glEnable(GL_CULL_FACE);
   glEnable(GL_TEXTURE_2D);
}

wxGL::~wxGL()
{
}

void wxGL::OnSize(wxSizeEvent &event)
{
   wxGLCanvas::OnSize(event);

   int w,h;
   GetClientSize(&w,&h);

   if(GetContext()){
      SetCurrent();
      glViewport(0,0,(GLint)w,(GLint)h);
   }
}

void wxGL::Render(wxImage *image)
{
   wxPaintDC dc(this);

   if(!init){
      InitGL();
      init = true;
   }

   SetCurrent();

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glGenTextures(1,&texture_id);
   glBindTexture(GL_TEXTURE_2D,texture_id);
   glTexImage2D(GL_TEXTURE_2D,0,GL_RGB8,
(GLint)image->GetWidth(),(GLint)image->GetHeight(),0,
GL_RGB,GL_UNSIGNED_BYTE,image->GetData());

   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(0.0f,0.0f,2.0f,
0.0f,0.0f,0.0f,
0.0f,-1.0f,0.0f);
   glRotatef(angleX,1.0f,0.0f,0.0f);
   glRotatef(angleY,0.0f,1.0f,0.0f);
   glRotatef(angleZ,0.0f,0.0f,1.0f);

   glEnableClientState(GL_VERTEX_ARRAY);
   glVertexPointer(3,GL_FLOAT,sizeof(VertexTexture),&vertex[0].vertex);

   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   glTexCoordPointer(2,GL_FLOAT,sizeof(VertexTexture),&vertex[0].texcoord);

   glDrawArrays(GL_TRIANGLE_STRIP,0,4);

   SwapBuffers();
}




g++ -o2 -o wxGLCV wxGLCV.cpp `wx-config --cxxflags --libs --unicode --gl-libs` `pkg-config opencv --cflags --libs`



2012年9月21日 星期五

wxWidgets With OpenGL

    最近整理硬碟突然翻到以前剛開始從MFC改用wxWidgets時寫的結合OpenGL的練習實驗,也想到還沒紀錄最基本的怎麼讓wxWidgets操作OpenGL,因為samples的方法我覺得不好,所以我覺得還是紀錄上來好了,基本上只要把wxPanel當作parent傳給wxGLCanvas就可以畫在wxPanel上,然後就可以用wxBoxSizer去layout了,用wxImage載入材質再將相關資訊bind上目標並用VA的方式畫出等等...。

render_data.h

#ifndef __RENDER_DATA__
#define __RENDER_DATA__

typedef struct
{
   float vertex[3];
   float texcoord[2];
}VertexTexture;

VertexTexture vertex[4] = {
   {{-0.5f,-0.5f,0.0f},{0.0f,1.0f}},
   {{0.5f,-0.5f,0.0f},{1.0f,1.0f}},
   {{-0.5f,0.5f,0.0f},{0.0f,0.0f}},
   {{0.5f,0.5f,0.0f},{1.0f,0.0f}}
};

#endif



wxGL.h


#ifndef __WX_GL__
#define __WX_GL__

#include <wx/wx.h>
#include <wx/glcanvas.h>

#include "render_data.h"

class wxGL;

class App:public wxApp
{
   public:

   bool OnInit();
};

class Frame:public wxFrame
{
   public:

      Frame(const wxString&);
      ~Frame();

      void OnExit(wxCommandEvent&);

      void CreateUI();
      void Render(wxTimerEvent&);

   private:

      wxGL *gl;
      wxTimer timer;
      wxSlider *angle[3];
      static const unsigned long fps = 60;
      unsigned long begin,last;

      DECLARE_EVENT_TABLE();
};

class wxGL:public wxGLCanvas
{
   public:

      wxGL(wxWindow*,wxWindowID,
   const wxPoint&,
   const wxSize&,
   long,const wxString);
      ~wxGL();

      void OnSize(wxSizeEvent&);

      void InitGL();
      void Render();
      void SetAngleXYZ(int x,int y,int z){angleX = x;angleY = y,angleZ = z;};

   private:

      bool init;
      float angleX,angleY,angleZ;
      wxImage *image;
      GLuint texture_id;

      DECLARE_EVENT_TABLE();
};

enum{
   RENDER_TIMER = 1000
};

DECLARE_APP(App)
IMPLEMENT_APP(App)

BEGIN_EVENT_TABLE(wxGL,wxGLCanvas)
   EVT_SIZE(wxGL::OnSize)
END_EVENT_TABLE()

BEGIN_EVENT_TABLE(Frame,wxFrame)
   EVT_MENU(wxID_EXIT,Frame::OnExit)
   EVT_TIMER(RENDER_TIMER,Frame::Render)
END_EVENT_TABLE()

#endif


wxGL.cpp


#include "wxGL.h"

bool App::OnInit()
{
   Frame *frame = new Frame(wxT("wxGL"));

   frame->Show(true);

   return true;
}

Frame::Frame(const wxString &title):wxFrame(NULL,wxID_ANY,title,wxDefaultPosition,wxSize(800,600)),timer(this,RENDER_TIMER)
{
   CreateUI();

   begin = 0;
   last = 0;

   timer.Start(10);
}

void Frame::CreateUI()
{
   wxMenu *file = new wxMenu;
   file->Append(wxID_EXIT,wxT("E&xit\tAlt-q"),wxT("Exit"));

   wxMenuBar *bar = new wxMenuBar;
   bar->Append(file,wxT("File"));
   SetMenuBar(bar);

   wxBoxSizer *top = new wxBoxSizer(wxVERTICAL);
   this->SetSizer(top);

   wxBoxSizer *screen_box = new wxBoxSizer(wxVERTICAL);
   top->Add(screen_box,0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);

   wxPanel *panel = new wxPanel(this,wxID_ANY,wxDefaultPosition,wxSize(380,380));
   screen_box->Add(panel,0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);
 
   for(int i = 0;i < 3;++i){
      angle[i] = new wxSlider(this,wxID_ANY,0,0,360,wxDefaultPosition,wxSize(300,-1),wxSL_HORIZONTAL | wxSL_AUTOTICKS | wxSL_LABELS);
      screen_box->Add(angle[i],0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);
   }

   gl = new wxGL(panel,wxID_ANY,wxDefaultPosition,wxSize(380,380),0,wxT("wxGL"));

   CreateStatusBar(2);
   SetStatusText(wxDateTime::Now().Format());

}

void Frame::Render(wxTimerEvent &event){

   begin = wxGetLocalTimeMillis().ToLong();

   gl->SetAngleXYZ(angle[0]->GetValue(),angle[1]->GetValue(),angle[2]->GetValue());

   if(begin - last > (1000 / fps)){
      last = begin;
      gl->Render();
   }

}

Frame::~Frame()
{
   timer.Stop();
}

void Frame::OnExit(wxCommandEvent &event)
{
   Close();
}

wxGL::wxGL(wxWindow *paraent,wxWindowID id = wxID_ANY,
      const wxPoint &pos = wxDefaultPosition,
      const wxSize &size = wxDefaultSize,
      long style = 0,const wxString name = wxT("wxGL")):
   wxGLCanvas(paraent,(wxGLCanvas*)NULL,id,pos,size,style | wxFULL_REPAINT_ON_RESIZE,name)
{
   wxInitAllImageHandlers();
   image = new wxImage(wxT("lena_std.tif"));
   texture_id = 0;
   init = false;
}

void wxGL::InitGL()
{
   SetCurrent();
 
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(60.0f,1.0f,0.1f,100.0f);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(0.0f,0.0f,2.0f,
0.0f,0.0f,0.0f,
0.0f,-1.0f,0.0f);

   for(int i = 0;i < 4;++i){
      vertex[i].texcoord[1] = 1.0f - vertex[i].texcoord[1];
   }

   glGenTextures(1,&texture_id);
   glBindTexture(GL_TEXTURE_2D,texture_id);
   glTexImage2D(GL_TEXTURE_2D,0,GL_RGB8,
(GLint)image->GetWidth(),(GLint)image->GetHeight(),0,
GL_RGB,GL_UNSIGNED_BYTE,image->GetData());

   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

   glEnable(GL_DEPTH_TEST);
   //glEnable(GL_CULL_FACE);
   glEnable(GL_TEXTURE_2D);
}

wxGL::~wxGL()
{
}

void wxGL::OnSize(wxSizeEvent &event)
{
   wxGLCanvas::OnSize(event);

   int w,h;
   GetClientSize(&w,&h);

   if(GetContext()){
      SetCurrent();
      glViewport(0,0,(GLint)w,(GLint)h);
   }
}

void wxGL::Render()
{
   wxPaintDC dc(this);

   if(!init){
      InitGL();
      init = true;
   }

   SetCurrent();

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(0.0f,0.0f,2.0f,
0.0f,0.0f,0.0f,
0.0f,-1.0f,0.0f);
   glRotatef(angleX,1.0f,0.0f,0.0f);
   glRotatef(angleY,0.0f,1.0f,0.0f);
   glRotatef(angleZ,0.0f,0.0f,1.0f);

   glEnableClientState(GL_VERTEX_ARRAY);
   glVertexPointer(3,GL_FLOAT,sizeof(VertexTexture),&vertex[0].vertex);

   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   glTexCoordPointer(2,GL_FLOAT,sizeof(VertexTexture),&vertex[0].texcoord);

   glDrawArrays(GL_TRIANGLE_STRIP,0,4);

   SwapBuffers();
}




g++ -o2 -o wxGL wxGL.cpp `wx-config --cxxflags --libs --unicode --gl-libs`

lena_std.tif