diff --git a/modules/highgui/include/opencv2/highgui/highgui.hpp b/modules/highgui/include/opencv2/highgui/highgui.hpp index 83b451e87d..a770f86fe1 100644 --- a/modules/highgui/include/opencv2/highgui/highgui.hpp +++ b/modules/highgui/include/opencv2/highgui/highgui.hpp @@ -151,6 +151,11 @@ CV_EXPORTS void pointCloudShow(const string& winname, const gpu::GlCamera& camer CV_EXPORTS void pointCloudShow(const string& winname, const gpu::GlCamera& camera, InputArray points, InputArray colors = noArray()); +CV_EXPORTS void addTextOpenGl(const string& winname, const string& text, Point org, Scalar color = Scalar::all(255), + const string& fontName = "Courier New", int fontHeight = 12, + int fontWeight = CV_FONT_NORMAL, int fontStyle = CV_STYLE_NORMAL); +CV_EXPORTS void clearTextOpenGl(const string& winname); + //Only for Qt CV_EXPORTS CvFont fontQt(const string& nameFont, int pointSize=-1, diff --git a/modules/highgui/include/opencv2/highgui/highgui_c.h b/modules/highgui/include/opencv2/highgui/highgui_c.h index fcbde34fe2..6f6cc0dc5f 100644 --- a/modules/highgui/include/opencv2/highgui/highgui_c.h +++ b/modules/highgui/include/opencv2/highgui/highgui_c.h @@ -63,7 +63,8 @@ enum { CV_FONT_LIGHT = 25,//QFont::Light, enum { CV_STYLE_NORMAL = 0,//QFont::StyleNormal, CV_STYLE_ITALIC = 1,//QFont::StyleItalic, - CV_STYLE_OBLIQUE = 2 //QFont::StyleOblique + CV_STYLE_OBLIQUE = 2,//QFont::StyleOblique + CV_STYLE_UNDERLINE = 4 }; /* ---------*/ @@ -257,6 +258,12 @@ CVAPI(void) cvCreateOpenGLCallback( const char* window_name, CvOpenGLCallback ca CVAPI(void) cvSetOpenGlContext(const char* window_name); CVAPI(void) cvUpdateWindow(const char* window_name); +CVAPI(void) cvAddTextOpenGl(const char* winname, const char* text, CvPoint org, CvScalar color CV_DEFAULT(cvScalar(255.0, 255.0, 255.0, 255.0)), + const char* fontName CV_DEFAULT("Courier New"), int fontHeight CV_DEFAULT(12), + int fontWeight CV_DEFAULT(CV_FONT_NORMAL), int fontStyle CV_DEFAULT(CV_STYLE_NORMAL)); + +CVAPI(void) cvClearTextOpenGl(const char* winname); + /****************************************************************************************\ * Working with Video Files and Cameras * \****************************************************************************************/ diff --git a/modules/highgui/src/window.cpp b/modules/highgui/src/window.cpp index 5ed8e34e91..bf241e4f41 100644 --- a/modules/highgui/src/window.cpp +++ b/modules/highgui/src/window.cpp @@ -597,6 +597,35 @@ void cv::pointCloudShow(const string& winname, const gpu::GlCamera& camera, Inpu #endif } +// OpenGL text + +void cv::addTextOpenGl(const string& winname, const string& text, Point org, Scalar color, const string& fontName, int fontHeight, int fontWeight, int fontStyle) +{ + cvAddTextOpenGl(winname.c_str(), text.c_str(), org, color, fontName.c_str(), fontHeight, fontWeight, fontStyle); +} + +void cv::clearTextOpenGl(const string& winname) +{ + cvClearTextOpenGl(winname.c_str()); +} + +#if (!defined WIN32 && !defined _WIN32) || defined HAVE_QT + +CV_IMPL void cvAddTextOpenGl(const char*, const char*, CvPoint, CvScalar, const char*, int, int, int) +{ + CV_Error(CV_OpenGlNotSupported, "This function works only under WIN32"); +} + +CV_IMPL void cvClearTextOpenGl(const char*) +{ + CV_Error(CV_OpenGlNotSupported, "This function works only under WIN32"); +} + +#endif // (!defined WIN32 && !defined _WIN32) || defined HAVE_QT + + +// Without OpenGL + #ifndef HAVE_OPENGL #ifndef HAVE_QT @@ -616,6 +645,16 @@ CV_IMPL void cvUpdateWindow(const char*) CV_Error(CV_OpenGlNotSupported, "The library is compiled without OpenGL support"); } +CV_IMPL void cvAddTextOpenGl(const char*, const char*, CvPoint, CvScalar, const char*, int, int, int) +{ + CV_Error(CV_OpenGlNotSupported, "The library is compiled without OpenGL support"); +} + +CV_IMPL void cvClearTextOpenGl(const char*) +{ + CV_Error(CV_OpenGlNotSupported, "The library is compiled without OpenGL support"); +} + void icvSetOpenGlCleanCallback(const char*, CvOpenGlCleanCallback, void*) { CV_Error(CV_OpenGlNotSupported, "The library is compiled without OpenGL support"); diff --git a/modules/highgui/src/window_w32.cpp b/modules/highgui/src/window_w32.cpp index c89faa3a3f..00a810f13b 100644 --- a/modules/highgui/src/window_w32.cpp +++ b/modules/highgui/src/window_w32.cpp @@ -56,6 +56,9 @@ #ifdef HAVE_OPENGL #include +#include +#include +#include #include "opencv2/highgui/highgui.hpp" #include "opencv2/core/gpumat.hpp" #include @@ -134,6 +137,217 @@ typedef struct CvTrackbar } CvTrackbar; +// OpenGL support + +#ifdef HAVE_OPENGL + +namespace +{ + class OpenGlFont + { + public: + OpenGlFont(HDC hDC, const std::string& fontName, int fontHeight, int fontWeight, int fontStyle); + ~OpenGlFont(); + + void draw(const char* str, int len, CvPoint org, CvScalar color, int width, int height) const; + + inline const std::string& fontName() const { return fontName_; } + inline int fontHeight() const { return fontHeight_; } + inline int fontWeight() const { return fontWeight_; } + inline int fontStyle() const { return fontStyle_; } + + private: + std::string fontName_; + int fontHeight_; + int fontWeight_; + int fontStyle_; + + GLuint base_; + + OpenGlFont(const OpenGlFont&); + OpenGlFont& operator =(const OpenGlFont&); + }; + + int getFontWidthW32(int fontWeight) + { + int weight = 0; + + switch(fontWeight) + { + case CV_FONT_LIGHT: + weight = 200; + break; + case CV_FONT_NORMAL: + weight = FW_NORMAL; + break; + case CV_FONT_DEMIBOLD: + weight = 550; + break; + case CV_FONT_BOLD: + weight = FW_BOLD; + break; + case CV_FONT_BLACK: + weight = FW_BLACK; + break; + default: + cvError(CV_StsBadArg, "getFontWidthW32", "Unsopported fonr width", __FILE__, __LINE__); + }; + + return weight; + } + + OpenGlFont::OpenGlFont(HDC hDC, const std::string& fontName, int fontHeight, int fontWeight, int fontStyle) + : fontName_(), fontHeight_(0), fontWeight_(0), fontStyle_(0), base_(0) + { + base_ = glGenLists(96); + + HFONT font = CreateFont + ( + -fontHeight, // height + 0, // cell width + 0, // Angle of Escapement + 0, // Orientation Angle + getFontWidthW32(fontWeight), // font weight + fontStyle & CV_STYLE_ITALIC ? TRUE : FALSE, // Italic + fontStyle & CV_STYLE_UNDERLINE ? TRUE : FALSE, // Underline + FALSE, // StrikeOut + ANSI_CHARSET, // CharSet + OUT_TT_PRECIS, // OutPrecision + CLIP_DEFAULT_PRECIS, // ClipPrecision + ANTIALIASED_QUALITY, // Quality + FF_DONTCARE | DEFAULT_PITCH, // PitchAndFamily + fontName.c_str() // FaceName + ); + + SelectObject(hDC, font); + + if (!wglUseFontBitmaps(hDC, 32, 96, base_)) + cvError(CV_OpenGlApiCallError, "OpenGlText::set", "Can't create font", __FILE__, __LINE__); + + fontName_ = fontName; + fontHeight_ = fontHeight; + fontWeight_ = fontWeight; + fontStyle_ = fontStyle; + } + + OpenGlFont::~OpenGlFont() + { + if (base_) + glDeleteLists(base_, 96); + } + + void OpenGlFont::draw(const char* str, int len, CvPoint org, CvScalar color, int width, int height) const + { + if (base_) + { + glPushAttrib(GL_LIST_BIT); + glListBase(base_ - 32); + + glColor4dv(color.val); + glRasterPos2f(static_cast(org.x) / width, static_cast((org.y + fontHeight_)) / height); + glCallLists(len, GL_UNSIGNED_BYTE, str); + + glPopAttrib(); + + CV_CheckGlError(); + } + } + + class OpenGlText + { + public: + OpenGlText(HDC hDC); + + void add(const std::string& text, CvPoint org, CvScalar color, const std::string& fontName, int fontHeight, int fontWeight, int fontStyle); + inline void clear() { text_.clear(); } + + void draw(int width, int height) const; + + private: + struct Text + { + std::string str; + + CvPoint org; + CvScalar color; + + cv::Ptr font; + }; + + HDC hDC_; + + std::vector< cv::Ptr > fonts_; + + std::vector text_; + }; + + OpenGlText::OpenGlText(HDC hDC) : hDC_(hDC) + { + fonts_.reserve(5); + text_.reserve(5); + } + + class FontCompare : public std::unary_function, bool> + { + public: + inline FontCompare(const std::string& fontName, int fontHeight, int fontWeight, int fontStyle) + : fontName_(fontName), fontHeight_(fontHeight), fontWeight_(fontWeight), fontStyle_(fontStyle) + { + } + + bool operator ()(const cv::Ptr& font) + { + return font->fontName() == fontName_ && font->fontHeight() == fontHeight_ && font->fontWeight() == fontWeight_ && font->fontStyle() == fontStyle_; + } + + private: + std::string fontName_; + int fontHeight_; + int fontWeight_; + int fontStyle_; + }; + + void OpenGlText::add(const std::string& str, CvPoint org, CvScalar color, const std::string& fontName, int fontHeight, int fontWeight, int fontStyle) + { + std::vector< cv::Ptr >::iterator fontIt = + std::find_if(fonts_.begin(), fonts_.end(), FontCompare(fontName, fontHeight, fontWeight, fontStyle)); + + if (fontIt == fonts_.end()) + { + fonts_.push_back(new OpenGlFont(hDC_, fontName, fontHeight, fontWeight, fontStyle)); + fontIt = fonts_.end() - 1; + } + + Text text; + text.str = str; + text.org = org; + text.color = color; + text.font = *fontIt; + + text_.push_back(text); + } + + void OpenGlText::draw(int width, int height) const + { + glDisable(GL_DEPTH_TEST); + + static cv::gpu::GlCamera glCamera; + glCamera.setupProjectionMatrix(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + for (size_t i = 0, size = text_.size(); i < size; ++i) + { + const Text& text = text_[i]; + text.font->draw(text.str.c_str(), text.str.length(), text.org, text.color, width, height); + } + } +} + +#endif // HAVE_OPENGL + + typedef struct CvWindow { int signature; @@ -178,11 +392,12 @@ typedef struct CvWindow void* glCleanData; cv::gpu::GlFuncTab* glFuncTab; + + OpenGlText* glText; #endif } CvWindow; - #define HG_BUDDY_WIDTH 130 #ifndef TBIF_SIZE @@ -743,6 +958,8 @@ namespace void initGl(CvWindow* window) { + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + std::auto_ptr glFuncTab(new GlFuncTab_W32); // Load extensions @@ -872,6 +1089,11 @@ namespace CV_CheckGlError(); + if (window->glText) + window->glText->draw(window->width, window->height); + + CV_CheckGlError(); + if (!SwapBuffers(window->dc)) CV_ERROR( CV_OpenGlApiCallError, "Can't swap OpenGL buffers" ); @@ -919,57 +1141,6 @@ CV_IMPL int cvNamedWindow( const char* name, int flags ) if (window != 0) { result = 1; - - #ifdef HAVE_OPENGL - if (window->useGl && !(flags & CV_WINDOW_OPENGL)) - { - wglMakeCurrent(window->dc, window->hGLRC); - - if (window->glCleanCallback) - { - window->glCleanCallback(window->glCleanData); - window->glCleanCallback = 0; - window->glCleanData = 0; - } - - releaseGlContext(window); - - window->dc = CreateCompatibleDC(0); - window->hGLRC = 0; - window->useGl = false; - } - else if (!window->useGl && (flags & CV_WINDOW_OPENGL)) - { - if (window->dc && window->image) - DeleteObject(SelectObject(window->dc, window->image)); - - if (window->dc) - DeleteDC(window->dc); - - bool useGl = false; - HDC hGLDC = 0; - HGLRC hGLRC = 0; - - createGlContext(window->hwnd, hGLDC, hGLRC, useGl); - - if (!useGl) - { - window->dc = CreateCompatibleDC(0); - window->hGLRC = 0; - window->useGl = false; - - result = 0; - } - else - { - window->dc = hGLDC; - window->hGLRC = hGLRC; - window->useGl = true; - initGl(window); - } - } - #endif // HAVE_OPENGL - EXIT; } @@ -1038,6 +1209,8 @@ CV_IMPL int cvNamedWindow( const char* name, int flags ) window->glCleanCallback = 0; window->glCleanData = 0; + + window->glText = 0; #endif window->last_key = 0; @@ -1093,6 +1266,67 @@ CV_IMPL void cvSetOpenGlContext(const char* name) __END__; } +CV_IMPL void cvAddTextOpenGl(const char* name, const char* text, CvPoint org, CvScalar color, const char* fontName, int fontHeight, int fontWeight, int fontStyle) +{ + CV_FUNCNAME( "cvSetOpenGlContext" ); + + __BEGIN__; + + CvWindow* window; + + if(!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + CV_ERROR( CV_StsNullPtr, "NULL window" ); + + if (!window->useGl) + CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" ); + + if (!wglMakeCurrent(window->dc, window->hGLRC)) + CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" ); + + if (!window->glText) + window->glText = new OpenGlText(window->dc); + + window->glText->add(text, org, color, fontName, fontHeight, fontWeight, fontStyle); + + InvalidateRect(window->hwnd, 0, 0); + + __END__; +} + +CV_IMPL void cvClearTextOpenGl(const char* name) +{ + CV_FUNCNAME( "cvSetOpenGlContext" ); + + __BEGIN__; + + CvWindow* window; + + if(!name) + CV_ERROR( CV_StsNullPtr, "NULL name string" ); + + window = icvFindWindowByName( name ); + if (!window) + CV_ERROR( CV_StsNullPtr, "NULL window" ); + + if (!window->useGl) + CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" ); + + if (!wglMakeCurrent(window->dc, window->hGLRC)) + CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" ); + + if (window->glText) + { + window->glText->clear(); + InvalidateRect(window->hwnd, 0, 0); + } + + __END__; +} + CV_IMPL void cvUpdateWindow(const char* name) { CV_FUNCNAME( "cvUpdateWindow" ); @@ -1172,6 +1406,9 @@ static void icvRemoveWindow( CvWindow* window ) if (window->useGl) { wglMakeCurrent(window->dc, window->hGLRC); + + if (window->glText) + delete window->glText; if (window->glCleanCallback) { diff --git a/samples/cpp/point_cloud.cpp b/samples/cpp/point_cloud.cpp index 42408919f5..d668da6187 100644 --- a/samples/cpp/point_cloud.cpp +++ b/samples/cpp/point_cloud.cpp @@ -1,11 +1,13 @@ #include #include #include +#include #include "opencv2/core/core.hpp" #include "opencv2/core/gpumat.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/calib3d/calib3d.hpp" +#include "opencv2/contrib/contrib.hpp" using namespace std; using namespace cv; @@ -187,13 +189,15 @@ int main(int argc, const char* argv[]) reprojectImageTo3D(disp, points, Q); - namedWindow("OpenGL Sample", WINDOW_OPENGL); + const string windowName = "OpenGL Sample"; + + namedWindow(windowName, WINDOW_OPENGL); int fov = 0; - createTrackbar("Fov", "OpenGL Sample", &fov, 100); + createTrackbar("Fov", windowName, &fov, 100); int mouse[2] = {0, 0}; - setMouseCallback("OpenGL Sample", mouseCallback, mouse); + setMouseCallback(windowName, mouseCallback, mouse); GlArrays pointCloud; @@ -211,8 +215,14 @@ int main(int argc, const char* argv[]) const Point3d leftVec(-1.0, 0.0, 0.0); Point3d pos; + TickMeter tm; + const int step = 20; + int frame = 0; + while (true) { + tm.start(); + int key = waitKey(1); if (key >= 0) key = key & 0xff; @@ -220,7 +230,7 @@ int main(int argc, const char* argv[]) if (key == 27) break; - double aspect = getWindowProperty("OpenGL Sample", WND_PROP_ASPECT_RATIO); + double aspect = getWindowProperty(windowName, WND_PROP_ASPECT_RATIO); const double posStep = 0.1; @@ -256,7 +266,21 @@ int main(int argc, const char* argv[]) camera.setCameraPos(pos, yaw, pitch, 0.0); - pointCloudShow("OpenGL Sample", camera, pointCloud); + pointCloudShow(windowName, camera, pointCloud); + + tm.stop(); + + if (frame++ >= step) + { + ostringstream fps; + fps << "FPS: " << step / tm.getTimeSec(); + + clearTextOpenGl(windowName); + addTextOpenGl(windowName, fps.str(), Point(0, 0), Scalar::all(255), "Courier New", 16); + + frame = 0; + tm.reset(); + } } return 0;