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

GMSAPR

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

131

//преобразования. Это требуется для обработки

//пикселов, находящихся на границах изображения

int x_start=0; int y_start=0;

int dx=m_rangX/2, dy=m_rangY/2; if(x-dx<0) x_start=dx-x; if(y-dy<0) y_start=dy-y;

int x_finish=m_rangX; if(x+dx>m_pSourceBM->GetBMWidth())

x_finish-=(x+dx-m_pSourceBM->GetBMWidth()); int y_finish=m_rangY; if(y+dy>m_pSourceBM->GetBMHeight() )

y_finish-=(y+dy-m_pSourceBM-> GetBMHeight());

//Расчет новых значений цвета пиксела с учетом соседей,

//попавших в зону действия матрицы преобразования

int NewBGR[3]; int count=0;

for(int c=0, mx=0, my=0; c<3; c++)

{

NewBGR[c]=0; count=0; for(my=y_start; my<y_finish; my++) for(mx=x_start; mx<x_finish; mx++)

{

if((pSPix=m_pSourceBM->GetPixPtr(x+ mx-dx), y+(my-dy)))!=NULL)

{

NewBGR[c]+=(m_pMatrix[my*m_rangX+mx] *

(*(pSPix+c)));

count+=m_pMatrix[my*m_rangX+mx];

}

}

}

// Адрес пиксела в изображении-приемнике pDPix=m_pDestBM->GetPixPtr(x, y);

132

// Установка нового значения в приемное изображение for(c=0; c<3; c++)

{// Приведение значения к допустимому диапазону

if(count!=0)

NewBGR[c]=NewBGR[c]/count;

if(NewBGR[c]<0)

NewBGR[c]=0;

else if(NewBGR[c]>255) NewBGR[c]=255;

*(pDPix+c)=NewBGR[c];

}

return TRUE;

};

В методе CMatrixFilter::TransformPix() сначала определяется область перекрытия изображения и матрицы преобразования. Этот шаг необходим в связи с тем, что на границах изображении пиксел может не иметь соседей с одной или двух сторон. На рис. 7 показаны некоторые ситуации, когда в преобразовании задействованы не все коэффициенты матрицы. Пикселу, над которым выполняется преобразование, соответствует индекс матрицы с номером 5.

Матрица на краю изображения

1 2 3

4 5 6

7 8 9

Матрица внутри изображения

1 2 3

4 5 6

7 8 9

Матрица на краю изображения

1 2 3

4 5 6

7 8 9

Рис. 7. Пересечение матрицы и изображения

133

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

6.5Использование гистограммы яркости для повышения контрастности изображения. Фильтр «Гистограмма»

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

Рис. 8. Изображение со слабой контрастностью

Гистограмма изображения с хорошим контрастом, как правило, равномерно занимает весь диапазон яркостей (рис. 9). Такие изображения, обычно, воспринимаются как более качественные.

134

Рис. 9. Изображение с хорошей контрастностью

В высококонтрастных изображениях также задействован весь диапазон яркостей, но гистограмма такого изображения может иметь пики, что связано с наличием больших зон темных и светлых пикселов (рис. 10).

Рис. 10. Изображение с высокой контрастностью

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

Мы можем попытаться исправить ситуацию, «растянув» яркость пикселов картинки на весь диапазон от 0 до 255. При этом пикселы, которые

135

были темными, станут еще темнее (вплоть до черного), а светлые пикселы станут еще светлее (вплоть до белого).

Шаблон окна диалога «Гистограмма» (IDD_HIST) имеет два ползунка (элементы Slider). Используем их для того, чтобы определить нижнюю и верхнюю границы диапазона значений яркости.

Прежде всего, добавим в класс CHistDlg обработку сообщения

WM_INITDIALOG. Сообщение WM_INITDIALOG посылается окну диалога перед тем, как оно будет показано на экране. В методе-обработчике этого сообщения установим начальные параметры ползунков и позиции «бегунков»:

BOOL CHistDlg::OnInitDialog()

{

CDialog::OnInitDialog();

m_ctrlOffset_b.SetRange(0, 127); // Ползунок нижней границы m_ctrlOffset_b.SetPos(0); // Крайнее левое положение

m_ctrlOffset_t.SetRange(128, 255); // Ползунок верхней границы m_ctrlOffset_t.SetPos(255); // Крайнее правое положение

// Текст m_strOffset_b="0"; m_strOffset_t="0"; UpdateData(FALSE); return TRUE;

}

Напомним, что переменные m_ctrlOffset_b и m_ctrlOffset_t

это объекты класса CSliderCtrl, связанные с ползунками, а m_strOffset_b и m_strOffset_t — объекты класса CString,

связанные с элементами «Static Text» в окне диалога.

Далее добавим в класс CHistDlg обработчики еще двух сообщений:

WM_HSCROLL, которое будет поступать при перемещении бегунка, и сообщения о нажатии пользователем кнопки OK в диалоге. При обработке сообщения WM_HSCROLL в окне диалога будет выводиться позиция бегунков.

136

