将数据从glReadPixels()转换为OpenCV :: Mat

我想从glReadPixels()的animation中获取每个OpenGL帧,并将数据转换为OpenCV :: Mat 。 我知道glReadPixels()从左到右从下到上的行获取数据。 另一方面,OpenCV以不同的方式存储数据。

有没有人知道任何图书馆或任何教程/例子,可以帮助我将数据从glReadPixels转换为C + +中的OpenCV:Mat

概要

OpenGL frame -----------------------> CV::Mat Data from left to right, Data from left to right, bottom to top. top to bottom. 

首先我们为我们的数据直接读取数据创build一个空的(或单元化的) cv::Mat 。 这可以在启动时完成一次,但另一方面,当图像已经具有匹配的大小和types时, cv::Mat::create并不真的花费太多。 types取决于你的需求,通常它就像CV_8UC3的24位彩色图像。

 cv::Mat img(height, width, CV_8UC3); 

要么

 img.create(height, width, CV_8UC3); 

那么你必须考虑到cv::Mat不必连续地存储图像行。 在每行末尾可能会有一个小的填充值,以使行4字节alignment(或8?)。 所以你需要弄乱像素存储模式:

 //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()); 

接下来,matrix的types会影响glReadPixels的格式和types参数。 如果你需要彩色图像,你必须记住OpenCV通常以BGR顺序存储颜色值,所以你需要使用GL_BGR(A) (这是OpenGL 1.2中添加的)而不是GL_RGB(A) 。 对于一个组件,使用GL_LUMINANCE (它将各个颜色分量相加)或者GL_REDGL_GREEN ,…(获得一个单独的组件)。 因此,对于我们的CV_8UC3图像来说,直接读入cv::Mat的最终调用将是:

 glReadPixels(0, 0, img.cols, img.rows, GL_BGR, GL_UNSIGNED_BYTE, img.data); 

最后,OpenCV从上到下存储图像。 所以你可能需要在获取它们之后翻转它们,或者在OpenGL中翻转它们(这可以通过调整投影matrix来完成,但是在这种情况下请注意三angular形的方向)。 要垂直翻转一个cv::Mat ,你可以使用cv::flip

 cv::flip(img, flipped, 0); 

所以要记住OpenCV:

  • 存储从上到下,从左到右的图像
  • 以BGR顺序存储彩色图像
  • 可能不会存储图像行紧密包装
 unsigned char* getPixelData( int x1, int y1, int x2, int y2 ) { int y_low, y_hi; int x_low, x_hi; if ( y1 < y2 ) { y_low = y1; y_hi = y2; } else { y_low = y2; y_hi = y1; } if ( x1 < x2 ) { x_low = x1; x_hi = x2; } else { x_low = x2; x_hi = x1; } while ( glGetError() != GL_NO_ERROR ) { ; } glReadBuffer( GL_BACK_LEFT ); glDisable( GL_TEXTURE_2D ); glPixelStorei( GL_PACK_ALIGNMENT, 1 ); unsigned char *data = new unsigned char[ ( x_hi - x_low + 1 ) * ( y_hi - y_low + 1 ) * 3 ]; glReadPixels( x_low, y_low, x_hi-x_low+1, y_hi-y_low+1, GL_RGB, GL_UNSIGNED_BYTE, data ); if ( glGetError() != GL_NO_ERROR ) { delete[] data; return 0; } else { return data; } } 

使用:

 CvSize size = cvSize( 320, 240 ); unsigned char *pixel_buf = getPixelData( 0, 0, size.width - 1, size.height - 1 ); if ( pixel_buf == 0 ) return 0; IplImage *result = cvCreateImage( size, IPL_DEPTH_8U, 3 ); memcpy( result->imageData, pixel_buf, size.width * size.height * 3 ); delete[] pixel_buf;