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

GMSAPR

.pdf
Скачиваний:
11
Добавлен:
16.03.2016
Размер:
9.01 Mб
Скачать

141

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

Растяжение диапазона яркости выполняется так же, как было рассмотрено в предыдущем разделе, за исключением того, что смещение по шкале яркости сверху и снизу одинаково и задается параметром c_offset. Еще одним отличием является то, что после преобразования яркости работа по коррекции контрастности происходит со значениями таблицы преобразования, полагая при этом, что они являются индексами в таблице, полученной после коррекции яркости.

#define CONTRAST_MEDIAN 159 // «Серая средина»

BOOL CBrightCont::Init(int b_offset, int c_offset)

{

int i=0,

// Индекс цвета в

таблице

преобразования

 

t=0,

// Индекс таблицы

 

 

 

// Индекс цвета, соответствующего

нижней границе

яркости

t_index=0,

// Индекс цвета, соответствующего верхней границе яркости b_index=0,

value_offset; // Смещение значения цвета double value=0.; // Новое значение цвета

// Изменяем яркость for(i, t=0; t<3; t++)

for(i=0; i<256; i++)

{

if( i+b_offset>255) BGRTransTable[t][i]=255;

else

if( i+b_offset<0) BGRTransTable[t][i]=0;

else BGRTransTable[t][i]=i+b_offset;

}

// Изменяем контрастность

142

if(c_offset<0)// Уменьшаем контрастность

{

for(i=0, t=0; t<3; t++) for(i=0; i<256; i++)

if(BGRTransTable[t][i]<CONTRAST_MEDIAN)

{// Расчитываем смещение в зависимости от

// удаленности цвета от «серой середины» value_offset=(CONTRAST_MEDIAN-

BGRTransTable[t][i])*c_offset/128;

if(BGRTransTable[t][i]-value_offset>CONTRAST_MEDIAN) BGRTransTable[t][i]=CONTRAST_MEDIAN;

else BGRTransTable[t][i]-=value_offset;

}

else

{// Расчитываем смещение в зависимости

//от удаленности цвета от «серой середины» value_offset=(BGRTransTable[t][i]-

CONTRAST_MEDIAN)*c_offset/128; if(BGRTransTable[t][i]+value_offset<CONTRAST_MEDIAN)

BGRTransTable[t][i]=CONTRAST_MEDIAN; else BGRTransTable[t][i]+=value_offset;

}

}

else if(c_offset>0) //Увеличиваем контрастность

{// Расчет нижней границы цвета

int offset_b=c_offset*CONTRAST_MEDIAN/128;

//Все значения в таблице

//ниже нижней границы получат значения 0 for(t=0; t<3; t++)

for(b_index=0; b_index<256; b_index++)

{

if(BGRTransTable[t][b_index]<offset_b) BGRTransTable[t][b_index]=0;

else break;

}

//Расчет верхней границы цвета

143

int offset_t=c_offset*128/CONTRAST_MEDIAN;

//Все значения выше верхней границы получат значения 255 for(t=0; t<3; t++)

for(t_index=255; t_index>=0; t_index--)

{

if(BGRTransTable[t][t_index]+offset_t>255) BGRTransTable[t][t_index]=255;

else break;

}

//Расчет шага изменения интенсивности цвета

double step=256./(256-(offset_b+offset_t));

// «Растягиваем» интенсивность цветов между нижней и верхней

//границами, чтобы они занимали весь диапазон от 0 до 255 for(t=0; t<3; t++)

{

value=0.;

for(i=b_index; i<=t_index; i++)

{

if(BGRTransTable[t][i]>=offset_b || BGRTransTable[t][i]<256-offset_t)

{

value=(int)((BGRTransTable[t][i]- offset_b)*step+0.5);

if(value>255) value=255; BGRTransTable[t][i]=(int)(value);

}

}

}

}

return TRUE;

};

Для того, чтобы пользователь мог указать значения коррекции яркости и контрастности, добавим в программу диалог «Яркость/Контраст». Создание

144

окна диалога очень мало отличается от создания окна для диалога «Гистограмма».

Рис. 14. Шаблон диалога коррекции яркости и контрастности

Присвоим диалогу идентификатор IDD_BRIGHT_CONT и создадим класс

CBrightContDlg, свяжем с элементами управления переменные. Для вызова диалога добавим в меню программы команду Edit | Brightness and Contrast, а в класс CBMDoc — метод обработки этой команды. В этом методе сначала создается диалог, и если пользователь нажал кнопку OK, то инициализируется фильтр «Яркость/Контраст» (объект m_BrightContFilter класса

CBrightCont описан в интерфейсе класса CBMDoc). Затем фильтр делается активным и вызывается фильтрующая функция — метод

CBMDoc::Transform().

void CBMDoc::OnEditBrightnessandcontrast()

{

CBrightContDlg BCDlg; if(BCDlg.DoModal()==IDCANCEL) return;

if(BCDlg.m_iBrightnessOffset!=0 || BCDlg.m_iContrastOffset!=0)

{

m_BrightContFilter.Init(BCDlg.m_iBrightnessOffset, BCDlg.m_iContrastOffset);

m_pCurFilter=&m_BrightContFilter;

Transform();

}

}

