OpenGL进行简单的通用计算实例

博主作为OpenGL新手,最近要用OpenGL进行并行的数据计算,突然发现这样的资料还是很少的,大部分资料和参考书都是讲用OpenGL进行渲染的。好不容易找到一本书《GPGPU编程技术,从OpenGL、CUDA到OpenCL》,里面对并行处理的发展进行了系统性的介绍,还是很不错的。小白博主很兴奋,看完书中第三章后恍然大悟了很多,就贴出书中代码3-3的例子,实现一番,并用一副图片数据做了实现。

实现环境:Window7 32bit, VS2013+OpenGL3.3+GLEW+GLFW。

OpenGL用来进行通用数据计算的流程如下图,数据从CPU(应用程序)中通过“用绘制来调用”发送到纹理缓存,以纹理映射的方式给到着色器,最后经过片段着色器的计算(GLSL语言)后,再将结果输出到纹理缓存,最后CPU(应用程序)再从纹理缓存中读取结果数据,至此计算完成。

1.书中代码3-3输入一组数据到纹理缓存,然后再从纹理缓存中读取这组数据,代码以及实验结果如下:

数据类型就设置为float,将数据发送至纹理缓存要用这个函数glTexSubImage2D( );

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
using namespace std;
#define WIDTH 2
#define HEIGHT 3
int main(int argc, char** argv)
{
    int nWidth=(int)WIDTH;
    int nHeight=(int)HEIGHT;
    int nSize=(int)nWidth*nHeight;

    //创建输入数据
    float* pfInput=new float[4*nSize];
    float* pfOutput=new float[4*nSize];
    for (int i=0; i<nSize*4; i++)
    {
        pfInput[i]= (float)(i + 1.2345);
    }
    //初始化并设置GLFW
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    //创建GLFW窗口
    GLFWwindow* window = glfwCreateWindow(3, 2, "LearnOpenGL", nullptr, nullptr);
    glfwMakeContextCurrent(window);
    //初始化GLEW
    //glewExperimental = GL_TRUE;
    glewInit();

    //创建FBO并绑定
    GLuint fb;
    glGenFramebuffersEXT(1, &fb);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);

    //创建纹理对象并绑定
    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    //设置纹理参数
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

    //将纹理关联到FBO
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, 0);
    
    //将纹理数据设置为单精度浮点数
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA_FLOAT32_ATI, nWidth, nHeight,0, GL_RGBA, GL_FLOAT, NULL); 
    //将数据传至输入纹理缓存
    //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nWidth, nHeight, 0, GL_RGBA, GL_FLOAT, pfInput);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, nWidth, nHeight, GL_RGBA, GL_FLOAT, pfInput);

    //从输出纹理缓存中读出数据
    glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
    glReadPixels(0,0, nWidth, nHeight, GL_RGBA, GL_FLOAT, pfOutput);

    //打印并检查结果
    bool bCap=true;
    for (int i=0; i<nSize*4; i++)
    {
        cout<<i<<":\t"<<pfInput[i]<<'\t'<<pfOutput[i]<<endl;
        if (pfInput[i]!=pfOutput[i])  bCap=false;
    }

    if (bCap) cout<<"Round trip complete!"<<endl;
    else      cout<<"Round trip failed!" <<endl;

    delete pfInput;
    delete pfOutput;
    glDeleteFramebuffers(1, &fb);
    glDeleteTextures(1, &tex);

    system("pause");
    
    return 0;
}

2.读取一幅图像,写入纹理缓存并从纹理缓存读出,配合OpenCV使用。代码如下(原理差不多):

 1 #include <iostream>
 2 #include <stdlib.h>
 3 #include <stdio.h>
 4 #define GLEW_STATIC
 5 #include <GL/glew.h>
 6 #include <GLFW/glfw3.h>
 7 #include <opencv.hpp>
 8 using namespace std;
 9 using namespace cv;
