Я пытаюсь отобразить два изображения размером 256x256 с типом данных ushort. Один должен быть в оттенках серого, а другой в RGB. Однако оба отображаются как черные квадраты. Я считаю, что ошибка кроется где-то в моем определении текстуры openGL, но я не уверен.
Вот моя минимальная версия кода.
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
//init glfw, window, glad, imgui
glfwInit();
const char* glsl_version = "#version 330 core";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(600, 400, "test", NULL, NULL);
glfwMakeContextCurrent(window);
gladLoadGL();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
ImGui::CreateContext();
ImGui::StyleColorsDark();
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init(glsl_version);
//define image data
ushort value;
Mat_<ushort> grey = Mat_<ushort>(256, 256);
Mat_<Vec3w> rgb = Mat_<Vec3w>(256, 256);
for (int i = 0; i < grey.rows; i++)
for (int j = 0; j < grey.cols; j++)
{
value = (i + j) / 256.0 * USHRT_MAX;
grey.at<ushort>(i, j) = value;
rgb.at<Vec3w>(i, j) = Vec3w(value, value, value);
}
//create textures
GLuint greyID;
GLuint rgbID;
glGenTextures(1, &greyID);
glBindTexture(GL_TEXTURE_2D, greyID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16, 256, 256, 0, GL_RED, GL_UNSIGNED_SHORT, grey.data);
glGenTextures(1, &rgbID);
glBindTexture(GL_TEXTURE_2D, rgbID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16UI, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT, rgb.data);
while (!(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS))
{
glfwPollEvents();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::Begin("Images");
ImGui::Image((void*)(intptr_t)greyID, ImVec2(256, 256));
ImGui::SameLine();
ImGui::Image((void*)(intptr_t)rgbID, ImVec2(256, 256));
ImGui::End();
ImGui::Render();
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
}
ImGui::DestroyContext();
glfwDestroyWindow(window);
glfwTerminate();
return 1;
}
Вот результат:
@LHLaurini Что именно вы подразумеваете под «вы все еще используете OpenCV 2»?
@DanMašek Я имею в виду, что OpenCV 2.x к этому моменту уже ~ 5 лет. Усложняет компиляцию на некоторых системах.
Я использовал glGetError()
после каждого вызова создания текстур и не получил никаких проблем, за исключением второго glTexImage2D
. Возвращает ошибку 1282
.
@LHLaurini Я понимаю, но как вы пришли к выводу, что эту версию использует OP? Я не вижу никаких указаний на это нигде в посте (но, может быть, я что-то пропустил?). Если вы делаете это предположение на основе директивы include, то это неверно — даже месячная версия 4.7.0 по-прежнему использует opencv2
для заголовков...
@DanMašek Ты прав.
@Lilmothiit Хм, это странно. 1282
есть GL_INVALID_OPERATION
, и ни одна из проблем в документах не кажется актуальной.
@LHLaurini В других дискуссиях по подобным вопросам, похоже, упоминается, что документация Khronos может быть устаревшей или неполной. Я не уверен.
Я обнаружил одну несвязанную проблему с моим кодом: установка значений (i + j) / 256.0 * USHRT_MAX
превышает предел USHRT_MAX для половины изображения. Хотел написать (i + j) / 512.0 * USHRT_MAX
. Однако его изменение не решает проблему.
Разве GL_RGB
во втором вызове glTexImage2D
не должен быть вместо GL_RGB_INTEGER
? В документации сказано, что «GL_INVALID_OPERATION генерируется, если комбинация internalFormat, формата и типа не является одной из приведенных выше таблиц». и эта комбинация, которую вы используете, отсутствует в вышеупомянутой таблице, насколько я вижу... Хотя, возможно, я смотрю на неправильную версию документов:/
@DanMašek Вы частично правы. GL_RGB_INTEGER
приводит к полному исчезновению моего блока Image
, так как мой тип данных короткий. Я думаю, GL_RGB16
или GL_RGB16UI
было бы правильно вместо этого? Однако установка любого из них по-прежнему не решает исходную проблему, но, по крайней мере, черный квадрат отображается.
@Lilmothiit вам нужно GL_RGB16
для внутреннего формата и GL_RGB
для формата данных.
@YakovGalka извините, я пробовал, но все равно не работает :(
В вашем коде две проблемы.
Во-первых, как обсуждалось в комментариях, в вашем случае вы, вероятно, захотите использовать GL_RGB16
вместо GL_RGB16UI
. Это позаботится об ошибке текстуры.
Вторая проблема заключается в том, что вам нужно добавить
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
после glBindTexture
.
Причина в том, что минимизирующий фильтр по умолчанию — GL_NEAREST_MIPMAP_LINEAR
, но вы указали только первый уровень мип-карты (поэтому текстура неполная). Кроме того, вы также можете уменьшить максимальный уровень. Взгляните на вики для получения дополнительной информации.
После исправления обеих этих проблем ваша программа работает:
Вы также можете рассчитать свой цвет как
value = min((i + j) / 256.0), 1.0) * USHRT_MAX;
Большое спасибо!! Что касается расчета value
, я уже прокомментировал, что хотел написать value = (i + j) / 512.0 * USHRT_MAX;
.
@Lilmothiit Ах, да, я пропустил это. Разделение на 510.0
было бы немного лучше, так как это максимальное значение (255+255
).
Чтобы добавить к ответу LHLaurini, я также допустил ошибку во втором звонке glTexImage2d
. Здесь внутренний формат GL_RGB16UI
неверен, так как мой тип данных short
. Этот формат должен быть GL_RGB16
:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT, rgb.data);
Я не вижу явных проблем. Попробуйте проверить наличие ошибок с помощью
glGetError
послеglTexImage2D
. Вы также можете попробовать использовать инструмент отладки, такой как RenderDoc или APITrace. С другой стороны, есть ли причина, по которой вы все еще используете OpenCV 2?