OpenGL纹理显示
OpenGL除了读取图像内存显示图像之外还有另一种图像显示方式:纹理显示。纹理显示相比于读内存直接显示稍复杂,读内存显示只需要glDrawPixels ()函数即可实现,纹理显示则需要设置更多参数,当然纹理显示的好处是让显示变得更灵活。由于涉及读取图片,依旧使用OpenCV图像读取
首先依旧是全局变量
//OpenCV读取图像
Mat I = imread("img.jpg");
//设置长宽
int width = I.cols;
int height = I.rows;
//设置图像指针
GLubyte* pixels;
使用OpenCV读取图像数据后将图像数据转化为纹理信息函数
GLuint load_texture()
//OpenGL纹理用整型数表示
GLuint texture_ID;
//获取图像指针
int pixellength = width*height * 3;
pixels = new GLubyte[pixellength];
memcpy(pixels, I.data, pixellength*sizeof(char));
imshow("OpenCV", I);
//将texture_ID设置为2D纹理信息
glGenTextures(1, &texture_ID);
glBindTexture(GL_TEXTURE_2D, texture_ID);
//纹理放大缩小使用线性插值
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//将图像内存用作纹理信息
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
free(pixels);
return texture_ID;
OpenGL的纹理是用无符号int型数索引来存储的。比如有10个纹理,可以分别用0-9这十个数字表示,类似于指针或数组。上面的函数做的就是把某个纹理赋给某个数字,让该数字表示该纹理,因此函数返回值是unsigned int型
其核心函数为
void glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
参数GLenum target:目标纹理格式,代码中为2D纹理,故使用GL_TEXTURE_2D
参数GLint level:纹理细致级别,代码中为图像转换为纹理,故设为0;若为mipmap纹理,即可设置级别
参数GLint internalformat:OpenGL显示图像颜色格式,代码中为普通rgb格式,故使用GL_RGB
参数GLsizei width, GLsizei height:图像宽高
参数GLint border:纹理单元的边框,包含边框取值为1,不包含边框取值为0,整体效果差别不大
参数GLenum format:图像格式,代码中为BGR格式(GL_BGR_EXT,OpenCV图像颜色顺序默认为BGR)
参数GLenum type:内存数据种类,代码中为unsigned char(GL_UNSIGNED_BYTE,OpenCV图像像素数据种类默认为unsigned char)
参数const GLvoid *pixels:待显示图像数据,代码中为图像指针pixels
另外,函数glTexParameteri()用来设置各种纹理参数,文章最后再做解释
OpenGL显示事件display:
void display()
// 清除屏幕
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//获取纹理对象
GLuint image = load_texture();
//重新设置OpenGL窗口:原点位置为左上角,x轴从左到右,y轴从上到下,坐标值与像素坐标值相同
glViewport(0, 0, (GLsizei)width, (GLsizei)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, height, 0);
//显示纹理
glEnable(GL_TEXTURE_2D); //允许使用纹理
glBindTexture(GL_TEXTURE_2D, image); //选择纹理对象
glBegin(GL_POLYGON); //设置为多边形纹理贴图方式并开始贴图
glTexCoord2f(0.0f, 0.0f); glVertex2f(0, 0); //纹理左上角对应窗口左上角
glTexCoord2f(0.0f, 1.0f); glVertex2f(0, height); //纹理左下角对应窗口左下角
glTexCoord2f(1.0f, 1.0f); glVertex2f(width, height); //纹理右下角对应窗口右下角
glTexCoord2f(1.0f, 0.0f); glVertex2f(width, 0); //纹理右上角对应窗口右上角
glEnd(); //结束贴图
glDisable(GL_TEXTURE_2D); //禁止使用纹理
//双缓存交换缓存以显示图像
glutSwapBuffers();
纹理显示的套路和简单显示的方法相似,注释已经写的很清楚了。值得一提的是
glViewport(0, 0, (GLsizei)width, (GLsizei)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, height, 0);
这四行代码可以将OpenGL与OpenCV画布坐标进行统一
另外再次强调,OpenGL是状态机,所有状态有开始一定要有结束,否则会出现问题。纹理显示也一样,应用纹理前glEnable(GL_TEXTURE_2D),结束应用后glDisable(GL_TEXTURE_2D);显示贴图前glBegin(GL_POLYGON),显示结束后glEnd()。每个状态开始结束均一一对应
main函数:
void main(int argc, char** argv)
//初始化GL
glutInit(&argc, argv);
//设置显示参数(双缓存,RGB格式)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
//设置窗口尺寸:width*height
glutInitWindowSize(width, height);
//设置窗口位置:在屏幕左上角像素值(100,100)处
glutInitWindowPosition(100, 100);
//设置窗口名称
glutCreateWindow("OpenGL");
//显示函数,display事件需要自行编写
glutDisplayFunc(display);
//重复循环GLUT事件
glutMainLoop();
运行显示结果:
该结果和读图显示结果相同。我们可以修改显示事件display使贴图变得灵活多样,比如:
三角形:
glBegin(GL_POLYGON);
glTexCoord2f(0.0f, 0.0f); glVertex2f(0, 0);
glTexCoord2f(0.0f, 1.0f); glVertex2f(0, height);
glTexCoord2f(1.0f, 1.0f); glVertex2f(width, height);
glEnd();
多边形:
glBegin(GL_POLYGON);
glTexCoord2f(0.33f, 0.0f); glVertex2f(width/3, 0);
glTexCoord2f(0.67f, 0.0f); glVertex2f(width*2/3, 0);
glTexCoord2f(1.0f, 0.5f); glVertex2f(width, height/2);
glTexCoord2f(0.5f, 1.0f); glVertex2f(width/2, height);
glTexCoord2f(0.0f, 0.5f); glVertex2f(0, height/2);
glEnd();
任意变换:
glBegin(GL_POLYGON);
glTexCoord2f(0.0f, 0.0f); glVertex2f(width/4, height/4);
glTexCoord2f(0.0f, 1.0f); glVertex2f(0, height);
glTexCoord2f(1.0f, 1.0f); glVertex2f(width, height*2/3);
glTexCoord2f(1.0f, 0.0f); glVertex2f(width*4/5, 50);
glEnd();
注意多边形的顶点要按顺时针或逆时针顺序输入,不然贴图会出错
最后简单介绍一下用来设置各种纹理参数函数glTexParameteri()
//纹理放大缩小使用线性插值(可设置插值方法)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//纹理水平竖直方向外扩使用重复贴图(与边缘像素贴图二选一)
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//纹理水平竖直方向外扩使用边缘像素贴图(与重复贴图二选一)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
所谓重复贴图:
完整代码:
#include "glut.h"
#include <opencv.hpp>
using namespace cv;
//OpenCV读取图像
Mat I = imread("img.jpg");
//设置长宽
int width = I.cols;
int height = I.rows;
//设置图像指针
GLubyte* pixels;
GLuint load_texture()
//OpenGL纹理用整型数表示
GLuint texture_ID;
//获取图像指针
int pixellength = width*height * 3;
pixels = new GLubyte[pixellength];
memcpy(pixels, I.data, pixellength*sizeof(char));
imshow("OpenCV", I);
//将texture_ID设置为2D纹理信息
glGenTextures(1, &texture_ID);
glBindTexture(GL_TEXTURE_2D, texture_ID);
//纹理放大缩小使用线性插值
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//纹理水平竖直方向外扩使用重复贴图
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//纹理水平竖直方向外扩使用边缘像素贴图(与重复贴图二选一)
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
//将图像内存用作纹理信息
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
free(pixels);
return texture_ID;
void display()
// 清除屏幕
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//获取纹理对象
GLuint image = load_texture();
//重新设置OpenGL窗口:原点位置为左上角,x轴从左到右,y轴从上到下,坐标值与像素坐标值相同
glViewport(0, 0, (GLsizei)width, (GLsizei)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, height, 0);
//显示纹理
glEnable(GL_TEXTURE_2D); //允许使用纹理
glBindTexture(GL_TEXTURE_2D, image); //选择纹理对象
//原始完全填充四边形
glBegin(GL_POLYGON); //设置为多边形纹理贴图方式并开始贴图
glTexCoord2f(0.0f, 0.0f); glVertex2f(0, 0); //纹理左上角对应窗口左上角
glTexCoord2f(0.0f, 1.0f); glVertex2f(0, height); //纹理左下角对应窗口左下角
glTexCoord2f(1.0f, 1.0f); glVertex2f(width, height); //纹理右下角对应窗口右下角
glTexCoord2f(1.0f, 0.0f); glVertex2f(width, 0); //纹理右上角对应窗口右上角
glEnd(); //结束贴图
//三角形
/*glBegin(GL_POLYGON);
glTexCoord2f(0.0f, 0.0f); glVertex2f(0, 0);
glTexCoord2f(0.0f, 1.0f); glVertex2f(0, height);
glTexCoord2f(1.0f, 1.0f); glVertex2f(width, height);
glEnd();*/
//多边形
/*glBegin(GL_POLYGON);
glTexCoord2f(0.33f, 0.0f); glVertex2f(width/3, 0);
glTexCoord2f(0.67f, 0.0f); glVertex2f(width*2/3, 0);
glTexCoord2f(1.0f, 0.5f); glVertex2f(width, height/2);
glTexCoord2f(0.5f, 1.0f); glVertex2f(width/2, height);
glTexCoord2f(0.0f, 0.5f); glVertex2f(0, height/2);
glEnd();*/
//任意变换
/*glBegin(GL_POLYGON);
glTexCoord2f(0.0f, 0.0f); glVertex2f(width/4, height/4);
glTexCoord2f(0.0f, 1.0f); glVertex2f(0, height);
glTexCoord2f(1.0f, 1.0f); glVertex2f(width, height*2/3);
glTexCoord2f(1.0f, 0.0f); glVertex2f(width*4/5, 50);
glEnd();*/
//边缘贴图效果
/*glBegin(GL_POLYGON);
glTexCoord2f(0.0f, 0.0f); glVertex2f(0, 0);
glTexCoord2f(0.0f, 2.0f); glVertex2f(0, height);
glTexCoord2f(2.0f, 2.0f); glVertex2f(width, height);
glTexCoord2f(2.0f, 0.0f); glVertex2f(width, 0);
glEnd();*/
glDisable(GL_TEXTURE_2D); //禁止使用纹理
//双缓存交换缓存以显示图像
glutSwapBuffers();
void main(int argc, char** argv)
//初始化GL
glutInit(&argc, argv);
//设置显示参数(双缓存,RGB格式)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
//设置窗口尺寸:width*height
glutInitWindowSize(width, height);
//设置窗口位置:在屏幕左上角像素值(100,100)处
glutInitWindowPosition(100, 100);
//设置窗口名称
glutCreateWindow("OpenGL");
//显示函数,display事件需要自行编写