10 #define WIDTH 2
11 #define HEIGHT 3
12 int main(int argc, char** argv)
13 {
14     //读取图像
15     Mat srcImg=imread("./lena.jpg");
16     Mat dstImg=Mat::zeros(srcImg.size(), srcImg.type());
17 
18     int nWidth=srcImg.cols;
19     int nHeight=srcImg.rows;
20     int nSize=(int)nWidth*nHeight;
21 
22     //BGR转换到RGB空间
23     cvtColor(srcImg, srcImg, CV_BGR2RGB);
24     cvtColor(dstImg, dstImg, CV_BGR2RGB);
25 
26     //获取图像数据指针
27     uchar* puInput=srcImg.data;
28     uchar* puOutput=dstImg.data;
29 
30     //初始化并设置GLFW
31     glfwInit();
32     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
33     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
34     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
35     glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
36     //创建GLFW窗口
37     GLFWwindow* window = glfwCreateWindow(3, 2, "LearnOpenGL", nullptr, nullptr);
38     glfwMakeContextCurrent(window);
39     //初始化GLEW
40     glewExperimental = GL_TRUE;
41     glewInit();
42 
43     //创建FBO并绑定
44     GLuint fb;
45     glGenFramebuffersEXT(1, &fb);
46     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
47 
48     //创建纹理对象并绑定
49     GLuint tex;
50     glGenTextures(1, &tex);
51     glBindTexture(GL_TEXTURE_2D, tex);
52     //设置纹理参数
53     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
54     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
55     //将纹理关联到FBO
56     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
57      
58     //将数据传至输入纹理缓存
59     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, nWidth, nHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, puInput);
60 
61     //从输出纹理缓存中读出数据
62     glReadPixels(0,0, nWidth, nHeight, GL_RGB, GL_UNSIGNED_BYTE, puOutput);
63 
64    //保存输出图像
65     imwrite("./LenaIsBack.jpg", dstImg);
66 
67     glDeleteFramebuffers(1, &fb);
68     glDeleteTextures(1, &tex);
69 
70     system("pause");
71     
72     return 0;
73 }

数据类型要设置为unsigned_byte,将数据送至纹理缓存要用这个函数glTexImage2D();最终保存出来的结果我没有再转换到BGR空间,所以输入的Lena和输出的Lena将会下面这样(仅供参考,哈哈)~:

其实最好设置两个纹理缓存对象,一个用于输入,一个用于输出,把输出的纹理缓存绑定的FBO(帧缓冲对象)。用GLSL语言在着色器中写出需要进行计算的算法就可以实现通用数据的处理了。对了,渲染的窗口还是要建立的,这样OpenGL以为它是在进行渲染到屏幕的操作,其实我们通过帧缓冲和纹理缓冲实现的是通用数据计算的过程。

今天就到这里,我继续去看书了,每天进步一点点点点。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python数据科学

快速入门Matplotlib教程

Matplotlib 可能是 Python 2D-绘图领域使用最广泛的套件。它能让使用者很轻松地将数据图形化,并且提供多样化的输出格式。这里将会探索 matpl...

12410
来自专栏Android点滴积累

Android高效内存2:让图片占用尽可能少的内存

Android高效内存:让图片占用尽可能少的内存 一、让你的图片最小化 1.1 大图小图内存使用情况对比 大图:440 * 336    小图:220 * 16...

315110
来自专栏IT派

开源|人脸检测的C / C ++源代

人脸检测的C/C++源代码,曾发表于 OPENCV 的 MAILING LIST,主要是对OPENCV 3.1 版本发布的代码做了一些速度上的优化,并且解决了内...

42450
来自专栏ACM小冰成长之路

51Nod-1868-彩色树

ACM模版 描述 ? 题解 树型DP,先上官方题解: ? 官方题解说的十分清楚,和我的代码思路也恰好吻合,大体上是针对每种颜色求出不包括该种颜色的路径的点对儿数...

24170
来自专栏和蔼的张星的图像处理专栏

8.SSD目标检测之二:制作自己的训练集

最近秋色甚好,一场大风刮散了雾霾,难得几天的好天气,周末回家在大巴上看着高速两旁夕阳照射下黄澄澄的树叶,晕车好像也好了很多。 特地周六赶回来为了周末去拍点素材...

16540
来自专栏xdecode

Java调用PDFBox打印自定义纸张PDF

打印对象 一份设置为A3纸张, 页面边距为(10, 10, 10, 10)mm的PDF文件. ? PageFormat  默认PDFPrintable无法设置页...

59750
来自专栏CreateAMind

paper:Multi-Level Discovery of Deep Options

10210
来自专栏图形学与OpenGL

3.6.2 编程实例-河南地图绘制

#include <iostream> #include <fstream> #include<vector> #include <GL/glut.h> usi...

12510
来自专栏专知

关于写论文说来简单但做起来难的三条建议

A few years ago, we prepared a series of workshops on writing research papers an...

29550
来自专栏机器之心

资源 | 博士生开源深度学习C++库DLL:快速构建卷积受限玻尔兹曼机

选自baptiste-wicht 机器之心编译 参与:刘晓坤、蒋思源 Baptiste Wicht公布了自己编写的深度学习库DLL1.0,可以通过C++接口使用...

62760

扫码关注云+社区

领取腾讯云代金券