OpenGL 绘制效果保存成图片

分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net

opengl中有一个非常有用的函数:glReadPixels(),可以读取各种缓冲区(深度、颜色,etc)的数值。要将opengl的绘制场景保存成图片,也需要使用这个函数。

一个简单的例子见如下的c程序。按键盘上的“C”键,可以将读取的图像缓冲区数据存储成tmpcolor.txt。

#include "windows.h"
#include <GL/glut.h>
#include <GL/GLAUX.H>
#include <iostream>
using namespace std;

//
typedef GLbyte* bytePt;

int winWidth = 400;
int winHeight = 400;
int arrLen = winWidth * winHeight * 3;
GLbyte* colorArr = new GLbyte[ arrLen ];

void saveColorData(bytePt& _pt, string& _str) {
FILE* pFile = NULL;
pFile = fopen(_str.c_str(), "wt");
if(!pFile) { fprintf(stderr, "error \n"); exit(-1); }

for(int i=0; i<winWidth * winHeight * 3; i ++) {
if(colorArr[i] == -1) { colorArr[i] = 255; }
}

for(int i=0; i<winWidth * winHeight * 3; i ++) {
fprintf(pFile, "%d\n", colorArr[i]);
}
fclose(pFile);
printf("color data saved! \n");
}

void init() {
glClearColor(0.5, 0.5, 0.5, 0.0);
glShadeModel(GL_SMOOTH);
}

void display() {
glClear(GL_COLOR_BUFFER_BIT);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, 1.0, 0.1, 500.0);
glMatrixMode(GL_MODELVIEW);

glColor3f(1.0, 0.0, 0.0);
glBegin(GL_TRIANGLES);
glVertex3f(0.0, 25.0, 0.0);
glVertex3f(-25.0, -25.0, 0.0);
glVertex3f(25.0, -25.0, 0.0);
glEnd();

glFlush();
}

void keyboard(unsigned char key, int x , int y) {
GLint viewPort[4] = {0};
switch(key) {
case ‘c‘:
case ‘C‘:
glGetIntegerv(GL_VIEWPORT, viewPort);
glReadPixels(viewPort[0], viewPort[1], viewPort[2], viewPort[3], GL_RGB, GL_UNSIGNED_BYTE, colorArr);
printf("color data read !\n");
saveColorData(colorArr, (string)"tmpcolor.txt");
default:
break;
}
}

int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(200, 200);
glutInitWindowSize(400, 400);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutMainLoop();

delete [] colorArr;

return 0;
}

 

tmpcolor.txt 中将每个像素的颜色按R、G、B顺序存放成了一个向量,即(R,G,B,R,G,B,...)。而且,读取缓冲区时的坐标原点是窗口坐标系的坐标原点(图片左下角);因此,可以在matlab中通过调整得到原来的图片:

function test
    a = load(‘tmpcolor.txt‘);

    pos = find(a == -1);
    a(pos) = 255;

    r = a(1:3:end);
    g = a(2:3:end);
    b = a(3:3:end);
    img = zeros(400,400,3);
    img(:,:,1) = reshape(r,[400,400]);
    img(:,:,2) = reshape(g,[400,400]);
    img(:,:,3) = reshape(b,[400,400]);
    img = uint8(img);

    tmpR = zeros(400,400);  tmpR = img(:,:,1);
    tmpG = zeros(400,400);  tmpG = img(:,:,2);
    tmpB = zeros(400,400);  tmpB = img(:,:,3);

    for i=1:1:400
        img(i,:,1) = tmpR(:,400-i+1);
        img(i,:,2) = tmpG(:,400-i+1);
        img(i,:,3) = tmpB(:,400-i+1);
    end

    figure;
    imshow(img);
end

 

当然,读到数据后,可以直接使用openCV等工具方便地存储图片。一段对应的opencv代码为:

void saveColorData2img(bytePt& _pt, string& _str) {
cv::Mat img;
vector<cv::Mat> imgPlanes;
img.create(winHeight, winWidth, CV_8UC3);
cv::split(img, imgPlanes);

for(int i = 0; i < winHeight; i ++) {
UCHAR* plane0Ptr = imgPlanes[0].ptr<UCHAR>(i);
UCHAR* plane1Ptr = imgPlanes[1].ptr<UCHAR>(i);
UCHAR* plane2Ptr = imgPlanes[2].ptr<UCHAR>(i);
for(int j = 0; j < winWidth; j ++) {
int k = 3 * (i * winWidth + j);
plane2Ptr[j] = _pt[k];
plane1Ptr[j] = _pt[k+1];
plane0Ptr[j] = _pt[k+2];
}
}
cv::merge(imgPlanes, img);
cv::flip(img, img ,0); // !!!
cv::imwrite(_str.c_str(), img);

printf("opencv save opengl img done! \n");
}

 

需要注意的是,如果想要把集成在MFC中的openGL场景转存成图片,因为MFC中的像素格式只支持RGBA和颜色索引,所以 glReadPixels 中需要使用 GL_RGBA 作为参数。对应写了一个C++类,可供参考:

class glGrabber {
public:
glGrabber();
~glGrabber();

void glGrab();
void saveColorData2Img(string& _str);
private:
GLbyte* colorArr;
GLint viewPort[4];
int winWidth;
int winHeight;
};

//
glGrabber::glGrabber() {
colorArr = NULL;
}

//
glGrabber::~glGrabber() {
if(colorArr!=NULL) { delete [] colorArr; colorArr = NULL; }
}

