Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

RedBook

.pdf
Скачиваний:
18
Добавлен:
11.06.2015
Размер:
7.43 Mб
Скачать

Фильтры являются разделяемым, если они могут быть представлены в виде произведения двух одномерных фильтров.

Для создания двух одномерных фильтров, представляющих разделяемый двумерный фильтр, применяется команда glSeparableFilter2D(). Также как и в случае glConvolutionFilter2D() внутренний формат определяет то, как будут обрабатываться пиксели.

void glSeparableFilter2D (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height,

GLenum format, GLenum type, const GLvoid *row, const

GLvoid *column);

Создает разделяемый двумерный фильтр. target должен быть установлен в значение GL_SEPARABLE_2D. Аргумент internalFormat может иметь те же значения, что и для команды glConvolutionFilter2D(). Аргумент width задает количество пикселей в массиве row. Похожим образом height задает число пикселей в массиве column. type и format так же как в команде glConvolutionFilter2D() определяют формат хранения для массивов row и column.

Чтобы включить обработку пикселей разделяемыми двумерными фильтрами, используйте glEnable(GL_SEPARABLE_2D). Если создан разделяемый фильтр, то он будет работать только в случае если активизированы оба режима: GL_CONVOLUTION_2D и GL_SEPARABLE_2D.

Например, вы можете создать фильтр 3x3, задав одномерный фильтр [-1/2, 1, -1/2] и для row, и для column разделяемого фильтра GL_LUMINANCE. OpenGL вычислит результирующее изображение с использованием двух одномерных фильтров так же, как она вычисляет его с использованием двумерного фильтра, вычислив следующее произведение:

.

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

8.2.5.2.2Одномерные фильтры

Одномерные фильтры идентичны двумерным за тем исключением, что высота фильтра предполагается равной 1. Однако одномерные фильтры влияют только на одномерные текстуры.

void glConvolutionFilter1D (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);

Задает одномерный фильтр. Аргумент target должен быть установлен в значение GL_CONVOLUTION_1D. Аргумент width задает количество пикселей в фильтре. Аргументы internalFormat, type и format имеют то же значение, что и соответствующие параметры glConvolutionFilter2D(). image указывает на одномерное изображение, которое будет использоваться в качестве фильтра.

Для активизации одномерной фильтрации используйте команду glEnablee(GL_CONVOLUTION_1D).

Возможно, вам понадобится задать фильтр с помощью величин, взятых из буфера кадра. Команда glCopyConvolutionFilterr1D() копирует ряд пикселей из текущего буфера для чтения (GL_READ_BUFFER), конвертирует их в заданный внутренний формат и использует их в качестве фильтра.

void glCopyConvolutionFilter1D (GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width);

Создает одномерный фильтр с помощью пикселей взятых из буфера кадра. glCopyConvolutionFilter1D() копирует width пикселей, начиная с позиции (x, y) и конвертирует их в internalFormat.

Когда фильтр создан, он может быть смасштабирован и скошен. Масштаб и скос задаются с помощью команды glConvolutionParameter*(). Фильтр не приводится к какому-либо диапазону после масштабирования и скоса.

void glConvolutionParameter{if} (GLenum target, GLenum pname, TYPE param); void glConvolutionParameter{if}v (GLenum target, GLenum pname, TYPE *params);

Устанавливают параметры, управляющие тем, как производится фильтрация. Аргумент targetдолжен быть установлен в значения GL_CONVOLUTION_1D, GL_CONVOLUTION_2D

или GL_SEPARABLE_2D. Аргумент pname должен принимать одно из значений

GL_CONVOLUTION_BORDER_MODE, GL_CONVOLUTION_FILTER_SCALE или

GL_CONVOLUTION_FILTER_BIAS. Указание в качестве аргумента pname значения GL_CONVOLUTION_BORDER_MODE устанавливает режим границы фильтрации. В этом случае params должно иметь значение GL_REDUCE, GL_CONSTANT_BORDER или

GL_REPLICATE_BORDER. Если pname установлен в GL_CONVOLUTION_FILTER_SCALE или

GL_CONVOLUTION_FILTER_BIAS, params должен указывать на массив из 4-ех цветовых величин для красного, зеленого, синего и альфа, соответственно.

8.2.5.2.3Режимы границы

Пиксели изображения, находящиеся на верхней и левой границах, обрабатываются иначе, чем внутренние пиксели. Результат по ним подвергается модификации в зависимости от режима границы фильтра. Существует три варианта фильтрования граничных пикселей:

режим GL_REDUCE приводит к тому, что изображение уменьшается в каждом из направлений. Ширина изображения уменьшается до (width-1). Точно так же высота изображения сокращается (height-1). Если такое сокращение приводит к тому, что изображение имеет нулевые или отрицательные размеры, выходное изображение не генерируется, но также не генерируется никаких ошибок.

