200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 深度学习(三十五)异构计算GLSL学习笔记(1)

深度学习(三十五)异构计算GLSL学习笔记(1)

时间:2018-08-02 18:05:58

相关推荐

深度学习(三十五)异构计算GLSL学习笔记(1)

异构计算GLSL学习笔记(1)

原文地址:/hjimce/article/details/51475644

作者:hjimce

最近开始学习深度学习的一些gpu编程,大体学了cuda后,感觉要在手机上跑深度学习,没有nvidia显卡,不能加速。所以只能老老实实的学习opengl的shader编程,进行gpu通用计算加速,总的感觉shader编程比cuda编程难,还好自己之前研究生的时候,经常用opengl的一些API函数,对opengl比较了解。对于每一种语言,最简单的学习程序就是:hello world,下面记录一下shader编程最简单的例子,利用gpu加速实现彩色图像转灰度图像。大体包含五个步骤:

1、初始化环境、创建shader程序等;

2、根据需求,编写片元着色器的纹理图像处理代码;

3、从cpu传入数据(利用uniform类型变量,传数据到shader中,如果是图片可以直接采用纹理传入);

4、设置渲染模型、纹理坐标,绘制矩形,进行渲染计算;

5、取回图片处理后的数据;

一、opengl与shader环境初始化、编译链接

(1)初始化环境

//1、初始化环境glutInit(&argc, argv);//glutInitWindowSize(512,512); //glutInitWindowPosition(100,100); glutCreateWindow("GLEW Test"); glewExperimental = GL_TRUE;glewInit();if (!glewIsSupported("GL_VERSION_4_0")) {std::cerr << "Failed to initialize GLEW with OpenGL 4.0!" << std::endl;return EXIT_FAILURE;}

(2)创建链接、编译shader程序

//2、读取、创建shader程序,编译连接等auto program_id = ShaderProgram("shader/gl_texture.vert", "shader/gl_texture.frag");glUseProgram(program_id);

ShaerProgram函数的代码如下:

