opengl离屏渲染(不需要和窗口绑定,仅当作一个可以渲染一张图片的API使用)+ opencv显示
具体过程参考的是这篇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();
GdiFlush();
mGLRender();
//SaveBmp(hbm,"output.bmp");
clockEnd = clock();
printf("%d\n", clockEnd - clockBegin); clockBegin = clock();
GdiFlush();
mGLRender1();
//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显示的更多相关文章
- 深度剖析OpenGL ES中的多线程和多窗口渲染技术
由 创新网小编 于 星期五, 2014-04-11 14:56 发表 移动设备中的CPU和GPU已经变得很强大,到处都是配备一个或多个高分辨率屏幕的设备,需要使用带有图形驱动器的复杂交互也日益增加.在 ...
- 基于OpenGL编写一个简易的2D渲染框架-01 创建窗口
最近正在学习OpenGL,我认为学习的最快方法就是做一个小项目了. 如果对OpenGL感兴趣的话,这里推荐一个很好的学习网站 https://learnopengl-cn.github.io/ 我用的 ...
- CSharpGL(35)用ViewPort实现类似3DMax那样的把一个场景渲染到4个视口
CSharpGL(35)用ViewPort实现类似3DMax那样的把一个场景渲染到4个视口 开始 像下面这样的四个视口的功能是很常用的,所以我花了几天时间在CSharpGL中集成了这个功能. 在CSh ...
- CSharpGL(34)以从零编写一个KleinBottle渲染器为例学习如何使用CSharpGL
CSharpGL(34)以从零编写一个KleinBottle渲染器为例学习如何使用CSharpGL +BIT祝威+悄悄在此留下版了个权的信息说: 开始 本文用step by step的方式,讲述如何使 ...
- Python pyQt4/pyQt5 学习笔记1(空白窗口,按钮,控件事件,控件提示,窗体显示到屏幕中间,messagebox)
PyQt4是用来编写有图形界面程序(GUI applications)的一个工具包.PyQt4作为一个Python模块来使用,它有440个类和超过6000种函数和方法.同时它也是一个可以在几乎所有主流 ...
- HashTab---Windows资源管理器的文件属性窗口中添加了一个叫做”文件校验”的标签
HashTab 是一个优秀的 Windows 外壳扩展程序,它在 Windows 资源管理器的文件属性窗口中添加了一个叫做”文件校验”的标签.该标签可以帮助你方便地计算文件的 MD5.SHA1 与 C ...
- WPF中使用WindowChrome美化窗口过程中的一个小问题
WPF中使用WindowChrome美化窗口,在园子里有几篇不错的文章,我也是参考练习过程中发现的问题,并记录下来. 在看过几篇教程后,给出的窗口很多出现这样一个问题,如果设置了窗口标题栏的高度大于默 ...
- ASP.NET#在设计窗口上添加了一个SqlDataSource控件后,没有显示出来?
在设计窗口上添加了一个SqlDataSource控件后,没有显示出来,但后台代码是有的 处理的办法:菜单栏->视图->可视辅助->ASP.NET非可视控件 (我用的是VS2012)
- python调用大漠插件教程03窗口绑定实例
怎样利用注册好的大漠对象来绑定窗口? 直接上代码,根据代码分析 from win32com.client import Dispatch import os from win32gui import ...
随机推荐
- 【百度地图API】如何进行地址解析与反地址解析?——模糊地址能搜索到精确地理信息!
原文:[百度地图API]如何进行地址解析与反地址解析?--模糊地址能搜索到精确地理信息! 摘要: 什么是地址解析? 什么是反地址解析? 如何运用地址解析,和反地址解析? 可以同时运用地址解析,和反地址 ...
- 深入理解C指针之四:指针和数组
原文:深入理解C指针之四:指针和数组 数组是C内建的基本数据结构,数组表示法和指针表示法紧密关联.一种常见的错误认识是数组和指针完全可以互换,尽管数组名字有时可以当做指针来用,但数组的名字不是指针.数 ...
- 备份IIS httpd.ini 重写规则,兼容大部分版本号IISserver
IISserver已经非常少,差点儿要退出市场了.nginx成为市场的主流. 备份一个httpd.ini,全部内容例如以下: [ISAPI_Rewrite] # 3600 = 1 hour Cache ...
- Socket 学习(一)
本次项目增加的引用using System.Net; using System.Net.Sockets; using System.Threading; TextBox.CheckForIllegal ...
- MVC验证02-自定义验证规则、邮件验证
原文:MVC验证02-自定义验证规则.邮件验证 本文体验MVC自定义验证特性,来实现对邮件的验证.对于刚写完的自定义验证特性,起初只能支持后端验证.如果要让前端jquery支持,还必须对jquery的 ...
- 关于WIN32.EXE变态木马下载器的解决办法
一.WIN32.EXE的来源:http://fdghewrtewrtyrew.biz/adv/130/win32.exe 二.运行后的表现:此WIN32.EXE通过80和8080端口访问若干个IP,若 ...
- Android学习小Demo(21)ListView的联动选择
在日常的App开发中,尤其是在开发生活服务的应用上,非常多时候,我们会须要联动地展现省市区的数据等,需求大概例如以下: 1)展现全部省份 2)当点击某省份的时候,在二级菜单上展现此省份以下所属的城市列 ...
- C++在struct与class差异
在C++中,既能够用structkeyword进行类的定义,也能够用classkeyword进行类的定义,那么这两者究竟有什么差别呢? 唯一的一点差别是:struct和class的默认訪问权限不一样. ...
- MySql处理数据库和表
show databases; mysql> show databases; mysql> create database db_test; Query OK, 1 row affecte ...
- unix域套接字UDP网络编程
unix域套接字UDP网络编程,服务器如下面: #include <stdio.h> #include <stdlib.h> #include <string.h> ...