Построение графиков с помощью glVertex2i () показывает артефакты при масштабировании с помощью glScaled () - PullRequest
1 голос
/ 14 мая 2019

Я использую OpenGL для построения гистограммы изображения RGB.Поскольку это гистограмма 8-битного изображения, мой набор данных содержит точки данных от нуля до 255.

Если я строю гистограмму без использования glScaled (), тогда график строится, как и ожидалось, но, конечно,не заполнять выделенную область (ширина которой является переменной, постоянная высоты).Однако, когда я использую glScaled (), график показывает странные артефакты.

См. Следующие изображения, чтобы увидеть пример проблемы:

Histogram without glScale

На изображении выше гистограмма представлена ​​в видепостроено с 256 точками данных без масштабирования с помощью glScaled ().

Histogram plot with glScale

Same as above but with a larger scale

Два изображения выше показывают гистограмму в виде графика с 256 точками данных И масштабируются с помощью glScaled ().Странные артефакты очевидны (недостающие данные?).Обратите внимание, что третья гистограмма имеет немного другую форму из-за изменения уровня освещенности.

Вот соответствующая часть моего кода инициализации OpenGL:

glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

glOrtho(0.0f, width, height, 0.0f, 0.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

// If this line is removed then the graph plots correctly
// m_scale_factor = width / 256
glScaled(m_scale_factor, 1.0, 1.0);

glClear(GL_COLOR_BUFFER_BIT);

А вотсоответствующая часть кода моего сюжета:

glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);

glBegin(GL_LINE_STRIP);
for (int n = 0; n < m_histogram_X; n++)
{
    glColor4ub(255, 0, 0, 255);
    glVertex2i(n, m_Hist_Channel_R[n]);
    glVertex2i(n, GRAPH_HEIGHT);

    glColor4ub(0, 255, 0, 255);
    glVertex2i(n, m_Hist_Channel_G[n]);
    glVertex2i(n, GRAPH_HEIGHT);

    glColor4ub(0, 0, 255, 255);
    glVertex2i(n, m_Hist_Channel_B[n]);
    glVertex2i(n, GRAPH_HEIGHT);
}
glEnd()

...

На этом этапе я чувствую, что должен заявить, что я новичок в OpenGL, поэтому возможно, что я неправильно понял многие вещи OpenGL ...

Мой вопрос: возможно ли исправить эту проблему в OpenGL, или мне придется увеличить число точек данных путем некоторой интерполяции, а затем построить график без масштабирования?

Я ценю любую предложенную помощь.

Ответы [ 2 ]

2 голосов
/ 15 мая 2019

Если вы разделите рендеринг на 3 прохода, вы сможете использовать треугольные полосы вместо линейных (которые должны заполнять промежутки).

glBegin(GL_TRIANGLE_STRIP);
glColor4ub(255, 0, 0, 255);
for (int n = 0; n < m_histogram_X; n++)
{
    glVertex2i(n, m_Hist_Channel_R[n]);
    glVertex2i(n, GRAPH_HEIGHT);
}
glEnd()

glBegin(GL_TRIANGLE_STRIP);
glColor4ub(0, 255, 0, 255);
for (int n = 0; n < m_histogram_X; n++)
{
    glVertex2i(n, m_Hist_Channel_G[n]);
    glVertex2i(n, GRAPH_HEIGHT);
}
glEnd()

glBegin(GL_TRIANGLE_STRIP);
glColor4ub(0, 0, 255, 255);
for (int n = 0; n < m_histogram_X; n++)
{
    glVertex2i(n, m_Hist_Channel_B[n]);
    glVertex2i(n, GRAPH_HEIGHT);
}
glEnd()
2 голосов
/ 14 мая 2019

Данные отсутствуют. Просто вы используете примитив для рисования таким образом, который не подходит для данных. GL_LINE_STRIP рисует одну длинную непрерывную линию, соединяя точки по мере их прохождения, а также интерполируя между заданными цветами.

По сути, вы делаете линию синего к красному от последней синей корзины до следующей высоты красной корзины, затем от красной корзины до зеленой корзины и оттуда до синей корзины. А потом вы переходите к следующей красной корзине и так далее. По сути, вы рисуете маленькие «шипы» с соединительными линиями между красным и синим. Конечно, будут пробелы, если для заполнения будет больше пикселей по ширине, чем для бинов.

Я предлагаю вам взять лист бумаги (графиков) и вручную выполнить этапы рисования, чтобы понять, как происходит этот результат.

Правда, которую нужно сказать: Это не самый эффективный способ нарисовать гистограмму в любом случае. Гораздо лучший подход состоит в том, чтобы загрузить данные гистограммы в 1D текстуру, нарисовать один большой квад (или еще лучше треугольник заполнения видового экрана, используя ножничное тестирование, чтобы разрезать видовой экран в прямоугольник) и для каждого фрагмента (примерно это пиксель, с некоторые дополнительные вещи) в фрагментном шейдере используйте координату X, чтобы найти корзину из текстуры и вычесть координату Y из текстуры и передать результат в функцию step или smoothstep GLSL для определить цвет для пикселя. Как ни странно это может показаться новичку, но рисование одного треугольника и выполнение всего остального в фрагментном шейдере является более эффективным, чем передача полосы полигонов. Это также дает гораздо лучшее качество!

Обновление - пример шейдера

Практическое приложение может быть реализовано с помощью такого шейдера (семантика Shadertoy):

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;

    // read the histogram data from a sampler
    // on shadertoy there are no 1D textures, so we use a
    // single row of a 2D texture instead, and sweep up/down
    // over time to get a "dynamic" histogram.
    vec3 h = texture(iChannel0, vec2(uv.x, sin(0.01*iTime))).rgb;

    // discard fragments which are "outside" the histogram
    // also use this value later for the alpha channel
    float a = smoothstep( 0.000, 0.001, length(h));
    if( 0. == a ){ discard; }

    // Color the fragment. The smoothstep gives some antialiasing.
    // For perfect pixel coverage based antialiasing we'd have to
    // determine the slope of the histogram, to construct a tangent
    // and determine the distance to it, i.e. create a
    // Signed Distance Field
    fragColor = vec4(
        smoothstep(-0.001, 0.001, h.r - uv.y),
        smoothstep(-0.001, 0.001, h.g - uv.y),
        smoothstep(-0.001, 0.001, h.b - uv.y),
        a );

    // Instead of using the smoothstep and/or the SDF using a
    // multisampled buffer and performing a simple `y >= h` test
    // would yield probably a nicer result.
}

Результат выглядит следующим образом

Shader based histogram

...