【问题标题】:opengl - displayed image shearedopengl - 显示的图像剪切
【发布时间】:2019-06-07 12:31:16
【问题描述】:

我正在尝试使用 OpenGL 显示由 Microsoft CImage 库从磁盘读取的图像。

现在可以在窗口中大致看到图像,但显然有问题。图像是灰色的,并且被剪切了。我不知道问题出在哪里,因为每个像素都应该对应_data中的插槽。

OpenGL 图像:

原图:

下面是我的代码:

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

【问题讨论】:

    标签: c++ opengl


    【解决方案1】:

    根据 glDrawPixels 上的this OpenGL doc(强调添加):

    从内存中读取宽度 x 高度像素,从位置数据开始。默认情况下,这些像素取自相邻的内存位置,除了在读取所有宽度像素之后,读取指针前进到下一个四字节边界。四字节行对齐由 glPixelStore 指定,参数为 GL_UNPACK_ALIGNMENT,可以设置为 1、2、4 或 8 个字节。

    请注意,您的颜色被定义为 3 个 GLuint 值 - 只有 3 个字节!每行像素包含3 * 897 = 2691 字节。 2691 之后的下一个 4 的倍数是 2692,因此定义 glDrawPixels 的方式,GL 在每一行之后跳过一个字节。这就是为什么图像被剪切并且它看起来是灰色的原因(如果放大,您会看到它不是灰色的,而是每隔三行都有正确的颜色,并且中间的颜色偏移了 120 度)。

    解决此问题的方法是在调用glDrawPixels 之前调用glPixelStore。改变就够了

    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 你写到数组的 0th 索引时。

    另外,请查看动态内存分配,而不是分配静态大小的数组。这将使您的代码不太容易出现访问冲突,即读取/写入实际上不属于您的内存,从而导致崩溃和其他问题。

    【讨论】:

    • 那一行代码就像魔术一样工作!我尝试使用动态分配的数组来存储这些字节,但是程序崩溃了,所以我使用固定大小来调试剪切问题。我已经编辑了部分代码以使用动态分配。你介意花点时间看看吗?
    • 我尝试在VS中调试代码,但是貌似_data = new GLubyte**[_h];没有成功分配内存,但是不知道为什么...
    • @AccM 您必须执行 GLubyte *_data = new GLubyte[_h * _w * 3]; 以使内存连续 - 然后将 for 循环更改为 _data[3 * ((_h - 1 - y) * _w + x)] = (GLubyte)GetRValue(pixel); 以及 G 和 B 值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-08
    • 2018-04-10
    相关资源
    最近更新 更多