之前一直苦于寻找OpenGL与OpenCV间的数据传输方法,对这两个库运用得不是很熟,在网上找的的方法却是OpenCV往OpenGL传输纹理和数据,即OpenCV把图做出来然后把数据传给OpenGL,让OpenGL来显示。但是我想要的方法是OpenGL往OpenCV传输数据,即OpenGL把图画好之后把图像的像素数据传输给OpenCV作一些处理(如平滑,提取边缘之类的),于是到冒着被墙的危险到国外论坛发帖求助,一哥们说glGetTexImage函数即可,于是去查阅此函数,发现也不过是把数据读入buffer,和glReadPixels函数类似。经过一番搜索,发现把buffer的数据copy到一个IplImage中就行了,具体方法如下:
1. OpenGL往OpenCV传输数据
IplImage* SaveCvImg()
{
/* 获取视口数据 */
GLint viewPort[4] = { 0 };
glGetIntegerv(GL_VIEWPORT, viewPort);
GLubyte* buffer = (GLubyte*)malloc(viewPort[2] * viewPort[3] *
sizeof(GLubyte) * 3);
/* 读取图像缓冲区数据 */
glReadPixels(viewPort[0], viewPort[1], viewPort[2], viewPort[3],
GL_BGR, GL_UNSIGNED_BYTE, buffer);
/* 将数据保存在IplImage中 */
/* 深度为8,通道数为3,24位图 */
IplImage* model2DImg = cvCreateImage(mImgSize, IPL_DEPTH_8U, 3);
/* 复制地址,所以最后不能free(buffer) */
model2DImg->imageData = (char*)buffer;
/* 由于OpenGL与OpenCv读取buffer的方向在y轴上相反,所以作x轴翻转,第二个参数为
* NULL表示作原地翻转.
*/
cvFlip(model2DImg, NULL, 0);
return model2DImg;
}
上面的代码中我直接让model2DImg->imageData的地址等于buffer的地址,如果大家担心指针及内存释放的问题,可以直接使用memcpy:
...
memcpy(model2DImg->imageData, buffer, Width*Heigh*3);
...
free(buffer);
再有就是上面的翻转。由于我之前用的方法是把buffer的数据直接加上一个文件头,以bmp的方式存储,也许读取buffer的方向与OpenCV的方向不一致,主要是y轴方向上的不一致,所以作了一个翻转。
2. OpenCV往OpenGL传数据
这个就比较简单了,直接读取IplImage的三个通道的数据行了,单通道的话就只读取单通道,下面以读取纹理数据为例:
//
// 载入图像纹理数据
void loadTextureToGL(IplImage* img)
{
CvScalar ss;
//accessing the image pixels
for (int i=0;i<height;i++)
{
for (int j=0;j<width;j++)
{
ss=cvGet2D(img,i,j); // ss.val[0] = red, ss.val[1] = green, ss.val[2] = blue
texture[i][j][2] = ss.val[0];
texture[i][j][1] = ss.val[1];
texture[i][j][0] = ss.val[2];
}
}
}
发现了解一下函数库的底层还是比较有用的,从原理入手才能更加灵活地运用!