RedBook_OpenGL
.pdfЦветовые таблицы задаются тем же образом, что и одномерные изображения. Как показано на рисунке 8-15, существует 3 цветовые таблицы для изменения цветовых величин, и все они задаются командой glColorTable().
void glColorTable (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *data);
Если target равно GL_COLOR_TABLE, GL_POST_CONVOLUTION_COLOR_TABLE или
GL_POST_COLOR_MATRIX_COLOR_TABLE, настраивает соответствующую цветовую таблицу, а если GL_PROXY_COLOR_TABLE, GL_PROXY_POST_CONVOLUTION_COLOR_TABLE или GL_ PROXY_POST_COLOR_MATRIX_COLOR_TABLE – проверяет, что заданная цветовая таблица может быть размещена в доступных ресурсах. Аргумент internalFormat используется, чтобы указать внутреннее представление данных в OpenGL. Он может принимать следующие символические значения – GL_ALPHA, GL_ALPHA4, GL_ALPHA8, GL_ALPHA12, GL_ALPHA16, GL_LUMINANCE, GL_LUMINANCE4, GL_LUMINANCE8, GL_LUMINANCE12, GL_LUMINANCE16, GL_LUMINANCE_ALPHA, GL_LUMINANCE4_ALPHA4, GL_LUMINANCE6_ALPHA2, GL_LUMINANCE_8ALPHA8, GL_LUMINANCE12_ALPHA4, GL_LUMINANCE12_ALPHA12, GL_LUMINANCE16_ALPHA16, GL_INTENSITY, GL_INTENSITY4, GL_INTENSITY8, GL_INTENSITY12, GL_INTENSITY16, GL_RGB, GL_R3_G3_B2, GL_RGB4, GL_RGB5, GL_RGB8, GL_RGB10, GL_RGB12, GL_RGB16, GL_RGBA, GL_RGBA2, GL_RGBA4, GL_RGB5_A1, GL_RGBA8, GL_RGB10_A2, GL_RGBA12, GL_RGBA16. Параметр width, который должен быть степенью 2, индицирует количество пикселей в цветовой таблице. Аргументы format и type описывают формат и тип данных цветовой таблицы. Они имеют такое же значение, как и эквивалентные параметры команды glDrawPixels().
Внутренний формат таблицы определяет то, какие компоненты пикселей изображения будут заменены. Например, если вы задаете GL_RGB в качестве формата, то красный,
зеленый и синий компоненты каждого входящего пикселя будут искаться в соответствующей цветовой таблице и заменяться значениями оттуда. Таблица 8-8 описывает, какие компоненты пикселей будут заменяться при различных внутренних форматах.
Таблица 8-8 Замена значений пикселей цветовой таблицей
Базовый внутренний |
Красный |
Зеленый |
Синий |
Альфа |
формат |
компонент |
компонент |
компонент |
компонент |
GL_ALPHA |
не изменяется |
не изменяется |
не изменяется |
|
GL_LUMINANCE |
|
|
|
не изменяется |
GL_LUMINANCE_ALPHA |
|
|
|
|
GL_INTENSITY |
|
|
|
|
GL_RGB |
|
|
|
не изменяется |
GL_RGBA |
|
|
|
|
|
|
|
|
|
В таблице 8-8 величины представляют собой светлоту в цветовой таблице, которая
влияет только на красный, зеленый и синий компоненты. представляет табличные интенсивности, которые одинаково влияют на красный, зеленый, синий и альфа компоненты.
После того как таблица была применена к изображению, пиксели могут быть смасштабированы и скошены, после чего, их значения приводятся к диапазону [0; 1].
Факторы GL_COLOR_TABLE_SCALE и GL_COLOR_TABLE_BIAS для каждой таблицы устанавливаются с помощью команды glColorTableParameter*().
void glColorTableParameter{if}v (GLenum target, GLenum pname, TYPE *param);
Устанавливаетпараметры GL_COLOR_TABLE_SCALE и GL_COLOR_TABLE_BIAS для каждой таблицы. target может быть равно GL_COLOR_TABLE, GL_POST_CONVOLUTION_COLOR_TABLE или GL_POST_COLOR_MATRIX_COLOR_TABLE и
задает целевую таблицу, для которой устанавливаются параметры. Возможными значениями для pnamee являются GL_COLOR_TABLE_SCALE и GL_COLOR_TABLE_BIAS.
Величина param указывает на массив из 4-ех величин, представляющих, соответственно, модификаторы для красного, зеленого, синего и альфа компонент.
Пример 8-5 показывает, как изображение может быть инвертировано посредством цветовой таблицы. Таблица настраивается таким образом, чтобы она заменяла каждый цвет на его инверсию. Пример инвертированного цветовой таблицей изображения приведен на рисунке 8-16.
Рисунок 8-16. Исходное изображение айсберга (слева) и то же изображение, инвертированное с помощью цветовой таблицы (справа))
Пример 8-5. Замена пикселей с использованием цветовой таблицы: файл colortable.cpp
#include <glut.h> #include <GL/glaux.h> #include "glext.h"
//Массив для исходного изображения
AUX_RGBImageRec *image;
//Тип и указатель для функции цветовой таблицы (EXTENSION) typedef void (APIENTRY * GLCOLORTABLE)
(GLenum target,GLenum internalFormat,GLsizei width, GLenum format, GLenum type, const GLvoid *data);
GLCOLORTABLE glColorTable=NULL;
void init()
{
int i;
GLubyte colorTable[256][3];
//Загрузить исходное изображение из 24-разрядного файла BMP
//(библиотека GLAUX) image=auxDIBImageLoad("peak.bmp");
//Получить адрес функции цветовой таблицы
//с помощью функции специфической для реализации OpenGL для
Windows glColorTable=(GLCOLORTABLE)wglGetProcAddress("glColorTable");
if (glColorTable==NULL)
{
MessageBox(NULL, "Function [glColorTable] from [GL_ARB_imaging] extension not supported!",
"Pixel Replacement Using Color Tables", MB_OK|MB_ICONSTOP);
exit(1);
}
glPixelStorei(GL_UNPACK_ALIGNMENT,1); glClearColor(0,0,0,0);
//Инвертирующая цветовая таблица for(i=0;i<256;++i)
{
colorTable[i][0]=255-i; colorTable[i][1]=255-i; colorTable[i][2]=255-i;
}
glColorTable(GL_COLOR_TABLE,GL_RGB,256, GL_RGB,GL_UNSIGNED_BYTE,colorTable);
glEnable(GL_COLOR_TABLE);
}
void deinit()
{
//Очислитьпамять delete image;
}
void reshape(int w, int h)
{
glViewport(0,0,(GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0,500,0,500);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT); glRasterPos2i(1,1); glDrawPixels(image->sizeX, image->sizeY,
GL_RGB,GL_UNSIGNED_BYTE,image->data);
glFlush();
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE |
hPrevInstance, |
LPSTR |
lpCmdLine, |
int |
nCmdShow) |
{ |
|
char* argv=""; |
|
int argc=0; |
|
glutInit(&argc,&argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(540,405);
glutCreateWindow("Pixel Replacement Using Color Tables"); init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
deinit(); return 0;
}
Замечание: Поскольку загрузка изображения должна производиться способом, зависящим от вашей оконной системы, а также потому, что в GLUT нет подобных функций, в данном примере используется функция auxDIBImageLoad() из библиотеки GLAUX для Windows.
Вместо того, чтобы задавать цветовую таблицу непосредственно из вашего приложения, вам может понадобиться использовать в качестве нее изображение, созданное в буфере кадра. Команда glCopyColorTable() позволяет вам задать ряд пикселей, которые считываются из буфера кадра и используются в качестве цветовой таблицы.
void glCopyColorTable (GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width);
Создает цветовую таблицу, используя данные из буфера кадра в качестве данных для цветовой таблицы. Пиксели считываются из текущего буфера для чтения (GL_READ_BUFFER) и обрабатываются так же как при вызове glCopyPixels(), но без последней конверсии. Учтите, что производятся также операции, заданные glPixelTransfer*(). Параметры target и internalFormat имеют то же значение, что и для glColorTable(). Цветовой массив будет состоять из width пикселей вправо, начиная с (x, y) буфера кадра.
8.2.5.1.2Замена всей цветовой таблицы или ее части
Если вам требуется заменить часть цветовой таблицы, вы можете загрузить ее секцию с помощью команд glColorSubTable() и glCopyColorSubTable().
void glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
Заменяет вхождения [start;start+count-1] цветовой таблица на величины, находящиеся в data. Параметр target может принимать значения GL_COLOR_TABLE, GL_POST_CONVOLUTION_COLOR_TABLE, GL_POST_COLOR_MATRIX_COLOR_TABLE.
Параметры format и type идентичны соответствующим параметрам glColorTable().
void glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei count);
Заменяет вхождения [start;start+count-1] цветовой таблица на countцветовых величин пикселей из ряда буфера кадра, начинающегося с позиции (x; y). Пиксели конвертируются в internalFormat оригинальной таблицы.
8.2.5.1.3Запрос величин цветовых таблиц
Величины пикселей, сохраненные в цветовой таблице, могут быть получены с помощью команды glGetColorTable().
8.2.5.1.4Проверка цветовых таблиц
Прокси цветовых таблиц позволяют заставить OpenGL выяснить, достаточно ли в системе ресурсов для размещения вашей цветовой таблицы. Если glColorTable() вызывается с одним из следующих аргументов:
∙GL_PROXY_COLOR_TABLE
∙GL_PROXY_POST_CONVOLUTION_COLOR_TABLE
∙GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE
OpenGL проверяет, есть ли ресурсы для размещения соответствующей таблицы. Если таблица не влезает, ее величины width, format и type устанавливаются в 0. Если вы хотите выяснить, достаточно ли ресурсов – проверьте одну из этих величин. Например, так:
glColorTable(GL_PROXY_COLOR_TABLE, GL_RGB, 1024, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glGetColorTableParameteriv(GL_PROXY_COLOR_TABLE, GL_COLOR_TABLE_WIDTH, &width);
if(width==0)
/*цветовая таблица не умещается*/
8.2.5.2Весовые модификаторы
Весовые модификаторы (convolutions) работают в качестве фильтров, заменяя каждый
пиксель изображения на взвешенное среднее соседствующих с ним пикселей и его самого. Размытие изображения, нахождение ребер и изменение контраста являются примерами применения весовые модификаторы.
На рисунке 8-18 показано, как пиксель и соседние с ним обрабатываются весовым модификатором размера 3x3 для получения пикселя .
Рисунок 8-17. Операция пиксельной фильтрации
Весовые модификаторы – это массивы весов пикселей, и работают они только на RGBA пикселях. Фильтр, также известный как kernel, является простым двумерным массивом весов. Каждый пиксель изображения – результата создается умножением группы
входящих пикселей на весовые коэффициенты фильтра и суммированием
получившихся произведений. Например, на рисунке 8-17 пиксель вычисляется суммированием произведений 9-ти пикселей из входящего изображения на 9 весовых коэффициентов из фильтра.
void glConvolutionFilter2D (GLenum target,GLenum internalFormat,GLsizei width,GLsizei height,
GLenum format,GLenum type,const GLvoid *image);
Задает двумерный фильтр. Параметр filter должен быть равен GL_CONVOLUTION_3D. internalFormat задает, над какими компонентами пикселей будет производиться фильтрация и может принимать одно из 38 значений, перечисленных для аргумента internalFormat команды glColorTable(). Аргументы width и height задают размеры
фильтра в пикселях. Максимальная ширина и высота для фильтров может быть получена с помощью команды glGetConvolutionParameter*(). Как и в случае glDrawPixels(), аргументы format и type задают формат пикселей, сохраненных в массиве, на который указывает image.
Как и для цветовых таблиц, внутренний формат фильтра определяет то, с какими компонентами пикселей требуется работать. Таблица 8-9 описывает, как различные
форматы влияют на пиксели. , , и представляют цветовые компоненты исходных пикселей. представляет собой величину светлоты фильтра
GL_LUMINANCE, а -- величину интенсивности фильтра GL_INTENSITY. Наконец, , , и представляют красный, зеленый, синий и альфа компоненты фильтра.
Таблица 8-9. Влияние фильтров на RGBA компоненты пикселей
Базовый формат |
Результат по |
Результат по |
Результат по |
Результат по |
|
красному |
зеленому |
синему |
альфа |
||
фильтра |
|||||
компоненту |
компоненту |
компоненту |
компоненту |
||
|
|||||
GL_ALPHA |
не изменяется |
не изменяется |
не изменяется |
|
|
GL_LUMINANCE |
|
|
|
не изменяется |
|
GL_LUMINANCE_ALPHA |
|
|
|
|
|
GL_INTENSITY |
|
|
|
|
|
GL_RGB |
|
|
|
не изменяется |
|
GL_RGBA |
|
|
|
|
|
|
|
|
|
|
Чтобы активизировать 2D фильтрацию, используйте glEnable (GL_CONVOLUTION_2D).
Пример 8-6 демонстрирует использование нескольких 2D фильтров GL_LUMINANCE размером 3x3 для поиска ребер в RGBизображении. Клавиши ‘h’, ‘v’ и ‘l’ переключают режимы.
Результат работы программы можно увидеть на рисунке 8-18 (яркость и контрастность изображений увеличена для наглядности). Слева вверху находится исходное изображение пирамиды, справа вверху – то же изображение, обработанное фильтром, позволяющим обнаружить горизонтальные ребра, внизу слева – похожий фильтр, но на этот раз вертикальный, справа внизу – изображение обработанное фильтром Лапласа.
Рисунок 8-18. Пример обработки изображения двумерным фильтром для обнаружения
ребер
Пример 8-6. Использование двумерных фильтров: файл convolution.cpp
#include <windows.h> #include <glut.h> #include <GL/glaux.h> #include "glext.h"
//Указатель на память, где будет содержаться картинка
AUX_RGBImageRec *image;
//Определить фильтры
GLfloat horizontal[3][3]={{0,-1,0},{0,1,0},{0,0,0}}; GLfloat vertical[3][3]= {{0,0,0},{-1,1,0},{0,0,0}}; GLfloat laplacian[3][3]= {{-0.125,-0.125,-0.125},
{-0.125,1,-0.125}, {-0.125,-0.125,-0.125}};
//Тип и указатель для фильтра (если конечно расширение поддерживается)
typedef void (APIENTRY * GLCONVOLUTIONFILTER2D)
(GLenum target,GLenum internalFormat,GLsizei width, GLsizei height,GLenum format, GLenum type, const GLvoid
*data);
GLCONVOLUTIONFILTER2D glConvolutionFilter2D=NULL;
void init()
{
//Проверяем, присутствует ли расширение GL_ARB_imaging (imaging subset)
if (glutExtensionSupported("GL_ARB_imaging")==0)
{
MessageBox(NULL,"ARB_imaging extension not supported", "Using Two-Dimensional Convolution
Filters",MB_OK|MB_ICONHAND); exit(1);
}
//Получаем указатель на функцию расширения glConvolutionFilter2D=(GLCONVOLUTIONFILTER2D)
wglGetProcAddress("glConvolutionFilter2D");
//Загружаем любую непалитровую картинку BMP image=auxDIBImageLoad("peak.bmp"); glPixelStorei(GL_UNPACK_ALIGNMENT,1); glClearColor(0,0,0,0);
}
void deinit()
{
//Освобождаемпамять delete image;
}
void keyboard(unsigned char key, int x, int y)
{
switch(key)
{
case 'h':
MessageBox(NULL,"Using horizontal filter", "Using Two-Dimensional Convolution
Filters",MB_OK);
glConvolutionFilter2D(GL_CONVOLUTION_2D,GL_LUMINANCE,3,3,
GL_LUMINANCE,GL_FLOAT,horizontal); glEnable(GL_CONVOLUTION_2D); break;
case 'v':
MessageBox(NULL,"Using vertical filter", "Using Two-Dimensional Convolution
Filters",MB_OK);
glConvolutionFilter2D(GL_CONVOLUTION_2D,GL_LUMINANCE,3,3,
GL_LUMINANCE,GL_FLOAT,vertical); glEnable(GL_CONVOLUTION_2D); break;
case 'l':
MessageBox(NULL,"Using laplacian filter", "Using Two-Dimensional Convolution
Filters",MB_OK);
glConvolutionFilter2D(GL_CONVOLUTION_2D,GL_LUMINANCE,3,3,
GL_LUMINANCE,GL_FLOAT,laplacian); glEnable(GL_CONVOLUTION_2D); break;
case 'r':
MessageBox(NULL,"No filter used", "Using Two-Dimensional Convolution
Filters",MB_OK);
glDisable(GL_CONVOLUTION_2D);
break; case 27:
exit(0);
}
glutPostRedisplay();
}
void reshape(int w, int h)
{
glViewport(0,0,(GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0,540,0,405);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT); glRasterPos2i(1,1); glDrawPixels(image->sizeX,image->sizeY,GL_RGB,
GL_UNSIGNED_BYTE,image->data);
glFlush();
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE |
hPrevInstance, |
LPSTR |
lpCmdLine, |
int |
nCmdShow) |
{ |
|
char* argv=""; int argc=0;
glutInit(&argc,&argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(540,405);
glutCreateWindow("Using Two-Dimensional Convolution Filters"); init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
deinit(); return 0;
}
Как и в случае с цветовыми таблицами, вы можете задать фильтр с помощью пиксельных величин, взятых из буфера кадра. Команда glCopyConvolutionFilter2D() копирует прямоугольник пикселей из текущего буфера для чтения (GL_READ_BUFFER) для использования в качестве данных фильтра. Если в качестве внутреннего формата используется GL_LUMINANCE или GL_INTENSITY, то в качестве величин фильтра берутся красные компоненты пикселей.
void glCopyConvolutionFilter2D (GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height);
Задает двумерный фильтр, инициализируя его пикселями из цветового буфера кадра. Аргумент target должен иметь значение GL_CONVOLUTION_2D, а internalFormat должен быть установлен в одно из значений, допустимых для glConvolutionFilter2D().
Прямоугольник пикселей с левым нижним углом в точке (x; y) и размерами width и height считывается из буфера кадра и конвертируется в internalFormat.
8.2.5.2.1Разделяемые двумерные фильтры