OpenCV的GUI部分做的太简单了 复杂的功能难以实现 整合其他库时接口兼容性等问题多多 真费事 写个手记以备用
转载请注明http://blog.csdn.net/boksic 如有疑问欢迎留言
安装wxwidgets(http://wiki.wxwidgets.org/Installing_and_configuring_under_Ubuntu)
sudo apt-get install libwxgtk2.8-dev libwxgtk2.8-dbg
安装opengl
sudo apt-get install freeglut3-dev libglew1.5-dev
为链接器添加链接库选项
-lGLU -lglut
整合wxWidgets
编译时出现错误
/usr/include/wx/platform.h:196:22: fatal error: wx/setup.h: そのようなファイルやディレクトリはありません
编译选项的问题
给 compiler加上 `wx-config --cxxflags`
给 linker加上`wx-config --libs --gl-libs`
首先 在运行wxWidgets的主循环函数时如何同时运行opencv或opengl的实时性函数(如摄像头捕获)
参考http://wiki.wxwidgets.org/Making_a_render_loop的文章
当中最好的方法是采用idle events
首先要定义好显示opencv或opengl的面板派生类,本例中用的是BasicDrawPane和BasicGLPane(会在后面讲到)
BasicDrawPane* drawPane; BasicGLPane *glPane;其中drawPane是用来绘制OpenCV数据,glPane是用来绘制OpenGL数据。
在主frame的初始化函数中添加面板的显示函数
在主程序函数的onIdle中添加绘图函数
如果还要添加其他的实时显示 按照这个模式修改如下地方即可
class MyApp: public wxApp { //省略 BasicDrawPane* drawPane; BasicGLPane *glPane; //省略 }; bool MyApp::OnInit() { //省略 drawPane = new BasicDrawPane(frame); sizer->Add(drawPane, 1, wxEXPAND); int args[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0 }; glPane = new BasicGLPane((wxFrame*) frame, args); sizer->Add(glPane, 1, wxEXPAND); //省略 } void MyApp::onIdle(wxIdleEvent& evt) { if (render_loop_on) { glPane->paintNow(); drawPane->paintNow(); //省略 } }
class MyFrame; class MyApp: public wxApp { bool render_loop_on; bool OnInit(); void onIdle(wxIdleEvent& evt); MyFrame* frame; BasicDrawPane* drawPane; BasicGLPane *glPane; public: void activateRenderLoop(bool on); }; IMPLEMENT_APP(MyApp) class MyFrame: public wxFrame { public: wxString CurrentDocPath; MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); void onClose(wxCloseEvent& evt) { wxGetApp().activateRenderLoop(false); evt.Skip(); // don't stop event, we still want window to close } void OnQuit(wxCommandEvent& event); DECLARE_EVENT_TABLE() }; enum { ID_Quit = 1 }; BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(ID_Quit, MyFrame::OnQuit) EVT_CLOSE(MyFrame::onClose) END_EVENT_TABLE() void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) { Close(true); } MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, -1, title, pos, size) { wxMenu *menuFile = new wxMenu; menuFile->Append(ID_Quit, _("E&xit") ); wxMenuBar *menuBar = new wxMenuBar; menuBar->Append(menuFile, _("&File") ); SetMenuBar(menuBar); CreateStatusBar(); SetStatusText(_("http://blog.csdn.net/boksic")); } bool MyApp::OnInit() { render_loop_on = false; wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); frame = new MyFrame(_("HMD Interface"), wxPoint(-1, -1), wxSize(1280, 530)); drawPane = new BasicDrawPane(frame); sizer->Add(drawPane, 1, wxEXPAND); int args[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0 }; glPane = new BasicGLPane((wxFrame*) frame, args); sizer->Add(glPane, 1, wxEXPAND); frame->SetSizer(sizer); frame->SetAutoLayout(true); frame->Show(); activateRenderLoop(true); cap = VideoCapture("input.avi"); return true; } void MyApp::activateRenderLoop(bool on) { if (on && !render_loop_on) { Connect(wxID_ANY, wxEVT_IDLE, wxIdleEventHandler(MyApp::onIdle) ); render_loop_on = true; } else if (!on && render_loop_on) { Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyApp::onIdle) ); render_loop_on = false; } } void MyApp::onIdle(wxIdleEvent& evt) { if (render_loop_on) { glPane->paintNow(); drawPane->paintNow(); evt.RequestMore(); } }
class BasicDrawPane: public wxPanel { public: BasicDrawPane(wxFrame* parent); void paintEvent(wxPaintEvent& evt); void paintNow(); void render(wxDC& dc); DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(BasicDrawPane, wxPanel) EVT_PAINT(BasicDrawPane::paintEvent) END_EVENT_TABLE() BasicDrawPane::BasicDrawPane(wxFrame* parent) : wxPanel(parent) { } void BasicDrawPane::paintEvent(wxPaintEvent& evt) { wxPaintDC dc(this); render(dc); } void BasicDrawPane::paintNow() { wxClientDC dc(this); render(dc); } void BasicDrawPane::render(wxDC& dc) { if (cap.read(ori))//从摄像头读取一帧图像到mat数据ori中 process();//自己的opencv处理函数 cvtColor(frame, temp, CV_RGB2BGR); wxImage wxImage0(temp.cols, temp.rows, temp.data, true); wxBitmap wxBitmap0 = wxBitmap(wxImage0); dc.DrawBitmap(wxBitmap0, 0, 0); }
当中一个关键点是是如何将opencv的mat数据显示出来 其实很简单的几句代码就可以了
frame和temp都是opencv的mat类数据
要将frame图像显示出来 先进行rgb到bgr转换 再wximage转换、wxbitmap转换即可
cvtColor(frame, temp, CV_RGB2BGR); wxImage wxImage0(temp.cols, temp.rows, temp.data, true); wxBitmap wxBitmap0 = wxBitmap(wxImage0); dc.DrawBitmap(wxBitmap0, 0, 0);
显示opengl的类用的是wxGLCanvas的派生,区别不算大
class BasicGLPane : public wxGLCanvas { wxGLContext* m_context; CModel3DS * monkey; public: BasicGLPane(wxFrame* parent, int* args); virtual ~BasicGLPane(); void resized(wxSizeEvent& evt); void paintEvent(wxPaintEvent& evt); void paintNow(); void render(wxDC& dc); DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(BasicGLPane, wxGLCanvas) EVT_PAINT(BasicGLPane::paintEvent) END_EVENT_TABLE() GLMmodel* pmodel1 = NULL; void BasicGLPane::paintEvent(wxPaintEvent& evt) { wxPaintDC dc(this); render(dc); } void BasicGLPane::paintNow() { wxClientDC dc(this); render(dc); } BasicGLPane::BasicGLPane(wxFrame* parent, int* args) : wxGLCanvas(parent, wxID_ANY, args, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE) { m_context = new wxGLContext(this); // To avoid flashing on MSW SetBackgroundStyle(wxBG_STYLE_CUSTOM); int argc = 1; char* argv[1] = { wxString((wxTheApp->argv)[0]).char_str() }; glutInit(&argc, argv); //这里是opengl的初始化代码段 可以添加自己代码 } BasicGLPane::~BasicGLPane() { delete m_context; } void BasicGLPane::resized(wxSizeEvent& evt) { Refresh(); } void BasicGLPane::render(wxDC& dc) { if (!IsShown()) return; wxGLCanvas::SetCurrent(*m_context); wxPaintDC(this); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//这里是opengl的绘图代码段 可以添加自己代码 glFlush(); SwapBuffers(); }