GL_CONSTANT_BORDER вычисляет фильтрованные граничные пиксели с

использованием постоянной пиксельной величины для пикселей вне исходного изображения. Постоянная пиксельная величина задается с помощью команды glConvolutionParameter*(). Размер результирующего изображения совпадает с размерами исходного.

GL_REPLICATE_BORDER производит вычисления способом аналогичным GL_CONSTANT_BORDER за тем исключением, что последний ряд и колонка пикселей используется для пикселей, лежащих вне исходного изображения. Размер результирующего изображения совпадает с размерами исходного.

8.2.5.2.4Пост фильтрационные операции

После того, как операция фильтрации завершена, пиксели могут быть масштабированы и скошены. Затем они приводятся к диапазону [0; 1]. Величины масштаба и скоса задаются командой glPixelTransfer*(), с аргументами

GL_POST_CONVOLUTION_*_SCALEили GL_POST_CONVOLUTION_*_BIAS. Если задать

цветовую таблицу командой glColorTable() с аргументом GL_POST_CONVOLUTION_COLOR_TABLE, то пиксели после фильтрации будут заменены с использованием этой таблицы.

8.2.5.3Цветовая матрица

Для конверсии цветовых пространств и линейных преобразований пиксельных величин, подмножество обработки изображений поддерживает стек матриц 4x4, выбираемый с помощью команды glMatrixMode(GL_COLOR). Например, чтобы преобразовать цветовое пространство RGB в CMY (cyan – голубой, magenta – фиолетовый, yellow – желтый) можно произвести следующие вызовы:

GLfloat rgb2cmy[16]= {-1,0,0,0, 0,-1,0,0, 0,0,-1,0, 1,1,1,1};

glMatrixMode(GL_COLOR);

//войти в режим цветовой матрицы

glLoadMatrixf(rgb2cmy);

//назад к видовой матрице

glMatrixMode(GL_MODELVIEW);

Замечание: помните о том, что матрицы в OpenGL хранятся по столбцам.

Стек цветовых матриц должен быть достаточного размера для хранения как минимум двух матриц. В отличие от других частей подмножества обработки изображений

конверсия с помощью цветовой матрицы производится всегда и не может быть выключена.

Пример 8-7 иллюстрирует использование цветовой матрицы для перемены местами красного и зеленого компонентов изображения. Результат работы программы показан на рисунке 8-19. Здесь слева изображено исходное изображение, а справа обработанное с помощью цветовой матрицы.

Рисунок 8-19. Результат обработки изображения цветовой матрицей, меняющей местами компоненты R и G

Пример 8-7. Обмен цветовых компонент с помощью цветовой матрицы: файл colormatrix.cpp

#include <windows.h> #include <glut.h>

#include <glaux.h> #include "glext.h"

//Указатель на память, где будет содержаться картинка

AUX_RGBImageRec *image;

//Задать цветовую матрицу для изменения порядка цветов в пикселе //изображения с RGB в GBR

GLfloat m[16]={ 0.0,1.0,0.0,0.0, 0.0,0.0,1.0,0.0, 1.0,0.0,0.0,0.0, 0.0,0.0,0.0,1.0

};

//Флаг показывающий, используем мы матрицу или нет bool reversing;

void init()

{

//Проверяем, присутствует ли расширение GL_ARB_imaging (imaging subset)

if (glutExtensionSupported("GL_ARB_imaging")==0)

{

MessageBox(NULL,"ARB_imaging extension not supported", "Using Color Matrix",MB_OK|MB_ICONHAND);

exit(1);

}

//Загружаем любую непалитровую картинку BMP image=auxDIBImageLoad("tree.bmp"); glPixelStorei(GL_UNPACK_ALIGNMENT,1); glClearColor(0,0,0,0);

reversing=false;

}

void deinit()

{

//Освобождаем память delete image;

}

void reshape(int w, int h)

{

glViewport(0,0,(GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0,542,0,407);

}

void keyboard(unsigned char key,int x,int y)

{

switch(key)

{

case 'r':

if (!reversing)

{

//Для расширения цветовой таблицы //нужен только идентификатор GL_COLOR //при отсутствии этого расширения //код ниже не сработает glMatrixMode(GL_COLOR);

glLoadMatrixf(m); glMatrixMode(GL_MODELVIEW);

}

else

{

glMatrixMode(GL_COLOR); glLoadIdentity(); glMatrixMode(GL_MODELVIEW);

}

reversing=!reversing;

glutPostRedisplay();

break; case 27:

exit(0);

break;

}

}

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(542,407);

glutCreateWindow("Exchanging Color Components Using the Color Matrix");

init();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutKeyboardFunc(keyboard);

glutMainLoop();

deinit(); return 0;

}

