我想用glReadPixels()从动画中获取每个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.
发布于 2012-02-01 23:52:45
首先,我们为要直接读入的数据创建一个空的(或单一化的) cv::Mat
。这可以在启动时完成一次,但另一方面,当图像已经具有匹配的大小和类型时,cv::Mat::create
的成本并不高。类型视您的需要而定,通常类似于24位彩色图像的CV_8UC3
。
cv::Mat img(height, width, CV_8UC3);
或
img.create(height, width, CV_8UC3);
然后,您必须考虑到cv::Mat
不需要连续地存储图像行。在每一行的末尾可能有一个小的填充值,以使行4字节对齐(或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());
接下来,矩阵的类型会影响glReadPixels
的格式和类型参数。如果您想要彩色图像,您必须记住,OpenCV通常以BGR顺序存储颜色值,因此您需要使用GL_BGR(A)
(它是在OpenGL 1.2中添加的)而不是GL_RGB(A)
。对于一个分量图像,使用GL_LUMINANCE
(对各个颜色分量求和)或GL_RED
,GL_GREEN
,...(获取单个组件)。因此,对于我们的CV_8UC3
镜像,将其直接读入cv::Mat
的最后一个调用将是:
glReadPixels(0, 0, img.cols, img.rows, GL_BGR, GL_UNSIGNED_BYTE, img.data);
最后,OpenCV从上到下存储图像。因此,您可能需要在获得它们之后翻转它们,或者首先在OpenGL中渲染它们翻转(这可以通过调整投影矩阵来完成,但在这种情况下要注意三角形方向)。要垂直翻转cv::Mat
,可以使用cv::flip
cv::flip(img, flipped, 0);
因此,请记住OpenCV:
发布于 2013-03-28 20:25:48
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;
https://stackoverflow.com/questions/9097756
复制相似问题