//
void glGrabber::glGrab() {
glGetIntegerv(GL_VIEWPORT, viewPort);
if(colorArr != NULL) { delete [] colorArr; colorArr = NULL; }
winWidth = viewPort[2];
winHeight = viewPort[3];

colorArr = new GLbyte[ winWidth * winHeight * 4 ]; // MFC的像素格式只支持RGBA

glReadPixels(viewPort[0], viewPort[1], viewPort[2], viewPort[3], GL_RGBA, GL_UNSIGNED_BYTE, colorArr); // RGBA

printf("x: %d, y: %d, window width: %d, window height: %d \n", viewPort[0], viewPort[1], viewPort[2], viewPort[3]);
printf("color data read! \n");
}

//
void glGrabber::saveColorData2Img(string& _str) {
cv::Mat img;
vector<cv::Mat> imgPlanes;
img.create(winHeight, winWidth, CV_8UC3);
cv::split(img, imgPlanes);

for(int i = 0; i < winHeight; i ++) {
UCHAR* plane0Ptr = imgPlanes[0].ptr<UCHAR>(i);
UCHAR* plane1Ptr = imgPlanes[1].ptr<UCHAR>(i);
UCHAR* plane2Ptr = imgPlanes[2].ptr<UCHAR>(i);
for(int j = 0; j < winWidth; j ++) {
int k = 4 * (i * winWidth + j); // RGBA
plane2Ptr[j] = colorArr[k];
plane1Ptr[j] = colorArr[k+1];
plane0Ptr[j] = colorArr[k+2];
}
}

cv::merge(imgPlanes, img);
cv::flip(img, img ,0); // !!!
cv::namedWindow("openglGrab");
cv::imshow("openglGrab", img);
cv::waitKey();

//cv::imwrite(_str.c_str(), img);

printf("opencv save opengl img done! \n");
}

http://blog.sina.com.cn/s/blog_8e6bfecf0100xd6r.html

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net

原文地址:https://www.cnblogs.com/sownchz/p/10500021.html

时间: 2024-11-05 21:37:46

OpenGL 绘制效果保存成图片的相关文章

OpenGL中的深度、深度缓存、深度测试及保存成图片

1.深度 所谓深度,就是在openGL坐标系中,像素点Z坐标距离摄像机的距离.摄像机可能放在坐标系的任何位置,那么,就不能简单的说Z数值越大或越小,就是越靠近摄像机. 2.深度缓冲区 深度缓冲区原理就是把一个距离观察平面(近裁剪面)的深度值(或距离)与窗口中的每个像素相关联.      首先,使用glClear(GL_DEPTH_BUFFER_BIT),把所有像素的深度值设置为最大值(一般是远裁剪面).      然后,在场景中以任意次序绘制所有物体.硬件或者软件所执行的图形计算把每一个绘制表面

如何把Excel中的单元格等对象保存成图片

对于Excel中的很多对象,比如单元格(Cell),图形(shape),图表(chart)等等,有时需要将它们保存成一张图片.就像截图一样. 最近做一个Excel相关的项目,项目中遇到一个很变态的需求, 需要对Excel中的一些对象进行拍图,比如,对一个单元格设置一些颜色之后拍图,或者对一个图表,报表拍成图片.经过比较曲折的经历,终于还是完成了.拿出来分享一下. 要做Excel,首先当然是查看Excel的com对象模型.地址在这里: http://msdn.microsoft.com/en-us

Canvas图保存成图片或pdf

Canvas画好的图片虽然可以通过toDataURL()转成二进制流的字符串格式,图片稍大一点就无法发送了,当然如果需求简单的话,可以在页面上加一个image元素,将转成的流直接赋给image的src就可以显示图片了. 但是大部分的时候我们还希望弹出保存框,保存图片到我们自己想要的路径下,或者添加一些统计和分析的信息到pdf中一起保存成一个pdf文件,这就需要在后台处理了,两种方式:后台新建一个Web Browser加载当前的页面,然后将获得到的图片流的信息再发送到前台弹出保存的对话框,后台发送

MindMapper导图如何保存成图片

我们可以将MindMapper思维导图保存为多种格式的文件,具有对多样性,从文档到图片这些我们常用的格式都能够自由转换.下面我们就一起去看看如何如何将MindMapper导图保存为图片. 当我们在MindMapper思维导图中绘制好导图,像要将之保存为图片时,点击[文件]中的保存/发送,然后跳转至文件格式板块中的更改文件格式. 我们可以看到都多种保存为图片的形式,我们一般常用第一项保存为图片文件形式. 点击后会跳出保存文件框,选择保存MindMapper文件的位置,选择好后点击保存,这时系统会跳

android脚步---将layout和其输出一起保存成图片

public void convertViewToBitmap(View view) { //View view = getLayoutInflater().inflate(R.layout.test_layout, null); view.setDrawingCacheEnabled(true); view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0

InputStream流保存成图片文件

public void saveBit(InputStream inStream) throws IOException{ ByteArrayOutputStream outStream = new ByteArrayOutputStream(); //创建一个Buffer字符串 byte[] buffer = new byte[1024]; //每次读取的字符串长度,如果为-1,代表全部读取完毕 int len = 0; //使用一个输入流从buffer里把数据读取出来 while( (len

php 加载字体 并保存成图片

[php] view plaincopy // Set the content-type header("Content-type: image/png"); // Create the image $im = imagecreatetruecolor(400, 100); // Create some colors $white = imagecolorallocate($im, 255, 255, 255); $grey = imagecolorallocate($im, 128,

C# 整个网页保存成图片

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.Secu

c# VSTO 将word 里面的图表保存成图片

private void button1_Click(object sender, RibbonControlEventArgs e) { Document doc = Globals.ThisAddIn.Application.ActiveDocument; Paragraphs pp= doc.Content.Paragraphs; Form1 form = new Form1(); form.Show(); Tables tablelist= doc.Tables; Table table