8.2.5.3.1Пост матричные операции

Также как и в случае пост фильтрационных операций, после применения цветовой матрицы пиксели могут быть масштабированы и скошены. Вызовы функции glPixelTransfer*() с аргументами GL_POST_COLOR_MATRIX_*_SCALE или

GL_POST_COLOR_MATRIX_*_BIAS позволяют задать параметры масштабирования или скоса соответственно. После масштабирования и скоса пиксели приводятся к диапазону

[0; 1].

8.2.5.4Гистограмма

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

изображению, которое, например, может быть использовано для балансировки контраста изображения.

Команда glHistogram() позволяет задать, какие компоненты изображения вы хотите использовать для создания гистограммы, а также, хотите ли вы только собрать статистику или продолжить обработку изображения. Чтобы собрать гистограммную статистику, вы должны выполнить команду glEnable(GL_HISTOGRAMM).

Для гистограммы, так же как и для цветовых таблиц, прокси механизм доступен для того, чтобы определить достаточно ли в системе ресурсов для хранения требуемой гистограммы. Если ресурсов не хватает, длина гистограммы, ее формат и разрешения компонент устанавливаются в 0. Вы можете запросить результаты прокси гистограммы,

используя команду glHistogramParameter().

void glHistogram (GLenum target, GLsizei width, GLenum internalFormat, GLboolean sink);

Задает, как должны сохраняться данные гистограммы изображения. Параметр target должен быть установлен в одно из значений GL_HISTOGRAM или GL_PROXY_HISTOGRAM. Параметр width задает количество вхождений в таблицу гистограммы. Его значение должно быть степенью 2. Параметр internalFormat определяет, как должны сохраняться данные гистограммы. Допустимыми значениями являются: 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_RGB, GL_RGB2, 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. В этом списке нет величин GL_INTENSITY*. Этот список отличается от величин допустимых для glColorTable(). Параметр sink индицирует, должны ли пиксели проходить дальше на этап вычисления минимума/максимума или следует их отбросить..

После того, как вы передали пиксели на конвейер с использованием glDrawPixels(), вы можете получить результаты гистограммы, используя glGetHistogram(). Помимо получения значений гистограммы, glGetHistogram() может быть использована для сброса внутреннего хранилища гистограммы. Внутреннее хранилище также может быть сброшено с помощью функции glResetHistogram().

void glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);

Возвращает собранную статистику в виде гистограммы. Параметр target должен быть установлен в значение GL_HISTOGRAM. Параметр resetзадает, должно ли внутренне хранилище гистограммы быть сброшено. Параметры format и type задают формат хранения массива values и то, как данные гистограммы должны быть возвращены приложению. Эти аргументы принимают те же значения, что и соответствующие параметры glDrawPixels().

В примере 8-8 программа вычисляет гистограмму изображения и выводит результирующее распределение на экран. Клавиша ‘s’ влияет на значение параметра sink, контролирующего дальнейший путь пикселей исходного изображения будут ли они пропущены на следующий этап конвейера или отброшены. Рисунок 8-20 демонстрирует исходное изображение (слева), а также изображение с наложенной на него гистограммой (справа).

Рисунок 8-20. Исходное изображение и его гистограмма

Пример 8-8. Вычисление гистограммы изображения: файл histogram.cpp

#include <windows.h> #include <glut.h> #include <glaux.h> #include "glext.h"

#define HISTOGRAM_SIZE 256

GLboolean sink=GL_FALSE;

//Указатель на память, где будет содержаться картинка

AUX_RGBImageRec *image;

//Тип и указатель для функции определяющей как данные гистограммы изображения будут сохранены

typedef void (APIENTRY * GLHISTOGRAM) (GLenum target,GLsizei width,

GLenum internalFormat, GLboolean sink); GLHISTOGRAM glHistogram=NULL;

//Тип и указатель для функции получения статистики по гистограмме typedef void (APIENTRY * GLGETHISTOGRAM)

(GLenum target,GLboolean reset, GLenum format, GLenum type, const GLvoid *values);

GLGETHISTOGRAM glGetHistogram=NULL;

void init()