При обработке сообщения «нажата кнопка OK» позиции бегунков запоминаются в переменных m_iOffset_b и m_iOffset_е. Эти переменные целого типа добавлены в класс CHistDlg специально для того, чтобы можно было извлечь из него информацию о позициях бегунков после закрытия окна диалога.

void CHistDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)

{

m_strOffset_b.Format("%d", m_ctrlOffset_b.GetPos()); m_strOffset_t.Format("%d", 255 -m_ctrlOffset_t.GetPos()); UpdateData(FALSE);

CDialog::OnHScroll(nSBCode, nPos, pScrollBar);

}

void CHistDlg::OnOK()

{

m_iOffset_b=m_ctrlOffset_b.GetPos(); m_iOffset_t=255-m_ctrlOffset_t.GetPos();

CDialog::OnOK();

}

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

Коррекция яркости — это точечный процесс. Поэтому создадим класс фильтра гистограмма CHistogram как производный от класса CDotFilter:

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

class CHistogram: public CDotFilter

{

public:

BOOL Init(int offset_b, int offset_t);

};

137

У этого класса объявлен всего один новый метод Init(), в который передаются смещения от нижней и от верхней границы диапазона яркостей. В методе Init() производится заполнение таблиц преобразования новыми значениями. При этом полный диапазон яркостей от 0 до 255 равномерно распределяется на заданный в диалоге «Гистограмма» диапазон.

BOOL CHistogram::Init(int offset_b, int offset_t)

{

int range=0;

//Все элементы в таблицах с индексом

//от 0 до нижней границы установим в 0 for(int i=0, t=0; t<3; t++)

for(i=0; i<offset_b; i++) BGRTransTable[t][i]=0;

//Все значения в таблицах с индексом

//от 255 до верхней границы установим в 255 for(t=0; t<3; t++)

for(i=255; i>=256-offset_t; i--) BGRTransTable[t][i]=255;

//Все значения в таблицах с индексом

//от нижней до верхней границы равномерно

//распределим на диапазон от 0 до 255 double step=256./(256-(offset_b+offset_t)); for(t=0; t<3; t++)

{

double value=0.;

for(i=offset_b; i<256-offset_t; i++)

{

BGRTransTable[t][i]=(int)((value)+0.5);

value+=step;

}

}

return TRUE;

};

138

После того, как пользователь нажал кнопку OK в диалоге «Гистограмма», мы проверяем «а не сдвинул ли он бегунки на ползунках». Если такое событие произошло, то мы инициализируем объект m_HistogramFilter (объявлен в интерфейсе класса CBMDoc) и делаем его активным, а затем вызываем метод

CBMDoc::Transform(), запускающий рабочий поток, в котором и происходит преобразование.

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

Рис. 11. Коррекция яркости

Результат коррекции яркости показан на рис. 12, а гистограмма изображения после коррекции на рис. 13. Для того чтобы эффект преобразования был лучше заметен, на рис. 12 показано изображение, лишь половина которого была преобразована. Мы помним, что метод CBMDoc::Transform() имеет такую возможность. Гистограмма же на рис. 13, соответствует полностью откорректированному изображению.

139

Рис. 12. Результат коррекции яркости

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

Мы рассмотрели процесс коррекции яркости вручную. Эту операцию можно выполнить и автоматически. При автоматической коррекции яркости алгоритм должен сначала найти границы корректируемого диапазона. Для этого нужно задать некоторое пороговое значение яркости (например, определить его от уровня средней яркости), а затем выполнить сканирование гистограммы изображения и найти индексы элементов гистограммы, значения которых находятся на заданном пороге, — определить диапазон коррекции. Далее коррекция выполняется точно так же, как и при «ручном» варианте.

Другими словами: назначим порог, к примеру, 10%. Сканируем гистограмму с левого края, и, как только попадается участок яркостью выше 10% - пододвигаем ползунок на эту позицию. То же самое и для правой стороны.

140

6.6 Фильтр «Яркость/Контраст»

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

Данное преобразование является точечным. Для его реализации добавим

впрограмму фильтр «Яркость/Контраст» — класс CBrightCont,

производный от класса CDotFilter. Интерфейс класса приведен ниже:

// Яркость-контраст

class CBrightCont: public CDotFilter

{

public:

BOOL Init(int b_offset, int c_offset);

};

Интерфейс класса CBrightCont ничем не отличается от CHistogram.

Однако значения b_offset и c_offset параметров метода

CBrightCont::Init(), могут быть как положительными, так и отрицательными, что будет соответствовать увеличению или уменьшению яркости/контрастности изображения.

Метод CBrightCont::Init() инициализирует таблицы преобразования. Сначала выполняется смещение яркости на заданную величину, а затем либо «сжатие», либо «растяжение» диапазона яркости. Причем, при сжатии значения яркости изменяются не равномерно, а пропорционально их удаленности от «серой середины», определенной константой CONTRAST_MEDIAN. Значение CONTRAST_MEDIAN 159 задает более светлый оттенок серого (чем, например, 255/2 = 127 — арифметическая середина диапазона яркости) и для многих изображений дает хороший результат. Вы можете поэкспериментировать со значением этой константы и

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