OpenGL视频帧拟合

时间:2018-12-15 16:30:40

标签: c++ opengl sdl kinect sdl-2

我正在一个项目中,我必须以肖像模式在4K屏幕上以640x480的分辨率从摄像机投影数据。

相机是Kinect V1,但我将切换到分辨率更高(1920x1080)的版本2。

我的问题是如何更改要显示的纹理比例以获得正确的结果。 目前,我设法在整个屏幕上显示,但是图像的宽度变平了。理想的做法是保持比例,并在图像的每侧切一个X宽度。

我在OpenGL中使用SDL,这是代码的相关部分:

// window creation
auto window = SDL_CreateWindow("Imagine",
                                   x,
                                   y,
                                   0,
                                   0,
                                   SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_BORDERLESS);

// GL initialization and texture creation
void SdlNuitrackRenderHandler::initTexture(int width, int height)
{
    glEnable(GL_TEXTURE_2D);
    glEnableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
    glOrtho(0, _width, _height, 0, -1.0, 1.0);
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();

    glGenTextures(1, &_textureID);

    width = power2(width);
    height = power2(height);

    if (_textureBuffer != 0)
        delete[] _textureBuffer;

    _textureBuffer = new uint8_t[width * height * 3];
    memset(_textureBuffer, 0, sizeof(uint8_t) * width * height * 3);

    glBindTexture(GL_TEXTURE_2D, _textureID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // Set texture coordinates [0, 1] and vertexes position
    {
        _textureCoords[0] = (float) _width / width;
        _textureCoords[1] = (float) _height / height;
        _textureCoords[2] = (float) _width / width;
        _textureCoords[3] = 0.0;
        _textureCoords[4] = 0.0;
        _textureCoords[5] = 0.0;
        _textureCoords[6] = 0.0;
        _textureCoords[7] = (float) _height / height;

        _vertexes[0] = _width;
        _vertexes[1] = _height;
        _vertexes[2] = _width;
        _vertexes[3] = 0.0;
        _vertexes[4] = 0.0;
        _vertexes[5] = 0.0;
        _vertexes[6] = 0.0;
        _vertexes[7] = _height;
    }

// Texture rendering
// Render prepared background texture
void SdlNuitrackRenderHandler::renderTexture()
{
    glClearColor(1, 1, 1, 1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glEnable(GL_TEXTURE_2D);
    glColor4f(1, 1, 1, 1);

    glBindTexture(GL_TEXTURE_2D, _textureID);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _width, _height, GL_RGB, GL_UNSIGNED_BYTE, _textureBuffer);

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glVertexPointer(2, GL_FLOAT, 0, _vertexes);
    glTexCoordPointer(2, GL_FLOAT, 0, _textureCoords);

    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    glDisable(GL_TEXTURE_2D);
}

1 个答案:

答案 0 :(得分:4)

尽管我同意注释中写的关于过时的OpenGL代码的内容,但这个问题与OpenGL的本质无关。您要在具有不同纵横比的另一个矩形内绘制一个具有正确纵横比的矩形。您只需要知道顶点的放置位置即可。

通常使用TEXTURE_2D纹理目标,除非您计划裁剪输入图像,否则您希望两个方向的纹理坐标均为0-1。曾经有一段时间,纹理的宽度和高度必须是2的幂。在很长一段时间以来,情况并非如此。因此,请删除以下两行:

width = power2(width);
height = power2(height);

所以第一件事就是正确设置它们:

    _textureCoords[0] = 1.0;
    _textureCoords[1] = 1.0;
    _textureCoords[2] = 1.0;
    _textureCoords[3] = 0.0;
    _textureCoords[4] = 0.0;
    _textureCoords[5] = 0.0;
    _textureCoords[6] = 0.0;
    _textureCoords[7] = 1.0;

(因此,该代码很难真正阅读,并且很难维护。您应将纹理坐标(和顶点坐标)设置为struct和{{ 1}}和x的值,这样就很有意义了。目前尚不清楚这是4组2D坐标,分别是(max,max),(max,min),(min,min),(min,最多),但我离题了。

接下来,要弄清楚纹理坐标,您需要知道视频是否要缩放以适合宽度或高度。为此,您可以找出

y

现在按double widthScaleRatio = displayWidth / imageWidth; // <- using this scale will guarantee the width of the new image is the same as the display's width, but might crop the height double heightScaleRatio = displayHeight / imageHeight; // <- using this scale will guarantee the height of the new image is the same as the display's height but might crop the width double scale = 1.0; // If scaling by the widthScaleRatio makes the height too big, use the heightScaleRatio // Otherwise use the widthScaleRatio if (imageHeight * widthScaleRatio > displayHeight) { scale = heightScaleRatio; } else { scale = widthScaleRatio; } 缩放您的宽度和高度:

scale

并基于此设置顶点:

double newWidth  = imageWidth * scale;
double newHeight = imageHeight * scale;

同样的警告也适用于使该代码与纹理坐标一样易于阅读。

编辑:这是一个简单的程序,用于演示其工作原理:

    _vertexes[0] = newWidth;
    _vertexes[1] = newHeight;
    _vertexes[2] = newWidth;
    _vertexes[3] = 0.0;
    _vertexes[4] = 0.0;
    _vertexes[5] = 0.0;
    _vertexes[6] = 0.0;
    _vertexes[7] = newHeight;

运行它,我得到:

  

新尺寸=(2160,1620)