Подгонка видеокарт OpenGL - PullRequest
0 голосов
/ 15 декабря 2018

Я работаю над проектом, в котором мне нужно проецировать данные с камеры с разрешением 640x480 на экран 4K в портретном режиме.

Камера - Kinect V1, но я переключусь на версию2 с лучшим разрешением (1920x1080).

Мой вопрос заключается в том, как изменить масштаб отображаемой текстуры, чтобы получить правильный результат.На данный момент мне удалось отобразить на весь экран, но изображение сглаживается по ширине.Идеально было бы сохранить пропорциональность и сократить ширину X с каждой стороны изображения.

Я использую SDL с OpenGL, вот соответствующая часть кода:

// 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 голосов
/ 15 декабря 2018

Хотя я согласен с тем, что было написано в комментариях об этом устаревшем коде OpenGL, проблема не имеет ничего общего с OpenGL по своей сути.Вы хотите нарисовать 1 прямоугольник с правильным соотношением сторон внутри другого прямоугольника с другим соотношением сторон.Вам просто нужно знать, где разместить вершины.

Как правило, с целью текстуры TEXTURE_2D вы хотите, чтобы ваши координаты текстуры были 0-1 в обоих направлениях, если вы не планируете обрезать входное изображение.Было время, когда текстуры должны были иметь ширину и высоту, которые были степенью 2. Это было не так в течение очень долгого времени.Итак, удалите эти 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 со значениями x и y, так что это имеет смысл. Сейчас не очевидно, что это 4 набора 2Dкоординаты (max, max), (max, min), (min, min), (min, max). Но я отвлекся.)

Далее, чтобы выяснить координаты текстуры, вам нужнознать, будет ли видео масштабироваться в соответствии с шириной или высотой.Для этого вы можете вычислить

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;

То же самое относится и к тому, чтобы сделать этот код более легким для чтения, как и с координатами текстуры.

РЕДАКТИРОВАТЬ: Вот простая программа, чтобы показать, как она работает:

int main(){
    double  displayWidth    = 2160;
    double  displayHeight   = 4096;
    double  imageWidth  =  640;
    double  imageHeight = 480;
    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;
    }

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

    std::cout << "New size = (" << newWidth << ", " << newHeight  << ")\n";
}

Когда я запускаю его, я получаю:

Новый размер = (2160, 1620)

...