opengl离屏渲染(不需要和窗口绑定,仅当作一个可以渲染一张图片的API使用)+ opencv显示
2015-05-22 15:29
821 查看
【原文:http://www.csdn123.com/html/itweb/20130919/127140_127126_127133.htm】
具体过程参考的是这篇BLOG: http://wiki.woodpecker.org.cn/moin/lilin/swig-glBmpContext 这一片BLOG的代码有个 BOOL SaveBmp(HBITMAP hBitmap, string FileName) 的函数,功能为保存成BMP格式的图片,我的代码中也就省去了这部分,用opencv来处理,这样使得熟悉opencv的人也能比较好了解吧,毕竟Windows的API一些结构体确实看起来比较生涩难懂。
以上的代码可以直接编译运行,记得加上opengl32.lib和glu32.lib(还有加上opencv的配置,如果不需要的话可以直接注释掉和OpenCV有关的代码,原始代码可以参考文章开头给出的blog)
还有值得注意的是pbits指向的是从图像左下角开始,由下至上的像素点的排列,和opencv的由上至下刚好相反,所以opencv显示的图片是水平镜像的。
简单得说吧,要进行离屏渲染,win32下需要做下面的几个步骤:
1.创建一个内存 DC
2.创建一个位图
3.把位图选入DC
4.设置DC的像元格式
5.通过DC创建OpenGL的渲染上下文RC
6.开始渲染.
其中有个GdiFlush()的函数,其作用是提供一个mutex的机制,给GDI objects提供一个保护机制,因为opengl在执行glFlush()绘制的时候,是可以没有等待绘制完就返回的(可以百度glFlush和glFinish的区别),如果这时候访问了GDI object可能会访问的是一个未完成的结果,或者产生读写冲突。
MSDN的解释是这样的:
An application should call GdiFlush before a thread goes away if there is a possibility that there are pending function calls in
the graphics batch queue. The system does not execute such batched functions when a thread goes away.
A multithreaded application that serializes access to GDI objects with a mutex must ensure flushing the GDI batch queue by calling GdiFlush as
each thread releases ownership of the GDI object. This prevents collisions of the GDI objects (device contexts, metafiles, and so on).
但是目前为止,还没发现过使用glFlush和glFinish的差异(难道是现在的显卡都太快了,绘制自己写的场景用的时间很短),如果大家有什么见解欢迎讨论哈。
具体过程参考的是这篇BLOG: http://wiki.woodpecker.org.cn/moin/lilin/swig-glBmpContext 这一片BLOG的代码有个 BOOL SaveBmp(HBITMAP hBitmap, string FileName) 的函数,功能为保存成BMP格式的图片,我的代码中也就省去了这部分,用opencv来处理,这样使得熟悉opencv的人也能比较好了解吧,毕竟Windows的API一些结构体确实看起来比较生涩难懂。
#include <windows.h> #include <iostream> #include <gl/gl.h> #include <gl/glu.h> #include <string> #include <time.h> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace std; using namespace cv; void mGLRender() { glClearColor(0.9f,0.9f,0.3f,1.0f); glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(30.0, 1.0, 1.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0, 0, -5, 0, 0, 0, 0, 1, 0); glBegin(GL_TRIANGLES); glColor3d(1, 0, 0); glVertex3d(0, 1, 0); glColor3d(0, 1, 0); glVertex3d(-1, -1, 0); glColor3d(0, 0, 1); glVertex3d(1, -1, 0); glEnd(); glFlush(); // remember to flush GL output! } void mGLRender1() { glClearColor(0.3f,0.3f,0.3f,1.0f); glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(30.0, 1.0, 1.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0, 0, -5, 0, 0, 0, 0, 1, 0); glBegin(GL_TRIANGLES); glColor3d(1, 0, 0); glVertex3d(0, 1, 0); glColor3d(0, 1, 0); glVertex3d(-1, -1, 0); glColor3d(0, 0, 1); glVertex3d(1, -1, 0); glEnd(); glFlush(); // remember to flush GL output! } int main(int argc, char* argv[]) { clock_t clockBegin, clockEnd; const int WIDTH = 400; const int HEIGHT = 400; // Create a memory DC compatible with the screen HDC hdc = CreateCompatibleDC(0); if (hdc == 0) cout<<"Could not create memory device context"; // Create a bitmap compatible with the DC // must use CreateDIBSection(), and this means all pixel ops must be synchronised // using calls to GdiFlush() (see CreateDIBSection() docs) BITMAPINFO bmi = { { sizeof(BITMAPINFOHEADER), WIDTH, HEIGHT, 1, 32, BI_RGB, 0, 0, 0, 0, 0 }, { 0 } }; unsigned char *pbits; // pointer to bitmap bits HBITMAP hbm = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void **) &pbits, 0, 0); if (hbm == 0) cout<<"Could not create bitmap"; //HDC hdcScreen = GetDC(0); //HBITMAP hbm = CreateCompatibleBitmap(hdcScreen,WIDTH,HEIGHT); // Select the bitmap into the DC HGDIOBJ r = SelectObject(hdc, hbm); if (r == 0) cout<<"Could not select bitmap into DC"; // Choose the pixel format PIXELFORMATDESCRIPTOR pfd = { sizeof (PIXELFORMATDESCRIPTOR), // struct size 1, // Version number PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL, // use OpenGL drawing to BM PFD_TYPE_RGBA, // RGBA pixel values 32, // color bits 0, 0, 0, // RGB bits shift sizes... 0, 0, 0, // Don't care about them 0, 0, // No alpha buffer info 0, 0, 0, 0, 0, // No accumulation buffer 32, // depth buffer bits 0, // No stencil buffer 0, // No auxiliary buffers PFD_MAIN_PLANE, // Layer type 0, // Reserved (must be 0) 0, // No layer mask 0, // No visible mask 0, // No damage mask }; int pfid = ChoosePixelFormat(hdc, &pfd); if (pfid == 0) cout<<"Pixel format selection failed"; // Set the pixel format // - must be done *after* the bitmap is selected into DC BOOL b = SetPixelFormat(hdc, pfid, &pfd); if (!b) cout<<"Pixel format set failed"; // Create the OpenGL resource context (RC) and make it current to the thread HGLRC hglrc = wglCreateContext(hdc); if (hglrc == 0) cout<<"OpenGL resource context creation failed"; wglMakeCurrent(hdc, hglrc); // Draw using GL - remember to sync with GdiFlush() clockBegin = clock(); mGLRender(); GdiFlush(); //SaveBmp(hbm,"output.bmp"); clockEnd = clock(); printf("%d\n", clockEnd - clockBegin); clockBegin = clock(); mGLRender1(); GdiFlush(); //SaveBmp(hbm,"output1.bmp"); clockEnd = clock(); printf("%d\n", clockEnd - clockBegin); /* Examining the bitmap bits (pbits) at this point with a debugger will reveal that the colored triangle has been drawn. */ //opencv show img Mat img(HEIGHT,WIDTH,CV_8UC4,(void *)pbits); imshow("img",img); waitKey(); destroyWindow("img"); // Clean up wglDeleteContext(hglrc); // Delete RC SelectObject(hdc, r); // Remove bitmap from DC DeleteObject(hbm); // Delete bitmap DeleteDC(hdc); // Delete DC system("pause"); return 0; }
以上的代码可以直接编译运行,记得加上opengl32.lib和glu32.lib(还有加上opencv的配置,如果不需要的话可以直接注释掉和OpenCV有关的代码,原始代码可以参考文章开头给出的blog)
还有值得注意的是pbits指向的是从图像左下角开始,由下至上的像素点的排列,和opencv的由上至下刚好相反,所以opencv显示的图片是水平镜像的。
简单得说吧,要进行离屏渲染,win32下需要做下面的几个步骤:
1.创建一个内存 DC
2.创建一个位图
3.把位图选入DC
4.设置DC的像元格式
5.通过DC创建OpenGL的渲染上下文RC
6.开始渲染.
其中有个GdiFlush()的函数,其作用是提供一个mutex的机制,给GDI objects提供一个保护机制,因为opengl在执行glFlush()绘制的时候,是可以没有等待绘制完就返回的(可以百度glFlush和glFinish的区别),如果这时候访问了GDI object可能会访问的是一个未完成的结果,或者产生读写冲突。
MSDN的解释是这样的:
An application should call GdiFlush before a thread goes away if there is a possibility that there are pending function calls in
the graphics batch queue. The system does not execute such batched functions when a thread goes away.
A multithreaded application that serializes access to GDI objects with a mutex must ensure flushing the GDI batch queue by calling GdiFlush as
each thread releases ownership of the GDI object. This prevents collisions of the GDI objects (device contexts, metafiles, and so on).
但是目前为止,还没发现过使用glFlush和glFinish的差异(难道是现在的显卡都太快了,绘制自己写的场景用的时间很短),如果大家有什么见解欢迎讨论哈。
相关文章推荐
- opengl离屏渲染(不需要和窗口绑定,仅当作一个可以渲染一张图片的API使用)+ opencv显示
- 一个可以显示图片(包括GIF动画)的ATL控件,以及在RichEdit中如何使用此控件插入图片
- openCV学习笔记(5):使用sprintf函数实现在窗口连续显示同一文件夹下的图片
- OpenCV2.4.10之多个图片在一个窗口显示
- 使用GDI+可以方便的把OpenCV的图像矩阵类型数据显示在MFC的窗口中
- 使用OpenCV 读取图片 ,再用OpenGL显示,图像有错位
- opencv在一个窗口里面显示多张图片
- 【循序渐进地学好OpenCV&4】使用2.0的API显示图片以及OpenCV的自动化内存管理
- 基于OpenCV3实现一个窗口显示若干张图片
- OpenCV3 一个窗口显示多个图片的实现函数
- QT5-控件-QScrollArea-可以用于把一个窗口分割为多个-比如根据图片大小显示滚动条
- OpenCV一个窗口显示多张图片
- OpenCV一个窗口显示多张图片
- 使用 Visual Studio 2008 和 OpenCV 在窗口显示图片或视频
- 一个可以显示图片(包括GIF动画)的ATL控件,以及在RichEdit中如何使用此控件插入图片
- OpenCV入门系列(4):显示一张图片和一个视频
- 如何利用opencv在一个窗口显示多张图片
- OpenCV一个窗口显示多张图片
- opencv2 一个窗口显示多幅图片
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——1.3 用OpenGL ES 2.0显示一张图片(上)