Opengl glReadPixels-图像看起来抖动
我希望捕获我在openGL中渲染的图像。我使用glReadPixels,然后用CImg保存图像。不幸的是,结果是错误的。见下文。左边的图像是正确的。我用GadWin PrintScreen捕捉到了它。右边的图像不正确。我用glReadPixels和CImg创建了它: 我已经在网上做了很多关于什么可能是错误的研究,但是我已经找不到途径去追求了。在此代码捕获图像:Opengl glReadPixels-图像看起来抖动,opengl,glreadpixels,cimg,Opengl,Glreadpixels,Cimg,我希望捕获我在openGL中渲染的图像。我使用glReadPixels,然后用CImg保存图像。不幸的是,结果是错误的。见下文。左边的图像是正确的。我用GadWin PrintScreen捕捉到了它。右边的图像不正确。我用glReadPixels和CImg创建了它: 我已经在网上做了很多关于什么可能是错误的研究,但是我已经找不到途径去追求了。在此代码捕获图像: void snapshot() { int width = glutGet(GLUT_WINDOW_WIDTH);
void snapshot() {
int width = glutGet(GLUT_WINDOW_WIDTH);
int height = glutGet(GLUT_WINDOW_HEIGHT);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
int bytes = width*height*3; //Color space is RGB
GLubyte *buffer = (GLubyte *)malloc(bytes);
glFinish();
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
glFinish();
CImg<GLubyte> img(buffer,width,height,1,3,false);
img.save("ScreenShot.ppm");
exit(0);
}
在一条评论之后,我抓取了位深度并打印到控制台上。结果如下:
redbits=8
greenbits=8
bluebits=8
depthbits=24
很明显,您是从帧缓冲区中获取图像的,但行长度似乎不正确。您将填料对齐设置为良好,但还有更多可设置的参数: 总包包装行长度 GL\u PACK\u SKIP\u像素 总帐\打包\跳过\行
将其设置为0,以确保紧密包装。此外,glReadPixels之后的glFinish也是超级像素。glReadPixels不异步工作–它仅在读取的数据复制到目标缓冲区后返回,或者在写入PBO的情况下,从PBO获取数据将等待操作完成。您显然是从帧缓冲区获取图像,但行长度似乎不正确。您将填料对齐设置为良好,但还有更多可设置的参数: 总包包装行长度 GL\u PACK\u SKIP\u像素 总帐\打包\跳过\行
将其设置为0,以确保紧密包装。此外,glReadPixels之后的glFinish也是超级像素。glReadPixels不异步工作–它仅在读取数据复制到目标缓冲区后返回,或者在写入PBO的情况下,从PBO获取数据将等待操作完成。CImg不会交错其颜色。也就是说,3个红色、绿色和蓝色像素将线性存储为: R1,R2,R3,…,G1,G2,G3,…,B1,B2,B3 但是,OpenGL的glReadPixel和glDrawPixel需要如下交叉颜色组件: R1、G1、B1、R2、G2、B2 此外,OpenGL将原点0,0放在图像的左下角。CImg在原点位于图像左上角的位置使用更多的方法 下面是我编写的一个例程,它将交错的颜色转换为CImg的面向通道的格式
void convertToNonInterleaved(int w, int h, unsigned char* tangled, unsigned char* untangled) {
//Take string in format R1 G1 B1 R2 G2 B2... and re-write it
//in the format format R1 R2 G1 G2 B1 B2...
//Assume 8 bit values for red, green and blue color channels.
//Assume there are no other channels
//tangled is a pointer to the input string and untangled
//is a pointer to the output string. This method assumes that
//memory has already been allocated for the output string.
int numPixels = w*h;
int numColors = 3;
for(int i=0; i<numPixels; ++i) {
int indexIntoInterleavedTuple = numColors*i;
//Red
untangled[i] = tangled[indexIntoInterleavedTuple];
//Green
untangled[numPixels+i] = tangled[indexIntoInterleavedTuple+1];
//Blue
untangled[2*numPixels+i] = tangled[indexIntoInterleavedTuple+2];
}
}
CImg不交错其颜色。也就是说,3个红色、绿色和蓝色像素将线性存储为: R1,R2,R3,…,G1,G2,G3,…,B1,B2,B3 但是,OpenGL的glReadPixel和glDrawPixel需要如下交叉颜色组件: R1、G1、B1、R2、G2、B2 此外,OpenGL将原点0,0放在图像的左下角。CImg在原点位于图像左上角的位置使用更多的方法 下面是我编写的一个例程,它将交错的颜色转换为CImg的面向通道的格式
void convertToNonInterleaved(int w, int h, unsigned char* tangled, unsigned char* untangled) {
//Take string in format R1 G1 B1 R2 G2 B2... and re-write it
//in the format format R1 R2 G1 G2 B1 B2...
//Assume 8 bit values for red, green and blue color channels.
//Assume there are no other channels
//tangled is a pointer to the input string and untangled
//is a pointer to the output string. This method assumes that
//memory has already been allocated for the output string.
int numPixels = w*h;
int numColors = 3;
for(int i=0; i<numPixels; ++i) {
int indexIntoInterleavedTuple = numColors*i;
//Red
untangled[i] = tangled[indexIntoInterleavedTuple];
//Green
untangled[numPixels+i] = tangled[indexIntoInterleavedTuple+1];
//Blue
untangled[2*numPixels+i] = tangled[indexIntoInterleavedTuple+2];
}
}
是否确定在绘图代码中使用GL_RGB像素绘图?windoqw是双缓冲的?您应该使用ReadBuffer设置您正在读取的缓冲区。它是双缓冲的,并且我已经在启动例程中将颜色空间初始化为RBG:glutInitDisplayModeGLUT|U double | GLUT|RGB;这看起来很像是一个错误的像素深度类型问题-类似于读取565数据并将其渲染为888。什么是CImg及其参数的含义是什么?您确定在绘图代码中使用GL_RGB像素绘图吗?windoqw是双缓冲的?您应该使用ReadBuffer设置您正在读取的缓冲区。它是双缓冲的,并且我已经在启动例程中将颜色空间初始化为RBG:glutInitDisplayModeGLUT|U double | GLUT|RGB;这看起来很像是一个错误的像素深度类型问题——比如读取565数据并将其渲染为888。什么是CImg及其参数的含义?谢谢DatenWalf。我将包参数设置为0。我还删除了多余的glFinish调用。输出图像也一样。它看起来仍然和问题中的一样。CImg会有错吗?或者你认为glReadPixel调用是问题所在?@ahoffer:是的,CImg可能是罪魁祸首。我并没有首先注意到它,但您正在使用模板实例化它,但您读取的是无符号字节。但是我不知道CImg,所以这可能是原因,也可能不是原因。试着换成CImg。谢谢。我修正了我的代码,但忘了更新StackOverflow。今天我遇到了一位同事,他告诉我不要偷懒,要建立一个良好的调试环境。我将返回并使用glDrawPixels渲染像素缓冲区中的内容,以便实时比较图像。如果这样做有效,那么我知道我使用了错误的CImg参数。我还将继续渲染单个三角形或正方形。@ahoffer:为了调试的目的,最好是在黑色背景上渲染一条1px宽的垂直白线。这样做会告诉你出了什么问题。从技术上讲,这是通过处理链发送一个脉冲,给你一个脉冲响应。你期望一个身份映射,如果冲动没有改变,一切都匹配。然而,如果脉冲
e变化,这些变化告诉你,你面临的是什么样的错误。谢谢datenwolf。我将包参数设置为0。我还删除了多余的glFinish调用。输出图像也一样。它看起来仍然和问题中的一样。CImg会有错吗?或者你认为glReadPixel调用是问题所在?@ahoffer:是的,CImg可能是罪魁祸首。我并没有首先注意到它,但您正在使用模板实例化它,但您读取的是无符号字节。但是我不知道CImg,所以这可能是原因,也可能不是原因。试着换成CImg。谢谢。我修正了我的代码,但忘了更新StackOverflow。今天我遇到了一位同事,他告诉我不要偷懒,要建立一个良好的调试环境。我将返回并使用glDrawPixels渲染像素缓冲区中的内容,以便实时比较图像。如果这样做有效,那么我知道我使用了错误的CImg参数。我还将继续渲染单个三角形或正方形。@ahoffer:为了调试的目的,最好是在黑色背景上渲染一条1px宽的垂直白线。这样做会告诉你出了什么问题。从技术上讲,这是通过处理链发送一个脉冲,给你一个脉冲响应。你期望一个身份映射,如果冲动没有改变,一切都匹配。如果脉搏发生了变化,这些变化会告诉你,你正面临着什么样的错误。
unsigned char* p = (unsigned char *)malloc(bytes);
convertToNonInterleaved(width, height, buffer, p);
CImg<unsigned char> img(p, width, height,1,3);
free(p);
img.mirror('y');
CImgDisplay main_disp(img,"Snapshot");
while (!main_disp.is_closed() ) {
main_disp.wait();
}
bytes = width*height*3; //Color space is RGB
if(buffer)
free(buffer);
buffer = (GLubyte *)malloc(bytes);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);