寫在前面:其實(shí)本不應(yīng)該發(fā)在Java方面的,只是最近在做的項(xiàng)目因?yàn)閷?shí)時(shí)應(yīng)用的關(guān)系沒(méi)有使用Java,因此借這里記錄一下心得。
最近在一個(gè)在Linux下開(kāi)放的項(xiàng)目中用到了wxWidgets,當(dāng)時(shí)在GTK+、QT和wx之間選擇了很久,最終確定選擇wxWidgets。有關(guān)這個(gè)框架的詳細(xì)信息,請(qǐng)自行g(shù)oogle之。
1. 整合OpenGL
WxWidgets中整合OpenGL是十分簡(jiǎn)單的,因?yàn)閣xWidgets本身對(duì)OpenGL進(jìn)行了封裝,因此只需要按照example中的例子進(jìn)行編寫即可。一種常見(jiàn)的方法是繼承wxGLCanvas類,將EVT_PAINT的回調(diào)函數(shù)進(jìn)行重載即可。一段示例代碼如下:
static int attriblist[] = {
WX_GL_RGBA, WX_GL_MIN_RED, 1, WX_GL_MIN_GREEN, 1,
WX_GL_MIN_BLUE, 1, WX_GL_DEPTH_SIZE, 1, WX_GL_DOUBLEBUFFER, None
};
BEGIN_EVENT_TABLE(UIOpenGLCanvas, wxGLCanvas)
EVT_SIZE(UIOpenGLCanvas::OnSize)
EVT_PAINT(UIOpenGLCanvas::OnPaint)
EVT_MOUSE_EVENTS(UIOpenGLCanvas::OnMouseEvent)
END_EVENT_TABLE()
UIOpenGLCanvas::UIOpenGLCanvas(wxWindow *parent, const wxString &caption)
// :wxGLCanvas(parent, wxID_ANY, attriblist, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE, wxT("GLCanvas"), wxNullPalette)
// :wxGLCanvas(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE, wxT("GLCanvas"))
:wxGLCanvas(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE, wxT("GLCanvas"), attriblist, wxNullPalette)
,m_caption(caption), count(0) {
int argc = 1;
char* argv[1] = { wxString((wxTheApp->argv)[0]).char_str() };
/*
NOTE: this example uses GLUT in order to have a free teapot model
to display, to show 3D capabilities. GLUT, however, seems to cause problems
on some systems. If you meet problems, first try commenting out glutInit(),
then try comeenting out all glut code
*/
glutInit(&argc, argv);
}
UIOpenGLCanvas::~UIOpenGLCanvas() {
}
void UIOpenGLCanvas::OnSize(wxSizeEvent& event) {
// this is also necessary to update the context on some platforms
wxGLCanvas::OnSize(event);
// set GL viewport (not called by wxGLCanvas::OnSize on all platforms
)
int w, h;
GetClientSize(&w, &h);
if (GetContext()) {
SetCurrent();
glViewport(0, 0, (GLint) w, (GLint) h);
}
}
void UIOpenGLCanvas::OnMouseEvent(wxMouseEvent& event) {
static int dragging = 0;
static float last_x, last_y;
// printf("%f %f %d\n", event.GetX(), event.GetY(), (int)event.LeftIsDown());
if(event.LeftIsDown()) {
if(!dragging) {
dragging = 1;
} else {
yrot += (event.GetX() - last_x)*1.0;
xrot += (event.GetY() - last_y)*1.0;
Refresh(false);
}
last_x = event.GetX();
last_y = event.GetY();
} else
dragging = 0;
}
void UIOpenGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
Render();
}
void UIOpenGLCanvas::Render() {
/* 此處很關(guān)鍵 */
wxPaintDC(this);
if (!GetContext())
return;
SetCurrent();
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, (GLint)GetSize().x, (GLint)GetSize().y);
glBegin(GL_POLYGON);
glColor3f(1.0, 0.0, 0.0);
glVertex2f(0.1, 0.1);
glVertex2f(-0.1, 0.1);
glVertex2f(-0.1, -0.1);
glVertex2f(0.1, -0.1);
glEnd();
// using a little of glut
glColor4f(0,0,1,1);
glutWireTeapot(0.4);
glPopMatrix();
glFlush();
SwapBuffers();
}
2. 整合OpenCV
這個(gè)話題在網(wǎng)上有過(guò)討論,在OpenCV中文論壇中提出了一種向HDC繪圖的方法。不過(guò)這種方法的局限在于:HDC是Windows平臺(tái)下特有的結(jié)構(gòu),在Linux下是不可行的。
其實(shí)OpenCV的核心是IplImage結(jié)構(gòu),基本上所有的OpenCV繪圖語(yǔ)句以及相應(yīng)的算法都可以通過(guò)這個(gè)結(jié)構(gòu)衍生出來(lái)。因此,一種直接的想法是如何將IplImage轉(zhuǎn)換為wxWidgets中的wxImage類型,這樣就可以直接在wxWidgets繪制IplImage類型的數(shù)據(jù)了。于是在網(wǎng)上尋找后,在一個(gè)國(guó)外論壇中找到了現(xiàn)成的代碼如下:
void copy_and_swap_rb(char *s, char *d, int size)
{
// Copy image data source s to destination d, swapping R and B channels.
// Assumes 8 bit depth, 3 interleaved channels, and width_step = width*3
const int step = 3;
char *end = s + size;
while (s<end) {
d[0] = s[2];
d[1] = s[1];
d[2] = s[0];
d += step;
s += step;
}
}
void wx2cv(wxImage &wx, IplImage *ipl)
{
// Copy image data from wxWidgets image to Ipl (opencv) image
// Assumes ipl image has seq "GBR", depth 8, and 3 channels, and
// has the same size as the wxImage, and width_step = width*3.
copy_and_swap_rb((char*)wx.GetData(), ipl->imageData, ipl->imageSize);
}
void cv2wx(IplImage *ipl, wxImage &wx )
{
// Copy image data from Ipl (opencv) image to wxImage
// Assumes ipl image has seq "GBR", depth 8, and 3 channels, and
// has the same size as the wxImage, and width_step = width*3.
copy_and_swap_rb( ipl->imageData, (char*)wx.GetData(),
wx.GetWidth()*wx.GetHeight()*3);
}
IplImage *cv_from_wx(wxImage &wx)
{
// Return a new IplImage copied from a wxImage.
// Must be freed by user with cvReleaseImage().
IplImage *ret = cvCreateImage(cvSize(wx.GetWidth(), wx.GetHeight()),
IPL_DEPTH_8U, 3);
wx2cv(wx, ret);
return ret;
}
wxImage wx_from_cv( IplImage *cx)
{
// Return new wxImage copied from a compatible IplImage.
// Assumes ipl image has seq "GBR", depth 8, and 3 channels
// Fear not. The copy on return is cheap; does not deep-copy the data.
wxImage wx(cx->width, cx->height, (unsigned char*) malloc(cx->imageSize), false);
cv2wx(cx, wx);
return wx;
}
進(jìn)行這樣的轉(zhuǎn)換后,我們就直接可以在wxWidgets中使用OpenCV的接口。
3. 整合MathPlot
MathPlot是sourceforge上的一個(gè)開(kāi)源項(xiàng)目,其功能是使用wxWidgets提供的繪圖方法構(gòu)建操作DC繪圖的高級(jí)接口。這個(gè)項(xiàng)目的源代碼十分簡(jiǎn)單,只有兩個(gè)文件,但是功能卻很實(shí)用。我在sourceforge上給了好評(píng)。
MathPlot內(nèi)部實(shí)現(xiàn)了坐標(biāo)軸的拖拽、平移和縮放,將圖形劃分為L(zhǎng)ayer,并且引入了動(dòng)態(tài)Layer的概念,即在這個(gè)Layer上繪制的圖形可以通過(guò)重設(shè)局部坐標(biāo)系的原點(diǎn)基準(zhǔn)坐標(biāo)實(shí)現(xiàn)移動(dòng),并繪制軌跡。而且,MathPlot內(nèi)部實(shí)現(xiàn)了雙緩沖,因此,這個(gè)框架對(duì)于需要實(shí)時(shí)顯示軌跡的簡(jiǎn)單應(yīng)用來(lái)說(shuō)具有很好使用價(jià)值。
由于MathPlot直接使用了wxWidgets的繪圖接口,因此其整合十分簡(jiǎn)單,只需要在需要繪制的Panel上使用MathPlot提供的接口即可實(shí)現(xiàn)整合。
以上簡(jiǎn)單說(shuō)明了wxWidgets如何整合OpenGL、OpenCV和MathPlot三種不同的繪圖框架,最后給一個(gè)將三種繪圖方法用在同一個(gè)窗口中實(shí)現(xiàn)不同功能的實(shí)例:
無(wú)人分享的快樂(lè)不是真快樂(lè),沒(méi)人分擔(dān)的痛苦是真痛苦。
posted on 2011-01-16 11:03
Feenn 閱讀(5587)
評(píng)論(2) 編輯 收藏