OpenGL读图显示
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);