glReadPixels - изображение выглядит размытым - PullRequest
1 голос
/ 27 июля 2011

Я хочу сделать изображение, отрисованное мной, в openGL. Я использую glReadPixels и затем сохраняю изображение с помощью CImg. К сожалению, результат неправильный. Увидеть ниже. Изображение слева правильное. Я захватил это с GadWin PrintScreen. Изображение справа неверно. Я создал его с помощью glReadPixels и CImg:

enter image description here enter image description here

Я провел много веб-исследований о том, что может быть не так, но у меня нет возможности продолжить. Вот код захвата изображения:

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);
}

Вот где я вызываю метод снимка:

void display(void) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        drawIndividual(0);
        snapshot();
        glutSwapBuffers();
    }

Следуя комментарию, я взял битовую глубину и распечатал на консоль. Вот результаты:

redbits=8
greenbits=8
bluebits=8
depthbits=24

Ответы [ 2 ]

5 голосов
/ 27 июля 2011

Вы явно получаете изображение из кадрового буфера, но длина строки кажется отключенной. Вы устанавливаете выравнивание упаковки (хорошо), но есть более настраиваемые параметры:

  • GL_PACK_ROW_LENGTH
  • GL_PACK_SKIP_PIXELS
  • GL_PACK_SKIP_ROWS

установите их в 0 для плотной упаковки. Также glFinish () после glReadPixels () является излишним. glReadPixels не работает асинхронно - он возвращается только после того, как прочитанные данные были скопированы в целевой буфер (или в случае записи в PBO, выборка данных из PBO будет ожидать завершения операции).

2 голосов
/ 01 августа 2011

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 для этого. После запуска этой программы этот код создает объект изображения:

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

И, насколько я могу судить, мне не нужно устанавливать какие-либо параметры упаковки. Вот код, который я использую для захвата пикселей из цели рендеринга OpenGL:

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);
...