GLuint ShaderProgram(const std::string &vertex_shader_file, const std::string &fragment_shader_file) {// 创建shader程序auto vertex_shader_id = glCreateShader(GL_VERTEX_SHADER);auto fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER);auto result = GL_FALSE;auto info_length = 0;// 读取shader源码std::ifstream vertex_shader_stream(vertex_shader_file);std::string vertex_shader_code((std::istreambuf_iterator<char>(vertex_shader_stream)), std::istreambuf_iterator<char>());std::ifstream fragment_shader_stream(fragment_shader_file);std::string fragment_shader_code((std::istreambuf_iterator<char>(fragment_shader_stream)), std::istreambuf_iterator<char>());// 编译顶点shader代码std::cout << "Compiling Vertex Shader ..." << std::endl;auto vertex_shader_code_ptr = vertex_shader_code.c_str();glShaderSource(vertex_shader_id, 1, &vertex_shader_code_ptr, NULL);glCompileShader(vertex_shader_id);// Check vertex shader logglGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result);if (result == GL_FALSE) {glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_length);std::string vertex_shader_log((unsigned int)info_length, ' ');glGetShaderInfoLog(vertex_shader_id, info_length, NULL, &vertex_shader_log[0]);std::cout << vertex_shader_log << std::endl;}// 编译片元着色器代码std::cout << "Compiling Fragment Shader ..." << std::endl;auto fragment_shader_code_ptr = fragment_shader_code.c_str();glShaderSource(fragment_shader_id, 1, &fragment_shader_code_ptr, NULL);glCompileShader(fragment_shader_id);// Check fragment shader logglGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result);if (result == GL_FALSE) {glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_length);std::string fragment_shader_log((unsigned long)info_length, ' ');glGetShaderInfoLog(fragment_shader_id, info_length, NULL, &fragment_shader_log[0]);std::cout << fragment_shader_log << std::endl;}// 创建链接程序std::cout << "Linking Shader Program ..." << std::endl;auto program_id = glCreateProgram();glAttachShader(program_id, vertex_shader_id);glAttachShader(program_id, fragment_shader_id);glBindFragDataLocation(program_id, 0, "FragmentColor");glLinkProgram(program_id);//打印编译信息,如果编译错误,就可以看见错误信息了glGetProgramiv(program_id, GL_LINK_STATUS, &result);if (result == GL_FALSE) {glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_length);std::string program_log((unsigned long)info_length, ' ');glGetProgramInfoLog(program_id, info_length, NULL, &program_log[0]);std::cout << program_log << std::endl;}glDeleteShader(vertex_shader_id);glDeleteShader(fragment_shader_id);return program_id;}

二、编写shader程序

上面在创建shader程序的时候,需要shader源码,对于图像处理来说,顶点着色器我们一般不需要用到,主要是利用片元着色器进行图像处理的相关计算。

(1)顶点着色器源码文件gl_texture.vert的代码如下:

#version 400//顶点着色器输入in vec2 Position;in vec2 TexCoord;//顶点着色器的输出,这个变量会进入片元着色器out vec2 fragTexCoord;void main() {// Copy the input to the fragment shaderfragTexCoord =TexCoord.xy;// Calculate the final position on screen// Note the visible portion of the screen is in <-1,1> range for x and y coordinatesgl_Position = vec4(Position.x,Position.y, 0.0, 1.0);}

(2)片元着色器gl_texture.frag

#version 400// 需要注意opengl纹理输入uniform sampler2D Texture;// 来自顶点着色器in vec2 fragTexCoord;//输出 out vec4 FragmentColor;void main() {// Lookup the color in Texture on coordinates given by fragTexCoordvec3 pColor = texture(Texture, fragTexCoord.xy).rgb;//转换成灰度图像float gray=pColor.r*0.2126+ 0.7152* pColor.g + 0.0722*pColor.b;FragmentColor =vec4(gray, gray,gray, 1.0);}

三、opencv读取图片、输入纹理、启用纹理等

//3、设置纹理相关参数、或者输入shader计算所需要的数据auto texture_id = LoadImage("2.jpg", height_width, height_width);//读入一张图片,转成纹理格式,把并把图片数据拷贝到opengl纹理单元。auto texture_attrib = glGetUniformLocation(program_id, "Texture");//找到shader程序中,变量名为Texture,类型为uniform的变量索引glUniform1i(texture_attrib,0);glActiveTexture(GL_TEXTURE0 + 0);//启用第一个纹理,并绑定纹理数据glBindTexture(GL_TEXTURE_2D, texture_id);

LoadImage函数代码如下:

GLuint LoadImage(const std::string &image_file, unsigned int width, unsigned int height){// Create new texture objectGLuint texture_id;glGenTextures(1, &texture_id);glBindTexture(GL_TEXTURE_2D, texture_id);// Set mipmapsglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);cv::Mat texture_cv=cv::imread(image_file);if (texture_cv.empty()){return -1;}else {glTexImage2D(GL_TEXTURE_2D, 0, 3, texture_cv.cols, texture_cv.rows, 0, GL_BGR, GL_UNSIGNED_BYTE, texture_cv.data);return texture_id;} }

四、绘制渲染、计算

通过绘制一个矩形,该矩形的纹理刚好就是我们的图片,这样就可以实现gpu图片处理了:

//4、设置渲染相关参数(矩形4个顶点、及其对应的纹理坐标)InitializeGeometry(program_id);//5、绘制、渲染glClearColor(0.f,0.f,0.f,1.f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

InitializeGeometry函数:

void InitializeGeometry(GLuint program_id) {// Generate a vertex array objectGLuint vao;glGenVertexArrays(1, &vao);glBindVertexArray(vao);// 顶点缓存GLfloat tempv[12] = {1.0f,1.0f,-1.0f,1.0f,1.0f,-1.0f,-1.0f, -1.0f}; //二维顶点坐标,分别为矩形的四个顶点坐标std::vector<GLfloat> vertex_buffer(tempv , tempv+12); // Generate a vertex buffer objectGLuint vbo;glGenBuffers(1, &vbo);glBindBuffer(GL_ARRAY_BUFFER, vbo);glBufferData(GL_ARRAY_BUFFER, vertex_buffer.size() * sizeof(GLfloat), vertex_buffer.data(), GL_STATIC_DRAW);// Setup vertex array lookupauto position_attrib = glGetAttribLocation(program_id, "Position");glVertexAttribPointer(position_attrib, 2, GL_FLOAT, GL_FALSE, 0, 0);glEnableVertexAttribArray(position_attrib);// Generate another vertex buffer object for texture coordinatesGLfloat temptex[8] = {1.0f,0.0f,0.0f,0.0f,1.0f,1.0f,0.0f, 1.0f}; std::vector<GLfloat> texcoord_buffer(temptex,temptex+8);GLuint tbo;glGenBuffers(1, &tbo);glBindBuffer(GL_ARRAY_BUFFER, tbo);glBufferData(GL_ARRAY_BUFFER, texcoord_buffer.size() * sizeof(GLfloat), texcoord_buffer.data(), GL_STATIC_DRAW);auto texcoord_attrib = glGetAttribLocation(program_id, "TexCoord");glVertexAttribPointer(texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 0, 0);glEnableVertexAttribArray(texcoord_attrib);glBindVertexArray(vao);}

这个需要设置好顶点坐标和纹理坐标。

五、取出数据到opencv中

渲染完毕后,我们就要把图像处理的结果保存回opencv的cv::Mat上,然后看看处理结果

void show(int height=height_width,int width=height_width){cv::Mat img=cv::Mat::zeros(height, width, CV_8UC3);//use fast 4-byte alignment (default anyway) if possible//glPixelStorei(GL_PACK_ALIGNMENT, (img.step & 3) ? 1 : 4);//set length of one complete row in destination data (doesn't need to equal img.cols)//glPixelStorei(GL_PACK_ROW_LENGTH, img.step/img.elemSize());glReadPixels(0, 0, img.cols, img.rows, GL_BGR, GL_UNSIGNED_BYTE, img.data);//opencv存储为BGR顺序cv::flip(img, img, 0);//需要翻转cv::imshow("result",img);cv::waitKey(0);}

最后贴一下主程序流程的完整代码:

#include "stdafx.h"#include <stdlib.h>#include "include/glew.h"#include "include/GLUT.H"#include <opencv2/opencv.hpp>#include "shader.h"#define height_width 512void show(int height=height_width,int width=height_width){cv::Mat img=cv::Mat::zeros(height, width, CV_8UC3);//use fast 4-byte alignment (default anyway) if possible//glPixelStorei(GL_PACK_ALIGNMENT, (img.step & 3) ? 1 : 4);//set length of one complete row in destination data (doesn't need to equal img.cols)//glPixelStorei(GL_PACK_ROW_LENGTH, img.step/img.elemSize());glReadPixels(0, 0, img.cols, img.rows, GL_BGR, GL_UNSIGNED_BYTE, img.data);//opencv存储为BGR顺序cv::flip(img, img, 0);//需要翻转cv::imshow("result",img);cv::waitKey(0);}int main( int argc, char** argv ){//1、初始化环境glutInit(&argc, argv);//glutInitWindowSize(512,512); //glutInitWindowPosition(100,100); glutCreateWindow("GLEW Test"); glewExperimental = GL_TRUE;glewInit();if (!glewIsSupported("GL_VERSION_4_0")) {std::cerr << "Failed to initialize GLEW with OpenGL 4.0!" << std::endl;return EXIT_FAILURE;}//2、读取、创建shader程序,编译连接等auto program_id = ShaderProgram("shader/gl_texture.vert", "shader/gl_texture.frag");glUseProgram(program_id);//3、设置纹理相关参数、或者输入shader计算所需要的数据auto texture_id = LoadImage("2.jpg", height_width, height_width);//读入一张图片,转成纹理格式,把并把图片数据拷贝到opengl纹理单元。auto texture_attrib = glGetUniformLocation(program_id, "Texture");//找到shader程序中,变量名为Texture,类型为uniform的变量索引glUniform1i(texture_attrib,0);glActiveTexture(GL_TEXTURE0 + 0);//启用第一个纹理,并绑定纹理数据glBindTexture(GL_TEXTURE_2D, texture_id);//4、设置渲染相关参数(矩形4个顶点、及其对应的纹理坐标)InitializeGeometry(program_id);//5、绘制、渲染glClearColor(0.f,0.f,0.f,1.f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);//6、取回数据到opencv,并显示结果show();//return 0;}

结果:

原图 处理结果

****************************转载请保留原文地址、作者等信息********************************

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。