添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

OpenGL读图显示

6 年前 · 来自专栏 让电脑看到这个美丽的世界

OpenGL显示图像有大体有两种形式:读取图像内存和纹理贴图。其中读取图像内存比较好理解也比较简单,但是处理灵活性不如纹理贴图。由于OpenGL没有直接读取jpg、bmp、png等图像格式的函数,需借助其他工具将图像文件读取转化为内存信息。相对C++的文件读取函数,我更习惯使用简便的OpenCV图像读取

首先设定一些全局变量方便操作:

//OpenCV读取图像
Mat I = imread("img.jpg");
//设置长宽
int width = I.cols;
int height = I.rows;
//设置图像指针
GLubyte* pixels;

其中图像长宽需要设定OpenGL窗口大小,图像指针需要在读取、转换、释放等多处使用



使用OpenCV读取图像数据并存入指针的函数:

void get_img()
	//OpenCV显示
	imshow("OpenCV", I);
	//设置指针长度
	int pixellength = width*height * 3;
	//开辟指针空间
	pixels = new GLubyte[pixellength];
	//图像指针复制
	memcpy(pixels, I.data, pixellength*sizeof(char));

其中指针复制函数为

void *memcpy(void *dest, const void *src, size_t n);

该函数为C++函数,作用是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中,因此其参数设定为

void *dest:目标指针,文中为图像指针pixels

const void *src:源内存地址起始位置,Mat型图像起始指针表示为Mat.data

size_t n:内存长度,文中为像素个数*3通道(int pixellength = width*height * 3),再乘以数据种类所占空间(sizeof(char)),最终形式为pixellength*sizeof(char)



OpenGL显示事件display:

void display()
	// 清除屏幕
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//像素读图
	glDrawPixels(width, height, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
	//双缓存交换缓存以显示图像
	glutSwapBuffers();

其中主要函数为

void glDrawPixels (GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);

参数GLsizei width, GLsizei height:图像宽高

参数GLenum format:图像格式,代码中为BGR格式(GL_BGR_EXT,OpenCV图像颜色顺序默认为BGR)

参数GLenum type:内存数据种类,代码中为unsigned char(GL_UNSIGNED_BYTE,OpenCV图像像素数据种类默认为unsigned char)

参数const GLvoid *pixels:待显示图像数据,代码中为图像指针pixels



main函数大体不变,只需在开始加上获取图像指针函数get_img(),在最后加上指针释放语句,并且注意将OpenGL尺寸设置为图像长宽即可

void main(int argc, char** argv)
	//获取图像指针函数
	get_img();
	//初始化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();
	//OpenGL循环结束后释放图像指针内存
	free(pixels);

运行显示结果:

左边为OpenCV显示结果,右边为OpenGL显示结果,发现OpenGL显示上下颠倒,这是由于OpenCV与OpenGL图像内存顺序不同导致的:OpenCV原点坐标位于图像左上角,而OpenGL原点坐标位于左下角。若想要OpenGL正常显示,须将OpenCV图像进行颠倒处理后再读取内存。OpenCV颠倒图像函数为

void flip(InputArray src, OutputArray dst, int flipCode);

参数InputArray src, OutputArray dst分别为源图像和目标图像,代码中不需要保留翻转前图像结果,因此两图像均为I

参数int flipCode:图像翻转方式,等于0表示竖直方向翻转,大于0表示水平方向翻转,小于0表示同时在竖直水平两个方向翻转,代码中需要竖直方向反转,因此设置为0

分别显示OpenCV反转前后的图像及OpenGL图像:

当然在设置OpenGL窗口时,不一定设置为与图像长宽相同,程序会自动对图像进行压缩或者拉伸。比如依旧设为400*400窗口,显示结果为:

完整代码:

#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;
void get_img()
	//OpenCV显示
	imshow("OpenCV", I);
	//图像翻转
	flip(I, I, 0);
	imshow("OpenCV flip", I);
	//设置指针长度
	int pixellength = width*height * 3;
	//开辟指针空间
	pixels = new GLubyte[pixellength];
	//图像指针复制
	memcpy(pixels, I.data, pixellength*sizeof(char));
void display()
	// 清除屏幕
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//像素读图
	glDrawPixels(width, height, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
	//双缓存交换缓存以显示图像
	glutSwapBuffers();
void main(int argc, char** argv)
	//获取图像指针函数
	get_img();
	//初始化GL
	glutInit(&argc, argv);
	//设置显示参数(双缓存,RGB格式)
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	//设置窗口尺寸:width*height
	glutInitWindowSize(width, height);
	//设置窗口尺寸为固定值:400*400
	//glutInitWindowSize(400, 400);
	//设置窗口位置:在屏幕左上角像素值(100,100)处
	glutInitWindowPosition(100, 100);
	//设置窗口名称
	glutCreateWindow("OpenGL");
	//显示函数,display事件需要自行编写
	glutDisplayFunc(display);