индекс
|
0
|
1
|
2
|
3
|
…
|
253
|
254
|
255
|
значение
|
255
|
254
|
253
|
252
|
…
|
2
|
1
|
0
|
Рисунок 2.4.1 - Таблица
преобразования "инверсия"
После
преобразования по формуле (V’= 255 - V) с использованием таблицы
интенсивность 255 будет заменена на 0, 254 - на 1 и т. д. В случае такого
простого преобразования, как инверсия цвета, использование таблицы может и не
дать особого выигрыша по скорости, но если новое значение пиксела должно
рассчитываться по более сложной формуле, чем в нашем случае, то выигрыш
будет весьма заметен. Кроме того, использование таблиц позволяет использовать
единообразный подход к осуществлению различных преобразований.
Пространственное преобразование заключается в
нахождении свертки значений группы пикселов. Свертка вычисляется как сумма
пиксельных значений, попавших в зону преобразования, помноженных на весовые
коэффициенты. В качестве весовых коэффициентов выступают элементы матрицы
преобразования. Значения элементов матрицы преобразования и определяют тип
преобразования. Размер матрицы преобразования соответствует области пикселов,
которые будут участвовать в преобразовании. Центральный элемент матрицы -
весовой коэффициент преобразуемого пиксела (х, у). Поэтому матрицы
преобразования, обычно имеют нечетный размер (например, 3x3 или 5x5 элементов).
Например, свертка с помощью единичной матрицы соответствует преобразованию
"размытие" (понижение четкости) изображения. Достигается такой эффект
за счет усреднения значений группы пикселов, охваченной матрицей
преобразования. Если значение пиксела (х, у) было выше среднего, оно
уменьшится, если было ниже среднего, то увеличится. Однако это не означает, что
все изображение станет монотонным, так как матрица преобразования движется по
изображению вместе с координатами (х, у), средний уровень тоже
изменяется.
3. ПРОСМОТР И РЕДАКТИРОВАНИЕ РАСТРОВЫХ ИЗОБРАЖЕНИЙ
3.1
Создание многодокументного приложения
С
помощью генератора приложений АррWizard создаём каркас приложения для просмотра
и редактирования рисунков.
- С
помощью команды File/New/Projects/MFC AppWizard (exe) начнем создание
приложения. Назовем проект ВМViewer.
- На
первом шаге выберем тип приложения Multiple documents.
- Далее
можно принять все установки по умолчанию.
3.2
Класс CRaster для работы с растровыми изображениями
Создаем
в программе класс CRaster, отвечающий за загрузку и осуществляющий поддержку
операций по обработке растрового изображения. Класс CRaster содержит два метода
DrawBitmap, выполняющих вывод изображения на контекст устройства. Аргументы
одного из методов позволяют задать положение и размеры выводимой области
исходного изображения и определить область назначения. По умолчанию изображение
выводится полностью в масштабе 1:1, однако с помощью аргументов этой функции
можно и изменить масштаб. Второй метод позволяет просто указать позицию начала
вывода и масштаб, в котором должно быть нарисовано изображение. Оба метода внутри
используют мощную АРI-функцию StretchDIBits().
Режим
масштабирования выбирается CDC-методом SetStretchBltMode():
int
SetStretchBltMode(int nStretchMode);
Аргумент
функции - nStretchMode - режим масштабирования. Поддерживаются следующие режимы
масштабирования:
-
BLACKONWHITE - выполняет булеву
операцию AND между цветом
существующих и удаленных пикселов (при уменьшении размера изображения). Этот
режим используется, если масштабируется рисунок "черным по белому",
т. е. алгоритм масштабирования будет стараться сохранить черные пикселы;
-
COLORNCOLOR - этот режим удаляет (добавляет) строки (столбцы) пикселов без
каких-либо попыток сохранить содержащуюся в них информацию. Наиболее быстрый
режим. Используется, когда необходимо сохранить цвета изображения неизменными;
- WHITEONBLACK - выполняет булеву операцию OR. Этот режим используется,
если масштабируется рисунок "белым по черному";
- HALFTONE - преобразует изображение к заданному размеру и при этом
трансформирует цвета так, чтобы средний цвет полученной картинки приближался к
исходному цвету. Наиболее медленный режим. Однако масштабированная картинка
выглядит лучше за счет сглаживания "лестничного эффекта". Этот режим
не работает в Windows 95/98, и, похоже, заменяется режимом COLORNCOLOR.
При
масштабировании фотографий и цветных рисунков в большинстве случаев наиболее
подходящим является режимы COLORNCOLOR и HALFTONE
.
Чтобы
можно было изменять масштаб вывода изображений, добавим в меню View программы
команды Zoom In, Zoom Out, а для установки режима масштабирования – команды
Stretch HALFTONE, Stretch COLORNCOLOR. Обработчики этих команд добавим в класс
облика (листинг 3.2.1). Эти функции изменяют состояние переменных m_dScale и
m_nStretchModeстановки режимов масштабирования также добавлены методы
OnUpdateViewStretchhalftone() и OnUpdateViewStretchcoloroncolor() для обработки
сообщения UPDATE_COMMAND_UI. В этих функциях можно управлять состоянием
соответствующих команд в интерфейсе программы (например, можно делать
недоступными команды в зависимости от состояния программы). В данном случае мы
просто маркируем соответствующий режим масштабирования.
Листинг
3.2.1 – Обработка команд масштабирования. Файл BMView.cpp
void
CBMView::OnViewZoomin()
{//
TODO: Add your command handler code here
m_dScale*=2;
OnUpdate(NULL,
0, NULL); }
void
CBMView::OnViewZoomout()
{//
TODO: Add your command handler code here
m_dScale/=2;
OnUpdate(NULL,
0, NULL); }
void
CBMView::OnViewStretchhalftone()
{//
TODO: Add your command handler code here
m_nStretchMode=HALFTONE;
OnUpdate(NULL,
0, NULL); }
void
CBMView::OnUpdateViewStretchhalftone(CCmdUI* pCmdUI)
{//
TODO: Add your command update UI handler code here
pCmdUI->SetCheck(m_nStretchMode==HALFTONE);
}
void
CBMView::OnViewStretchcoloroncolor()
{//
TODO: Add your command handler code here
m_nStretchMode=COLORONCOLOR;
OnUpdate(NULL,
0, NULL); }
void
CBMView::OnUpdateViewStretchcoloroncolor(CCmdUI* pCmdUI)
{//
TODO: Add your command update UI handler code here
pCmdUI->SetCheck(m_nStretchMode==COLORONCOLOR);}
3.3
Модификация класса документа для обеспечения работы с изображениями
Поскольку
данными в нашей программе будут изображения, модифицируем класс документа так,
чтобы он умел работать с изображениями. В проект приложения добавим файлы
Raster.h, Raster.cpp. В классе документа надо определить данные как объекты
класса СRaster. В принципе, для целей показа картинки на экране хватит и одного
объекта СRaster. Чтобы наделить программу некоторыми возможностями по
редактированию изображений потребуется не один, а, как минимум, два объекта:
один для хранения исходной картинки, второй - буфер для приема преобразованной
картинки.
Порядок
работы с двумя объектами СRaster в этом случае будет выглядеть следующим
образом:
-
Загружаем изображение в первый объект СRaster и показываем его наэкране до тех
пор, пока пользователь не даст команду выполнить какие-нибудь изменения
изображения.
-
Помещаем измененное изображение во второй объект СRaster и начинаем показывать
второй объект-картинку.
- Может
случиться так, что пользователю не понравится то, как мы изменили его картинку,
тогда он отдает команду "Отменить преобразования".При этом меняются
объекты местами.
3.4
Программная схема выполнения преобразований. Графические фильтры
Поскольку
следует реализовать целый ряд процедур преобразования изображений, необходимо
предусмотреть, как они будут уживаться между собой и взаимодействовать с
остальными модулями программы. В мультимедийном программировании широко
распространена концепция фильтров. Фильтр - это некоторая программа, которая,
пропуская через себя данные, преобразует их некоторым образом. В нашем случае
данными являются значения цветов пикселов изображения. Представим, что у нас
имеется набор фильтров, пропуская через которые данные изображения мы можем
добиваться различных эффектов (рис. 3.6.1).
Для того
чтобы получить нужный эффект, достаточно просто указать программе, какой фильтр
считать активным. В программе должна существовать "фильтрация" -
процедура, в которой будет выполняться само пропускание данных через фильтр.
Фильтры
можно реализовать в виде классов, производных от какого-то одного базового
класса. В базовом классе следует определить набор методов, общих для всех
фильтров. В программе заведем переменную - указатель на активный фильтр.
Используя этот указатель, "фильтрация" будет обращаться к нужному
фильтру.
Рисунок
3.6.1 - Схема использования фильтров для преобразования изображений
Саму
фильтрацию изображения можно выполнять по-разному. Например, можно передать
фильтру всю исходную картинку и ожидать от него уже полностью преобразованного
изображения. А можно пропускать через фильтр исходное изображение по одному
пикселу. В последнем случае не придется дублировать цикл обработки всего
изображения в каждом фильтре, и вызывающая фильтр процедура получит полный
контроль над областью изображения, к которой будет применено преобразование.
Реализуем
на практике второй способ организации "фильтрации". При этом сам процесс
преобразования изображения вынесем в отдельный поток (назовем его
"рабочим" потоком) выполнения программы. Это даст нам возможность
контролировать не только область применения фильтра, но и продолжительность
выполнения операции, т.е. возможность остановить выполнение
"фильтрации". Общая схема преобразования в этом случае будет
выглядеть следующим образом:
1. Пришла команда выполнить
преобразование - создаем рабочий поток.
2. Уведомляем объекты-облики о том, что начали
преобразование. Приэтом облик запускает таймер и начинает периодически
интересоваться,сколько процентов работы выполнено, показывая пользователю
процентвыполнения.
3. В рабочем потоке выполняется
преобразование и увеличивается процент выполнения.
4. По окончании преобразования (или если
пользователь прервал выполнение) в объекты-облики посылаются сообщения о
завершении работы ипоказывается преобразованная картинка.
Поскольку
данными в программе ВМViewer заведует класс CBMDoc, именно в него и поместим "фильтрацию". Для
создания рабочего потока потребуется добавить в класс CBMDoc несколько методов:
Transform()
- создает рабочий поток;
ThreadProc
() - функция потока, запускает "фильтрацию" для конкретного
объекта-документа;
TransformLoop()
- сама "фильтрация";
InformAllViews()
- передает сообщения всем обликам документа; Рассмотрим метод TransformLoop()
(Листинг 3.6.1).
Листинг
3.6.1 – Метод CBMDoc::TransformLoop(). Файл BMDoc.cpp
void
CBMDoc::TransformLoop()
{if(m_pCurFilter==NULL)
return;
if(!CreateCompatibleBuffer())
return;
m_EventDoTransform.SetEvent();
m_bEditable=FALSE;
InformAllViews(UM_STARTTRANSFORM);
CRaster*pSBM=GetCurrentBMPtr(),//источник
*pDBM=GetBufferBMPtr();//
приёмник
//
Установили в фильтр источник и приёмник преобразований
m_pCurFilter->SetBuffers(pSBM,
pDBM);
for(LONG
y=0; y<pSBM->GetBMHeight(); y++)
{//
Процент выполнения
InterlockedExchange(&m_lExecutedPercent,
100*y/pSBM->GetBMHeight());
//Проверка
не решили ли прервать преобразование
if(!m_EventDoTransform.Lock(0))
{InformAllViews(UM_ENDOFTRANSFORM,
FALSE, 0);
m_bEditable=TRUE;
return; }
LONG
x=0;
//
Преобразование с использованием текущего фильтра
for(;
x<pSBM->GetBMWidth(); x++)
m_pCurFilter->TransformPix(x,
y); }
m_EventDoTransform.ResetEvent();
m_bEditable=TRUE;
SwapBM();//Сделать
буфер текущим изображением
SetModifiedFlag();
//флаг “данные изменились”
InformAllViews(UM_ENDOFTRANSFORM,
TRUE, 0);
return;
};
В методе
TransformLoop() мы сначала "зажигаем" событие "Выполняется
преобразование" - объект m_EventDoTransform класса CEvent. Затем сообщаем
текущему фильтру, какое изображение будет исходным, и какое - приемным (адреса
объектов CRaster). Далее в цикле прогоняем через фильтр пикселы изображения. На
текущий фильтр указывает переменная m_pCurFilter, которую мы завели в классе
CBMDoc специально для этих целей. Тип этой переменной - указатель на объект
класса CFilter. Преобразование же данных выполняется с помощью метода
Cfilter::TransformPix(), Класс СFilter как раз и является базовым для всех
фильтров.
В
процессе преобразования перед обработкой очередной строки пикселов вычисляется
процент выполнения как процент уже обработанных строк изображения. Вычисленное значение
записывается в переменную m_lExecutedPercent с помощью API-функции
InterlockedExchange() - эта функция позволяет предотвратить одновременное обращение
к переменной из разных потоков. Далее проверяется, по-прежнему ли установлено
событие m_EventDoTransform. И только затем обрабатываются пикселы строки.
Причем в нашей программе в иллюстрационных целях мы позволяем пользователю
посмотреть эффект преобразования на половине изображения. Если установлен флаг
m_bEditHalf, первая половина строки копируется в неизменном виде.
После
того как все пикселы изображения были обработаны, скидывается флаг
m_EventDoTransform, буферное изображение становится активным и во все облики
направляется сообщение UM_ENDOFTRANSFORM
с параметром TRUE, который
говорит о том, что преобразование завершилось и надо обновить изображение в
окне облика.
Для
контроля количества выполненной работы фильтра в класс CBMView с помощью ClassWizard
добавим метод OnTimer(). В этом методе будет выполняться запрос процента
выполнения операции и обновляться информация о выполнении. Процент выполнения
операции отображается в заголовке окна облика.
Приход
сообщения UM_ENDOFTRANSFORM обрабатывается методом OnEndTransform(), который
зависит от значения аргумента wParam:
-
TRUE - преобразование успешно закончено -
выполняет обновление экрана;
-
FALSE
- пользователь прервал
операцию - не выполняет обновление экрана. Далее им вызывается функция
OnStopTimer(), которая разрушает таймер.
Выделение
операций обработки данных, которые могут выполняться длительный отрезок
времени, в отдельный поток позволяет пользователю сохранить контроль над
выполнением программы. В нашем приложении пользователь, запустив фильтрацию на
одном из открытых изображений, может переключиться на просмотр и
редактирование другого изображения. При необходимости пользователь может
остановить выполнение преобразования, для этого в программе предусмотрим
команду, которая бы сбрасывала флаг m_EventDoTransform. При сбросе этого флага
цикл выполнения преобразования СВМDос::ТгаnsformLoop() прерывается, потоковая
функция завершается и рабочий поток прекращает свое существование.
3.5
Класс “Фильтр”
Выполнение
задачи подразумевает существование в программе некоторого объекта-фильтра.
Фильтры выполняют разные преобразования, но с точки зрения
"фильтрации" они все одинаковы и обращаться с ними она будет
единообразно. Поэтому нам надо определить базовый класс CFilter для фильтра с
минимальным, но основным набором методов, с помощью которых будет происходить
общение. Данные класса - два указателя на объекты-картинки класса Craster:
-
m_рSourseBM - адрес объекта "исходная картинка", откуда берутся
данные для преобразования;
-
m_рDestBM - адрес объекта "приемная картинка", куда помещаются
преобразованные данные.
Методы
класса:
-
SetBuffers () - сообщает фильтру адреса исходного и приемного изображения;
- TransformPix() – преобразует данные одного пиксела с координатами (x,y).
Переменная-указатель на этот класс m_pCurFilter заведена в классе CBMDoc. Этой
переменной присваивается адрес текущего фильтра.
Для
реализации точечных методов преобразования создаём класс CdotFilter (Листинг
3.7.1).
Листинг
3.7.1 – Базовый класс для точечных фильтров CdotFilter. Файл Filter.h
//Базовый
класс для точечных фильтров
class
CDotFilter: public CFilter
{
protected:
//Таблицы
преобразования для компонентов цвета
BYTE
BGRTransTable[3][256];
public:
//Метод
преобразования пиксела
BOOL
TransformPix(LONG x, LONG y);};
Данными
этого класса являются три таблицы преобразования компонентов RGB цвета.
Для
точечного фильтра переопределён метод . Реализация метода приведена в листинге
3.7.2
Листинг
3.7.2 – Метод CDotFilter:: TransformPix (). Файл Filter.cpp
BOOL
CDotFilter::TransformPix(LONG x, LONG y)
{BYTE
*pDPix=NULL, *pSPix=NULL;
//
Источник необходим
if(m_pSourceBM==NULL)
return
FALSE;
//Если
приёмник не задан, то преобразование помещаем в источник
if(m_pDestBM==NULL)
m_pDestBM=m_pSourceBM;
//
Получаем указатели на пикселы в источнике и приёмнике
if((pDPix=m_pDestBM->GetPixPtr(x,
y))==NULL ||
(pSPix=m_pSourceBM->GetPixPtr(x,
y))==NULL)
return
FALSE;
//
Преобразование. Порядок BGR
*pDPix=BGRTransTable[0][*pSPix];
*(pDPix+1)=BGRTransTable[1][*(pSPix+1)];
*(pDPix+2)=BGRTransTable[2][*(pSPix+2)];
return
TRUE; };
Хотя
формат 24-битового цвета называют RGB, в файле формата BMP компоненты цвета
хранятся в обратном порядке (Порядок BGR).
В
производных от CDotFilter классах останется реализовать инициализацию таблиц
преобразования.
Для реализации
пространственных (матричных) методов преобразования создаём класс
CMatrixFilter. Интерфейс класса приведён в листинге 3.7.3
Листинг 3.7.3 – Интерфейс
базового для матричных фильтров класса CmatrixFilter. Файл Filter.h
// Пространственные
(матричные фильтры)
// Базовый класс
class CMatrixFilter:
public CFilter
{
protected:
int m_rangX; // размер
матрицы по X и Y
int m_rangY;
const int *m_pMatrix; //
указатель на матрицу
public:
//Методпреобразования пиксела
BOOL TransformPix(LONG x,
LONG y); };
Данными этого класса
являются размер матрицы преобразования и указатель на матрицу. Размер мртрицы
определяет зону пикселов, окружающих пиксел (x,y), которая будет вовлечена в
расчёт нового значения пиксела (x,y). Указателю на матрицу преобразования
m_pMatrix будет присваиваться адрес матрицы, которая будет использована в
преобразовании. Реализация метода CmatrixFilter:: TransformPix() приведена в
листинге3.7.4
Листинг 3.7.4 – Метод
CmatrixFilter:: TransformPix(). Файл Filter.cpp
// Пространственные
фильтры
BOOL
CMatrixFilter::TransformPix(LONG x, LONG y)
{BYTE *pDPix=NULL,
*pSPix=NULL;
// Источник и приёмник
необходимы
if(m_pSourceBM==NULL ||
m_pDestBM==NULL)
return FALSE;
// Определяем зону
перекрытия изображения и матрицы. Это требуется для //обработки пикселов,
находящихся на границах изображения
int x_start=0;
int dx=m_rangX/2,
dy=m_rangY/2;
if(x-dx<0)
x_start=dx-x;
int y_start=0;
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);
//Установка нового
значения в приёмное изображение
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() сначала определяется область перекрытия изображения и матрицы
преобразования. Этот шаг необходим в связи с тем, что на границах изображения
пиксел может не иметь соседей.
Новое
значение пиксела формируется с учетом значений всех пикселов и коэффициентов
матрицы преобразования, попавших в область перекрытия изображения и матрицы
преобразования.
3.6 Фильтр “Яркость/Контраст”
Изменение
яркости заключается в изменении интенсивности цвета всех пикселов на заданное
значение. Данное преобразование является точечным. Для его реализации добавим в
программу класс CBrightCont, производный от класса CDotFilter. Интерфейс класса
приведён в листинге 3.6.1
Листинг
3.6.1 – Интерфейс класса CBrightCont. Файл Filter.h
//
Яркость/контраст
class
CBrightCont: public CDotFilter
{
public:
BOOL
Init(int b_offset, int c_offset);
};
Переменные
b_offset, c_offset – это объекты, связанные с ползунками, могут принимать
положительные и отрицательные значения, что соответствует увеличению или
уменьшению яркости/контрастности изображения.
Реализация
метода CBrightCont::Init() приведена в листинге 3.6.2 Этот метод инициализирует
таблицы преобразования. Сначала выполняется смещение яркости на заданную
величину, а затем либо "сжатие", либо "растяжение"
диапазона яркости. Причем при сжатии значения яркости изменяются не равномерно,
а пропорционально их удаленности от "серой середины", определенной
константой CONTRAST_MEDIAN. После преобразования яркости работа по коррекции
контрастности происходит со значениями таблицы преобразования, полагая при
этом, что они являются индексами в таблице, полученной после коррекции яркости.
Листинг
3.6.2 – Метод CBrightCont::Init().Файл Filter.cpp
//
"Серая середина" –уровень 159
#define
CONTRAST_MEDIAN 159
BOOL
CBrightCont::Init(int b_offset, int c_offset)
{int
i=0,//Индекс цвета в таблице преобразований
t=0,//Индекс
таблицы
//Индекс
цвета, соответствующего нижней границе яркости
t_index=0,
//
Индекс цвета, соответствующего верхней границе яркости
b_index=0,
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; }
//
Изменяем контрастность
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; }
}
elseif(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; }
//
Расчёт верхней границы цвета
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; };
3.7 Фильтр “Инверсия”
Этот фильтр реализуется с помощью таблицы преобразований. Для его
реализации добавим в программу класс CInvertColors (листинг 3.7.1), производный
от класса CDotFilter.
Листинг
3.7.1 – Интерфейс класса CInvertColors.Файл Filter.h
//Инверсия
цветов
class
CInvertColors: public CDotFilter
{
public:
CInvertColors();
};
Операция
инверсии цветов не требует никаких настроечных параметров, поэтому
инициализация таблиц преобразования выполняется в конструкторе класса (листинг
3.7.1).
Листинг
3.7.1 – Конструктор класса CInvertColors .Файл Filter.cpp
CInvertColors::CInvertColors()
{for(int
i=0, t=0; t<3; t++)
for(i=0;
i<256; i++)
{BGRTransTable[t][i]=255-i;
}
};
3.8 Фильтр “Размытие”
Фильтр
"Размытие" - это уже пространственное преобразование. Применение
этого фильтра оказывает эффект сглаживания деталей изображения. Фильтр
реализуется классом CВlur (листинг 3.8.1)
Листинг
3.8.1 – Интерфейс класса CBlur. Файл Filter.h
class
CBlur: public CMatrixFilter
{public:
CBlur();
};
Листинг
3.8.2 – Конструктор класса CBlur.Файл Filter.cpp
const
int BlurMatrix[25]=
{1,1,1,
1,1,
1,1,1,
1,1,
1,1,1,
1,1,
1,1,1,
1,1,
1,1,1,
1,1
};
CBlur::CBlur()
{m_pMatrix=BlurMatrix;
m_rangX=5;
m_rangY=5;
};
Матрица
BlurMatrix задаёт преобразование “Размытие”, а в конструкторе CBlur()
запоминается её адрес и размер.
3.9 Фильтр “Резкость”
Для
повышения четкости изображения в фильтре используется матрица
"Размытие". Задача повышения четкости изображения заключается в том,
чтобы выделить высокочастотные детали изображения. Светлые детали сделать ярче,
темные - темнее. Для этого изображение сначала размывается, а затем
определяется разность между размытым изображением и оригиналом. На величину
этой разницы изменяется яркость оригинала. Таким образом, однородные участки
изображения не подвергнутся изменениям, а те места картинки, где присутствуют
высокочастотные детали, станут конрастнее. Фильтр реализуется классом CSharp
(листинг 3.9.1).
Листинг
3.9.1 – Интерфейс класса CSharp. Файл Filter.h
class
CSharp: public CMatrixFilter
{
public:
CSharp();
BOOL
TransformPix(LONG x, LONG y); };
В классе
CSharp переопределён метод TransformPix(), реализация метода приведена в
листинге 3.9.1.
Листинге
3.9.1 – Методы класса CSharp. Файл Filter.cpp.
CSharp::CSharp()
{
m_pMatrix=BlurMatrix;
m_rangX=5;
m_rangY=5;
};
//
коэффициент увеличения резкости
#define
SHARP_COEFF 3
BOOL
CSharp::TransformPix(LONG x, LONG y)
{
//Размыли пиксел
if(!CMatrixFilter::TransformPix(x,
y))
return
FALSE;
BYTE
*pDPix=NULL, *pSPix=NULL;
pSPix=m_pSourceBM->GetPixPtr(x,y);
pDPix=m_pDestBM->GetPixPtr(x,
y);
int d=0;
for(int
c=0; c<3; c++)
{ //
Нашли разницу
d=*(pSPix+c)-*(pDPix+c);
//
Усилили разницу
d*=SHARP_COEFF;
//
Присвоили пикселу новое значение
if(*(pDPix+c)+d
<0)
*(pDPix+c)=0;
else
if(*(pDPix+c)+d
> 255)
*(pDPix+c)=255;
else
*(pDPix+c)+=d;}
return
TRUE; }
4. ИНСТРУКЦИЯ ПОЛЬЗОВАТЕЛЯ
Запуск программы
осуществляется при открытии файла BMViewer.exe. На экране появляется окно,
представленное на рисунке 4.1.
Рисунок 4.1 – Главное
окно программы
Выбрав в меню Файл/Открыть…
пльзователь выбирает файл, который следует открыть. Одновременно может быть
открыто несколько файлов. С помощью пункта меню Файл/Сохранить сохраняется
текущий вид изображения. Пункт меню Файл/Сохранить… позволяет сохранить текущий
вид изображения под новым именем.
Пункты меню Вид/Масштаб In,
Масштаб Out позволяют увеличивать/уменьшать масштаб изображения (Рисунок 4.2).
Рисунок 4.2 –
Масштабирование изображения.
Пункты меню Правка/…
позволяют корректировать открытое изображение при помощи фильтров:
Яркость/Контраст (Brightness/Contrast), Резкость (Sharp), Размытие (Blur),
Инверсия (Inverse) представлены на рис.4.3.
Рисунок 4.3 –Пункты меню
Правка
Применение фильтра Размытие
оказывает эффект сглаживания деталей изображения. Фильтр целесообразно
использовать для повышения качества изображения низкого разрешения. Границы
пикселов становятся менее чёткими, сглаживается «шум», что зрительно улучшает
качество изображения. Результат применения фильтра представлен на рисунке 4.4.
Фильтр Резкость
целесообразно применять при работе с изображением, в котором присутствует
большое количество мелких повторяющихся деталей не низкого качества: например, рисунок
на ткани или шерсть животных. Применение в этих случаях фильтра Резкость даёт
нам в результате изображение, наиболее приближённое к оригиналу. Фильтр Резкость
зачастую применяют в рекламной полиграфии для преувеличенного выделения
отдельных деталей изображения, на которых следует сделать акцент. Результат
применения фильтра представлен на рисунке 4.5.
Фильтр Яркость/Контраст
- наиболее часто применяется для цветокоррекции слишком затемнённых
изображений. Сначала следует увеличить яркость изображения, затем повысить
контрастность. Как правило, контрастность в этом случае следует увеличить
немного меньше, чем яркость. Результат применения фильтра представлен на
рисунке 4.6.
Фильтр Инверсия инвертирует
цвета изображения, что даёт явно заметный, яркий результат. Этот эффект можно
использовать для любителей креативного, гипертрофированно яркого дизайна.
Применение фильтра представлено на рисунке 4.7.
Рисунок 4.4 – результат
применения фильтра Размытие
Рисунок 4.5 – результат
применения фильтра Резкость (с масштабом)
Рисунок 4.6 – результат
применения фильтра Яркость/Контраст
Рисунок 4.7
– результат применения фильтра Инверсия
ЗАКЛЮЧЕНИЕ
В ходе выполнения данного
дипломного проекта было разработано программное обеспечение для открытия и фильтрации
растровых изображений при помощи графических фильтров, основанных на
пространственных и точечных преобразованиях.
Систематизированы и
закреплены практические навыки использования ЭВМ, программного обеспечения,
существующих графических редакторов, работающих с растровой графикой, а также
теоретические знания по курсу “Технология программирования гибких
компьютеризированных систем” .
ПЕРЕЧЕНЬ ССЫЛОК
1.
Поляков А.Ю.,
Брусенцев В.А. Методы и алгоритмы компьютерной графики в примерах на Visual
C++, 2-е изд., перераб. и доп. – СПб.: БХВ-Петербург, 2003. – 560 с.
2.
Мюррей Д., Райпер
У. Ван. Энциклопедия форматов графических файлов/пер. с англ. – К.: BHV, 1997.
– 672 с.
3.
Холзнер С. Visual
C++ 6: учебный курс – СПб: Питер, 2001. – 576 с.
4.
Шилдт Г.
Справочник программиста по С/С++.: Пер. с англ. – М.: Издательский дом
«Вильямс», 2001. – 448 с.
5.
Круглински Д.,
Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.0 для
профессионалов/Пер. с англ. - СПб: Питер; М.:Издательско-торговый дом
"Русская Редакция", 2003. - 864 с.
6.
Глушаков С.В.,
Коваль А.В., Черепнин С.А. Программирование на Visual C++ 6.0. – Харьков:
Фолио, 2002.- 726 с.
ПРИЛОЖЕНИЕ
Листсинг программы
// BMDoc.cpp :
implementation of the CBMDoc class
//
#include
"stdafx.h"
#include
"BMViewer.h"
#include
"BMDoc.h"
#include
"HistDlg.h"
#include
"BrightContDlg.h"
#include
"DeNoiseDlg.h"
#include
"BMView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] =
__FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CBMDoc
IMPLEMENT_DYNCREATE(CBMDoc,
CDocument)
BEGIN_MESSAGE_MAP(CBMDoc,
CDocument)
//{{AFX_MSG_MAP(CBMDoc)
ON_COMMAND(ID_EDIT_UNDO,
OnEditUndo)
ON_COMMAND(ID_EDIT_BRIGHTNESSANDCONTRAST,
OnEditBrightnessandcontrast)
ON_COMMAND(ID_EDIT_INVERTCOLORS,
OnEditInvertcolors)
ON_COMMAND(ID_EDIT_BLUR,
OnEditBlur)
ON_COMMAND(ID_EDIT_SHARP,
OnEditSharp)
ON_UPDATE_COMMAND_UI(ID_EDIT_BLUR,
OnUpdateEditBlur)
ON_UPDATE_COMMAND_UI(ID_EDIT_SHARP,
OnUpdateEditSharp)
ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO,
OnUpdateEditUndo)
ON_UPDATE_COMMAND_UI(ID_EDIT_BRIGHTNESSANDCONTRAST,
OnUpdateEditBrightnessandcontrast)
ON_UPDATE_COMMAND_UI(ID_EDIT_INVERTCOLORS,
OnUpdateEditInvertcolors)
ON_COMMAND(ID_EDIT_STOP,
OnEditStop)
ON_UPDATE_COMMAND_UI(ID_EDIT_STOP,
OnUpdateEditStop)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CBMDoc
construction/destruction
CBMDoc::CBMDoc():m_EventDoTransform(FALSE,
TRUE)
{
// TODO: add one-time
construction code here
m_pCurBM=NULL;
m_bEditable=FALSE;
m_pCurFilter=NULL;
}
CBMDoc::~CBMDoc()
{
}
BOOL
CBMDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add
reinitialization code here
// (SDI documents will
reuse this document)
return TRUE;
}
// Адрес пикселя
pCurPix=m_pData+y*DataStrLength+x*3;
// Яркость рассчитывается
как 0.3*Red+0.59*Green+0.11*Blue,
// но пиксельные данные
хранятся в файле BMP, в порядке BGR
Brightness=(BYTE)((0.11*(*pCurPix)
+
0.59*(*(pCurPix+1))+
0.3*(*(pCurPix+2)))*Range/256);
pHist[Brightness]+=1;
}
return TRUE;
};
// stdafx.cpp : source
file that includes just the standard includes
//BMViewer.pch will be
the pre-compiled header
//stdafx.obj will contain
the pre-compiled type information
#include
"stdafx.h"
// BMDoc.h : interface
of the CBMDoc class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_BMDOC_H__0CC04D31_A879_4674_AAD5_292699AE7BA7__INCLUDED_)
#define
AFX_BMDOC_H__0CC04D31_A879_4674_AAD5_292699AE7BA7__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER >
1000
#include <afxmt.h>
#include
"Raster.h"
#include
"Filter.h"
#define
UM_STARTTRANSFORMWM_USER+0x8000
#define
UM_ENDOFTRANSFORMUM_STARTTRANSFORM+1
class CBMDoc : public
CDocument
{
protected: // create from
serialization only
CBMDoc();
DECLARE_DYNCREATE(CBMDoc)
// Attributes
public:
// Флаги
BOOLm_bEditable;// можем
ли редактировать данные
CEventm_EventDoTransform;
// событие - выполняется преобразование
// Статистика
LONGm_lExecutedPercent;
// Данные
CRaster m_BM[2];// два
буфера для изображений
CRaster *m_pCurBM;//
указатель на активный буфер
//Фильтры
CFilter*m_pCurFilter;
CBrightCont
m_BrightContFilter;
CInvertColors
m_InvertColorsFilter;
CBlurm_BlurFilter;
CSharpm_SharpFilter;
// Operations
public:
CSize GetCurrentBMSize();
//Возвращает номер
активного буфера
intGetNCurrentBM();
//Возвращает указатель на
текущую картинку
CRaster*
GetCurrentBMPtr();
//Возвращает указатель на
буфер
CRaster*
GetBufferBMPtr();
//Поменять текущее
изображение и буффер местами
void SwapBM();
//Нарисовать текущее
изображение
void DrawCurrent();
// Создает буфер
заданного размера
// (при вызове без
аргументов размер равен текущей картинке)
// совместимый с текущей
картинкой
BOOL
CreateCompatibleBuffer(LONG width=0, LONG height=0);
//Запускает поток
преобразования
void Transform();
protected:
//Функция потока
преобразования
static UINT
ThreadProc(LPVOID pv);
//Цикл преобразования с
использованием активного фильтра
void TransformLoop();
//Посылает сообщение всем
окнам
void InformAllViews(UINT
msg, WPARAM wPar=0, LPARAM lPar=0);
public:
// Overrides
// ClassWizard generated
virtual function overrides
//{{AFX_VIRTUAL(CBMDoc)
public:
virtual BOOL
OnNewDocument();
virtual void
Serialize(CArchive& ar);
virtual BOOL
OnOpenDocument(LPCTSTR lpszPathName);
virtual BOOL
OnSaveDocument(LPCTSTR lpszPathName);
//}}AFX_VIRTUAL
// Implementation
public:
void Onio();
virtual ~CBMDoc();
#ifdef _DEBUG
virtual void
AssertValid() const;
virtual void
Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map
functions
protected:
//{{AFX_MSG(CBMDoc)
afx_msg void
OnEditUndo();
afx_msg void
OnEditBrightnessandcontrast();
afx_msg void
OnEditInvertcolors();
afx_msg void
OnEditBlur();
afx_msg void
OnEditSharp();
afx_msg void
OnUpdateEditBlur(CCmdUI* pCmdUI);
afx_msg void
OnUpdateEditSharp(CCmdUI* pCmdUI);
afx_msg void
OnUpdateEditUndo(CCmdUI* pCmdUI);
afx_msg void
OnUpdateEditBrightnessandcontrast(CCmdUI* pCmdUI);
afx_msg void
OnUpdateEditInvertcolors(CCmdUI* pCmdUI);
afx_msg void
OnEditStop();
afx_msg void
OnUpdateEditStop(CCmdUI* pCmdUI);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++
will insert additional declarations immediately before the previous line.
#endif //
!defined(AFX_BMDOC_H__0CC04D31_A879_4674_AAD5_292699AE7BA7__INCLUDED_)
// BMView.h :
interface of the CBMView class
//
/////////////////////////////////////////////////////////////////////////////
#if
!defined(AFX_BMVIEW_H__A58B1237_DC72_4389_BA43_93CC54F0F5EA__INCLUDED_)
#define
AFX_BMVIEW_H__A58B1237_DC72_4389_BA43_93CC54F0F5EA__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER >
1000
class CBMView : public
CScrollView
{
// Идентификатор таймера
UINT m_nTimer;
// Заголовок окна
CString m_strOrgTitle;
//Виртуальный экран
CBitmap
m_VirtScreenBitmap;// растр
CDCm_VirtScreenDC;//
контекст
// Масштаб вывода
картинки
doublem_dScale;
intm_nStretchMode;
protected: // create from
serialization only
DECLARE_DYNCREATE(CBMView)
// Attributes
public:
CBMDoc* GetDocument();
// Operations
public:
BOOL
UpdateVirtualScreen();
void OnStartTimer();
void OnStopTimer();
afx_msg LONG
OnStartTransform(UINT wParam, LONG lParam);
afx_msg LONG
OnEndTransform(UINT wParam, LONG lParam);
// Overrides
// ClassWizard generated
virtual function overrides
//{{AFX_VIRTUAL(CBMView)
public:
virtual BOOL
PreCreateWindow(CREATESTRUCT& cs);
virtual void
OnInitialUpdate();
protected:
virtual BOOL
OnPreparePrinting(CPrintInfo* pInfo);
virtual void
OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void
OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnDraw(CDC*
pDC);
virtual void
OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
virtual void OnPrint(CDC*
pDC, CPrintInfo* pInfo);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CBMView();
#ifdef _DEBUG
virtual void
AssertValid() const;
virtual void
Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map
functions
protected:
//{{AFX_MSG(CBMView)
afx_msg BOOL
OnEraseBkgnd(CDC* pDC);
afx_msg void OnTimer(UINT
nIDEvent);
afx_msg int
OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void
OnViewZoomin();
afx_msg void
OnViewZoomout();
afx_msg void
OnViewStretchhalftone();
afx_msg void
OnUpdateViewStretchhalftone(CCmdUI* pCmdUI);
afx_msg void
OnViewStretchcoloroncolor();
afx_msg void
OnUpdateViewStretchcoloroncolor(CCmdUI* pCmdUI);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#ifndef _DEBUG // debug
version in BMView.cpp
inline CBMDoc*
CBMView::GetDocument()
{ return
(CBMDoc*)m_pDocument; }
#endif
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++
will insert additional declarations immediately before the previous line.
#endif //
!defined(AFX_BMVIEW_H__A58B1237_DC72_4389_BA43_93CC54F0F5EA__INCLUDED_)
// BMViewer.h : main
header file for the BMVIEWER application
//
#if
!defined(AFX_BMVIEWER_H__854A9B8C_6BD4_44CA_B4E4_F00CEF40C1E7__INCLUDED_)
#define
AFX_BMVIEWER_H__854A9B8C_6BD4_44CA_B4E4_F00CEF40C1E7__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER >
1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h'
before including this file for PCH
#endif
#include
"resource.h" // main symbols
/////////////////////////////////////////////////////////////////////////////
// CBMApp:
// See BMViewer.cpp for
the implementation of this class
//
class CBMApp : public
CWinApp
{
public:
CBMApp();
// Overrides
// ClassWizard generated
virtual function overrides
//{{AFX_VIRTUAL(CBMApp)
public:
virtual BOOL
InitInstance();
//}}AFX_VIRTUAL
// Implementation
//{{AFX_MSG(CBMApp)
afx_msg void
OnAppAbout();
afx_msg void OnFileNew();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++
will insert additional declarations immediately before the previous line.
#endif //
!defined(AFX_BMVIEWER_H__854A9B8C_6BD4_44CA_B4E4_F00CEF40C1E7__INCLUDED_)
//BrightContDlg.h
#if
!defined(AFX_BRIGHTCONTDLG_H__310F8D78_02DE_4055_A8DD_609EFC475802__INCLUDED_)
#define
AFX_BRIGHTCONTDLG_H__310F8D78_02DE_4055_A8DD_609EFC475802__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER >
1000
// BrightContDlg.h :
header file
//
/////////////////////////////////////////////////////////////////////////////
// CBrightContDlg dialog
class CBrightContDlg :
public CDialog
{
// Construction
public:
CBrightContDlg(CWnd*
pParent = NULL); // standard constructor
int m_iBrightnessOffset;
int m_iContrastOffset;
// Dialog Data
//{{AFX_DATA(CBrightContDlg)
enum { IDD =
IDD_BRIGHT_CONT };
CSliderCtrlm_ctrlContrast;
CSliderCtrlm_ctrlBrightness;
CStringm_strBrightness;
CStringm_strContrast;
//}}AFX_DATA
// Overrides
// ClassWizard generated
virtual function overrides
//{{AFX_VIRTUAL(CBrightContDlg)
protected:
virtual void
DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map
functions
//{{AFX_MSG(CBrightContDlg)
virtual BOOL
OnInitDialog();
afx_msg void
OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
virtual void OnOK();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++
will insert additional declarations immediately before the previous line.
#endif //
!defined(AFX_BRIGHTCONTDLG_H__310F8D78_02DE_4055_A8DD_609EFC475802__INCLUDED_)
// ChildFrm.h :
interface of the CChildFrame class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_CHILDFRM_H__D84A743A_B4B5_4CE3_80C2_DF6B6B8A0860__INCLUDED_)
#define
AFX_CHILDFRM_H__D84A743A_B4B5_4CE3_80C2_DF6B6B8A0860__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER >
1000
class CChildFrame :
public CMDIChildWnd
{
DECLARE_DYNCREATE(CChildFrame)
public:
CChildFrame();
// Attributes
protected:
CSplitterWnd
m_wndSplitter;
public:
// Operations
public:
// Overrides
// ClassWizard generated
virtual function overrides
//{{AFX_VIRTUAL(CChildFrame)
public:
virtual BOOL PreCreateWindow(CREATESTRUCT&
cs);
protected:
virtual BOOL
OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CChildFrame();
#ifdef _DEBUG
virtual void
AssertValid() const;
virtual void Dump(CDumpContext&
dc) const;
#endif
// Generated message map
functions
protected:
//{{AFX_MSG(CChildFrame)
// NOTE - the ClassWizard
will add and remove member functions here.
// DO NOT EDIT what you
see in these blocks of generated code!
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++
will insert additional declarations immediately before the previous line.
#endif //
!defined(AFX_CHILDFRM_H__D84A743A_B4B5_4CE3_80C2_DF6B6B8A0860__INCLUDED_)
// Filter.h :
interface of CFilter and derived classes
/////////////////////////////////////////////////////////////////////////////
#ifndef _FILTER_INCLUDED
#define _FILTER_INCLUDED
class CRaster;
// Базовый виртуальный
класс
class CFilter
{
protected:
CRaster *m_pSourceBM;
CRaster *m_pDestBM;
public:
// Устанавливает исходное
и приемное изображения
void SetBuffers(CRaster
*pSource, CRaster *pDest=NULL)
{m_pSourceBM=pSource;m_pDestBM=pDest;};
// Виртуальный метод
преобразования пиксела
// будет переопределен в
производных классах
virtual BOOL
TransformPix(LONG x, LONG y){ return FALSE;};
};
// Базовый класс для
точечных фильтров
class CDotFilter: public
CFilter
{
protected:
// Таблицы преобразования
для компонент цвета
BYTE
BGRTransTable[3][256];
public:
// Метод преобразования
пиксела
BOOL TransformPix(LONG x,
LONG y);
};
// Яркость-контраст
class CBrightCont: public
CDotFilter
{
public:
BOOL Init(int b_offset,
int c_offset);
};
// Инверсия цветов
class CInvertColors:
public CDotFilter
{
public:
CInvertColors();
};
// Рельеф
/*class CEmboss: public CDotFilter
{
public:
BOOL TransformPix(LONG x,
LONG y);
};*/
// Пространственные
(матричные) фильтры
// Базовый класс
class CMatrixFilter:
public CFilter
{
protected:
int m_rangX; // размер
матрицы по X и Y
int m_rangY;
const int *m_pMatrix; //
указатель на матрицу
public:
// Метод преобразования
пиксела
BOOL TransformPix(LONG x,
LONG y);
};
class CBlur: public
CMatrixFilter
{
public:
CBlur();
};
class CSharp: public
CMatrixFilter
{
public:
CSharp();
BOOL TransformPix(LONG x,
LONG y);
};
#endif
// MainFrm.h :
interface of the CMainFrame class
//
/////////////////////////////////////////////////////////////////////////////
#if
!defined(AFX_MAINFRM_H__0E83271E_987C_45D5_8475_25E6B2754E48__INCLUDED_)
#define
AFX_MAINFRM_H__0E83271E_987C_45D5_8475_25E6B2754E48__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER >
1000
class CMainFrame : public
CMDIFrameWnd
{
DECLARE_DYNAMIC(CMainFrame)
public:
CMainFrame();
// Attributes
public:
// Operations
Public:
// Overrides
// ClassWizard generated
virtual function overrides
//{{AFX_VIRTUAL(CMainFrame)
virtual BOOL
PreCreateWindow(CREATESTRUCT& cs);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CMainFrame();
#ifdef _DEBUG
virtual void
AssertValid() const;
virtual void
Dump(CDumpContext& dc) const;
#endif
protected: // control bar
embedded members
CStatusBar m_wndStatusBar;
CToolBar m_wndToolBar;
// Generated message map
functions
protected:
//{{AFX_MSG(CMainFrame)
afx_msg int
OnCreate(LPCREATESTRUCT lpCreateStruct);
// NOTE - the ClassWizard
will add and remove member functions here.
// DO NOT EDIT what you
see in these blocks of generated code!
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++
will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MAINFRM_H__0E83271E_987C_45D5_8475_25E6B2754E48__INCLUDED_)
// Raster.h :
interface of CRaster class
/////////////////////////////////////////////////////////////////////////////
#ifndef _RASTER_INCLUDED
#define _RASTER_INCLUDED
// макрос для определения
количества байт в выровненной по DWORD строки пикселов в DIB
// Width - длина строки в
пикселах; BPP - бит на пиксел
#define
BYTESPERLINE(Width, BPP) ((WORD)((((DWORD)(Width) * \
(DWORD)(BPP) + 31)
>> 5)) << 2)
class CRaster
{
LPBITMAPINFOm_pBMI; //указатель
на описание изображения
PBYTEm_pData;//указатель
на начало растровых данных
public:
CRaster();
~CRaster();
void Clear(); //очистка
памяти
// Возвращает
LPBITMAPINFO
GetBMInfoPtr(){return m_pBMI;}//указатель на заголовок растра
RGBQUAD*
GetBMColorTabPtr();//указатель на таблицу цветов
LONG GetBMWidth();
//ширину в пикселах;
LONG
GetBMHeight();//высоту в пикселах;
BYTE*
GetBMDataPtr(){return m_pData;};//указатель на растровые данные
BYTE* GetPixPtr(LONG x,
LONG y);//указатель на пиксел
// Загружает из файла
BOOL LoadBMP(CString
FileName);
// Выводит DIB на
контекст pDC
// x, y - позиция левого
верхнего угла области назначения
// cx, cy - размер
области назначения
// x0, y0 - позиция
левого верхнего угла выводимой части изображения
// cx0, cy0 - размер
выводимой части изображения
// str_mode - режим
масштабирования
// rop - растровая
операция определяет способ наложения изображения
void DrawBitmap(CDC *pDC,
LONG x=0, LONG y=0, LONG cx=0, LONG cy=0,
LONG x0=0, LONG y0=0,
LONG cx0=0, LONG cy0=0, int str_mode=COLORONCOLOR, DWORD rop=SRCCOPY);
// Выводит DIB на
контекст pDC с позиции (x,y) в масштабе scale
void DrawBitmap(CDC *pDC,
LONG x, LONG y, double scale, int str_mode=COLORONCOLOR, DWORD rop=SRCCOPY);
// Записывает BMP в файл
BOOL SaveBMP(CString
FileName);
// Создает копию
BOOL CreateCopy(CRaster
*pOrg);
// Создает растр
заданного размера, совместимый с параметрами BITMAPINFO
BOOL
CreateCompatible(LPBITMAPINFO pBMI, LONG width=0, LONG height=0);
// Возвращает гисторамму
изображения
BOOL GetHistogham(DWORD
*pHist, int Range);
};
#endif
//{{NO_DEPENDENCIES}}
// Microsoft Developer
Studio generated include file.
// Used by BMViewer.rc
//
#define IDD_ABOUTBOX 100
#define IDR_MAINFRAME 128
#define IDD_HIST 130
#define IDD_BRIGHT_CONT 131
#define IDD_DENOISE 132
#define
IDC_SLIDER_BRIGHTNESS 1001
#define
IDC_STATIC_BRIGHTNESS 1002
#define
IDC_SLIDER_CONTRAST 1003
#define IDC_SLIDER_HIST_B
1003
#define
IDC_STATIC_CONTRAST 1004
#define IDC_SLIDER_HIST_T
1004
#define IDC_OFFSET_B_TXT 1005
#define IDC_OFFSET_T_TXT 1006
#define IDC_NOISE_SMOOTH 1008
#define IDC_NOISE_SHOW 1009
#define IDC_K 1011
#define IDC_SPIN_K 1012
#define IDC_HIST_VIEW 1014
#define ID_VIEW_HISTOGRAM
32771
#define ID_EDIT_HISTOGRAM
32772
#define
ID_EDIT_BRIGHTNESSANDCONTRAST 32773
#define
ID_EDIT_INVERTCOLORS 32774
#define ID_EDIT_BLUR 32775
#define ID_EDIT_SHARP 32776
#define ID_EDIT_CONTOUR 32777
#define ID_EDIT_EDITHALF 32778
#define ID_EDIT_HALF 32779
#define ID_EDIT_EMBOSS 32780
#define ID_EDIT_DENOISE 32781
#define ID_EDIT_STOP 32782
#define ID_VIEW_ZOOMIN 32792
#define ID_VIEW_ZOOMOUT 32793
#define
ID_VIEW_STRETCHHALFTONE 32794
#define
ID_VIEW_STRETCHCOLORONCOLOR 32795
#define ID__DFVGD 32796
// Next default values
for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef
APSTUDIO_READONLY_SYMBOLS
#define _APS_3D_CONTROLS 1
#define
_APS_NEXT_RESOURCE_VALUE 133
#define
_APS_NEXT_COMMAND_VALUE 32797
#define
_APS_NEXT_CONTROL_VALUE 1015
#define
_APS_NEXT_SYMED_VALUE 101
#endif
#endif
// stdafx.h : include
file for standard system include files,
// or project specific
include files that are used frequently, but
// are changed
infrequently
//
#if
!defined(AFX_STDAFX_H__3471DB7C_3910_44C3_92EA_6D934D04BC94__INCLUDED_)
#define AFX_STDAFX_H__3471DB7C_3910_44C3_92EA_6D934D04BC94__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER >
1000
#define VC_EXTRALEAN//
Exclude rarely-used stuff from Windows headers
#include <afxwin.h>
// MFC core and standard components
#include <afxext.h>
// MFC extensions
#include
<afxdisp.h> // MFC Automation classes
#include
<afxdtctl.h>// MFC support for Internet Explorer 4 Common Controls
#ifndef
_AFX_NO_AFXCMN_SUPPORT
#include
<afxcmn.h>// MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++
will insert additional declarations immediately before the previous line.
#endif //
!defined(AFX_STDAFX_H__3471DB7C_3910_44C3_92EA_6D934D04BC94__INCLUDED_)