{

//Проверяем, присутствует ли расширение GL_ARB_imaging (imaging subset)

if (glutExtensionSupported("GL_ARB_imaging")==0)

{

MessageBox(NULL,"ARB_imaging extension not supported", " Compute and Diagram an Image's Histogram ", MB_OK|MB_ICONHAND);

exit(1);

}

//Получаем указатель на функции расширения glHistogram=(GLHISTOGRAM)wglGetProcAddress("glHistogram");

glGetHistogram=(GLGETHISTOGRAM)wglGetProcAddress("glGetHistogram");

//Загружаем любую непалитровую картинку BMP image=auxDIBImageLoad("pyr.bmp");

glPixelStorei(GL_UNPACK_ALIGNMENT,1); glClearColor(0,0,0,0);

glHistogram(GL_HISTOGRAM,HISTOGRAM_SIZE,GL_RGB,sink); glEnable(GL_HISTOGRAM);

}

void deinit()

{

//Освобождаем память delete image;

}

void keyboard(unsigned char key, int x, int y)

{

switch(key)

{

case 's': sink=!sink;

glHistogram(GL_HISTOGRAM,HISTOGRAM_SIZE,GL_RGB,sink); glutPostRedisplay();

break; case 27:

deinit();

exit(0);

break;

}

}

void reshape(int w, int h)

{

glViewport(0,0,(GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0,540,0,405);

}

void display()

{

int i;

GLushort values[HISTOGRAM_SIZE][3];

glClear(GL_COLOR_BUFFER_BIT); glRasterPos2i(1,1); glDrawPixels(image->sizeX,image->sizeY,GL_RGB,

GL_UNSIGNED_BYTE,image->data);

glGetHistogram(GL_HISTOGRAM,GL_TRUE,GL_RGB,GL_UNSIGNED_SHORT,values);

//Plot histogram glBegin(GL_LINE_STRIP);

glColor3f(1.0,0.0,0.0); for(i=0;i<HISTOGRAM_SIZE;i++)

glVertex2s(i,values[i][0]);

glEnd(); glBegin(GL_LINE_STRIP);

glColor3f(0.0,1.0,0.0); for(i=0;i<HISTOGRAM_SIZE;i++)

glVertex2s(i,values[i][1]);

glEnd(); glBegin(GL_LINE_STRIP);

glColor3f(0.0,0.0,1.0);

for(i=0;i<HISTOGRAM_SIZE;i++) glVertex2s(i,values[i][2]);

glEnd();

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("Compute and Diagram an Image's Histogram"); init();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutKeyboardFunc(keyboard);

glutMainLoop();

deinit(); return 0;

}

Команда glResetHistogram() сбрасывает гистограмму без извлечения ее данных.

void glResetHistogram (GLenum target);

Сбрасывает счетчики гистограммы в 0. Параметр target должен быть установлен в

GL_HISTOGRAM.

8.2.5.5Минимум и максимум

Команда glMinmax() вычисляет минимальное и максимальное значения компонентов пикселя из пиксельного прямоугольника. Как и в случае glHistogram() после

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

void glMinmax (GLenum target, GLenum internalFormat, GLboolean sink);

Вычисляет минимальное и максимальное значения пикселей изображения. Аргумент target должен быть установлен в GL_MINMAX. internalFormat задает для каких компонент должны быть вычислены значения минимума и максимума. Допустимыми значениями для internalFormat команды glMinmax() являются те же, что и для команды glHistogram(). Если аргумент sink установлен в GL_TRUE, то после вычисления минимума и максимума путь пикселей по конвейеру прекращается, иначе их обработка продолжается.

Для получения вычисленных значений используется команда glGetMinmax(). Так же

как в случае glGetHistogram() внутренние значения могут быть сброшены после их получения.

void glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);

Возвращает результаты вычисления минимума и максимума. Аргумент target должен быть установлен в GL_MINMAX. Если аргумент reset равен GL_TRUE, значения минимума и максимума сбрасываются в свои начальные значения. Аргументы format и type задают формат значений возвращаемых в массиве values и могут принимать те же значения, что и аналогичные параметры команды glDrawPixels().

Пример 8-9 демонстрирует использование команды glMinMax() для вычисления минимального и максимального значений компонент пикселей в формате GL_RGB.

Пример исходного изображения и результатов работы программы можно увидеть на рисунке 8-21. Операция вычисления минимума и максимума должна быть активизирована с использованием команды glEnable(GL_MINMAX).

В массиве, возвращенном командой glGetMinmax() первыми элементами идут вычисленные минимумы для всех трех цветовых компонент, а следом за ними все максимумы.

Рисунок 8-21. Изображение и экстремумы цветовых компонент его пикселей

Пример 8-9. Вычисление минимума и максимума пиксельных величин: файл minmax.cpp

#include <windows.h> #include <glut.h> #include <glaux.h> #include <stdio.h> #include "glext.h"

//Указатель на память, где будет содержаться картинка

AUX_RGBImageRec *image;

Соседние файлы в предмете Компьютерная Графика