opengl - показанное изображение - PullRequest
0 голосов
/ 13 января 2019

Я пытаюсь использовать OpenGL для отображения изображений, считанных с диска библиотекой Microsoft CImage.

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

OpenGL изображение: opengl image

Исходное изображение: original image

Ниже мой код:

int _w = 300;
int _h = 300;
GLubyte ***_data;

void init() {
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0, _w, 0.0, _h);
}

void display() {
    glClear(GL_COLOR_BUFFER_BIT);
    glRasterPos2i(0, 0);
    glDrawPixels(_w, _h, GL_RGB,
        GL_UNSIGNED_BYTE, _data);
    glFlush();
}

int main(int argc, char** argv) {
    CImage img_handler;
    img_handler.Load(_T("bg.jpg"));
    _w = img_handler.GetWidth();
    _h = img_handler.GetHeight();

    COLORREF pixel;
    _data = new GLubyte**[_h];

    for (int y = 0; y < _h; y++) {
        _data[_h-y-1] = new GLubyte*[_w];
        for (int x = 0; x < _w; x++) {
            pixel = img_handler.GetPixel(x, y);

            _data[_h-y-1][x] = new GLubyte[3];
            _data[_h-y][x][0] = (GLubyte)GetRValue(pixel);
            _data[_h-y][x][1] = (GLubyte)GetGValue(pixel);
            _data[_h-y][x][2] = (GLubyte)GetBValue(pixel);
        }
    }

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH/*enable depth buffer*/);
    glutInitWindowSize(_w, _h);
    glutCreateWindow("test");

    init();
    glutDisplayFunc(display);
    glutMainLoop();

    return 0;
}

1 Ответ

0 голосов
/ 13 января 2019

Согласно этому документу OpenGL на glDrawPixels (выделение добавлено):

ширина x высота пикселей считываются из памяти, начиная с данных о местоположении. По умолчанию эти пиксели взяты из смежных областей памяти, за исключением того, что после считывания всех пикселей ширины, указатель чтения продвигается к следующей четырехбайтовой границе . Четырехбайтовое выравнивание строк определяется glPixelStore с аргументом GL_UNPACK_ALIGNMENT, и оно может быть установлено в один, два, четыре или восемь байтов.

Обратите внимание, что ваши цвета определены как значения 3 GLuint - всего 3 байта! Каждая строка пикселей содержит 3 * 897 = 2691 байтов. Следующее значение, кратное 4 после 2691, равно 2692, и, таким образом, определяется glDrawPixels, GL пропускает один байт после каждой строки. Вот почему изображение обрезается и почему оно выглядит серым (если вы увеличите масштаб, вы увидите, что оно не серое, а каждая третья строка имеет правильные цвета, а промежуточные оттенки смещены на 120 градусов).

Способ исправить это - сделать glPixelStore вызов перед вызовом glDrawPixels. Достаточно изменить

glDrawPixels(_w, _h, GL_RGB,
    GL_UNSIGNED_BYTE, _data);

до

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glDrawPixels(_w, _h, GL_RGB,
    GL_UNSIGNED_BYTE, _data);

Кроме того, код внутри вашего цикла for неверен. _h-y должно быть _h-y-1, чтобы при y=0 вы не записывали вне границ массива и аналогично, когда y=_h-1, вы записываете в 0-й индекс массива.

Кроме того, обратите внимание на динамическое выделение памяти вместо выделения массива статического размера. Это сделает ваш код менее подверженным нарушениям доступа, т.е. чтению / записи памяти, которая на самом деле вам не принадлежит, что приводит к сбоям и другим проблемам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...