145

Посмотрим же на эффект, который дает фильтр яркости и контрастности. Попробуем сначала немного увеличить яркость фотографии, показанной на рис. 11. На рис. 15 показана та же фотография, яркость половины которой увеличена на 30 единиц3 коррекции.

Рис. 15. Фотография после коррекции яркости

Гистограмма этой же картинки (если преобразование применено ко всей ее площади) показана на рис. 16. Видно, что по сравнению с гистограммой (рис. 11), она сместилась в область светлых тонов.

Рис. 16. Гистограмма яркости фотографии после коррекции яркости

3 Диапазоном коррекции считаем половину диапазона яркости (255/2=127), но на ползунке он представлен значением

MAX_CORRECTION_OFFSET. Поэтому 1 единица коррекции равна 127/MAX_CORRECTION_OFFSET.

Это просто особенность программной реализации.

146

Продолжим редактирование этой фотографии и попробуем изменить контрастность изображения, для этой цели можно, конечно, воспользоваться услугами коррекции контрастности диалога «Гистограмма», но можно испытать и новые средства. Увеличим контраст на 20 единиц коррекции. Результат показан на рис. 17.

Рис. 17. Фотография после коррекции контраста

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

Рис. 18. Гистограмма яркости фотографии после коррекции яркости и контраста

147

6.7 Фильтр «Инверсия цветов»

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

CInvertColors:

// Инверсия цветов

class CInvertColors: public CDotFilter

{

public:

CInvertColors();

};

Операция инверсии цветов не требует никаких настроечных параметров, поэтому инициализация таблиц преобразования выполняется в конструкторе класса:

CInvertColors::CInvertColors()

{

for(int i=0, t=0; t<3; t++)

for(i=0; i<256; i++)

BGRTransTable[t][i]=255-i;

};

Вот это фильтр — такой простой, а какой эффект!

148

Рис. 19. Половина изображения обработана фильтром "Инверсия"

Конечно, как и для прочих фильтров, в классе CBMDoc завели объект класса CInvertColors, а в меню добавили соответствующую команду и в класс CBMDoc метод-обработчик. В общем, все, как у всех.

6.8 Фильтр «Рельеф»

Рассмотрим еще один точечный фильтр, который, однако, может быть отнесен и к пространственным (а если хорошенько присмотреться, то в нем можно заметить признаки и покадрового, и геометрического процессов). Этот фильтр может быть реализован с использованием матриц или без их применения. Мы рассмотрим вариант без использования матриц. Эффект, создаваемый фильтром, может быть сравнен с высеканием рельефа на камне. Этот фильтр можно найти во многих графических редакторах (англоязычный вариант названия — Emboss).

149

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

Фильтр «Рельеф» реализован классом CEmboss:

// Фильтр - Рельеф

class CEmboss: public CDotFilter

{

public:

BOOL TransformPix(LONG x, LONG y);

};

Из-за того, что преобразование в фильтре CEmboss отличается от точечного, пришлось переопределить метод CDotFilter::TransformPix(). Вот одно из достоинств объектноориентированного стиля — больше ничего менять не пришлось. Вся остальная схема работы с фильтром осталась без изменений.

Ниже приведена реализация метода TransformPix(). Константы

STONE_OFFSET_X и STONE_OFFSET_Y задают расстояние и направление смещения вычитаемого пиксела и влияют на получаемый эффект. Можно создать диалог, в котором этими параметрами можно было бы «поиграть». В приведенной реализации функции CEmboss::TransformPix() всем компонентам цвета задается одинаковая интенсивность. Это тоже необязательно, можно окрашивать результат в любые оттенки, как это сделано, например, в редакторе Ulead Photoimpact.

#define STONE_OFFSET_X 3 #define STONE_OFFSET_Y -3

BOOL CEmboss::TransformPix(LONG x, LONG y)

{

BYTE *pDPix=NULL, *pSPix1=NULL, *pSPix2=NULL; if(m_pSourceBM==NULL|| m_pDestBM==NULL)

return FALSE;

150

// Получаем указатели на пикселы в источнике и приемнике if((pDPix=m_pDestBM->GetPixPtr(x, y))==NULL ||

(pSPix1=m_pSourceBM->GetPixPtr(x,y))==NULL) return FALSE;

if ((pSPix2 = m_pSourceBM->GetPixPtr (x+STONE_OFFSET_X, y+STONE_OFFSET_Y))==NULL)

pSPix2=pSPix1; // Расчет яркости

BYTE Y1, Y2;

Y1=(BYTE)(0.11*(*pSPix1) + 0.59*(*(pSPix1+1)) + 0.3*(*(pSPix1+2)));

Y2=(BYTE)(0.11*(*pSPix2) + 0.59*(*(pSPix2+1)) + 0.3*(*(pSPix2+2)));

// Находим разницу и смещаем ее в серую область

BYTE d=(Y1-Y2+255)/2;

// Пиксел получает новые значения

*pDPix=d;

*(pDPix+1)=d;

*(pDPix+2)=d; return TRUE;

};

Результат применения фильтра показан на рис. 20.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]