Работа с BMP-изображениями
МИНИСТЕРСТВО
ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ
Федеральное
государственное автономное образовательное учреждение высшего
профессионального образования
"САНКТ-ПЕТЕРБУРГСКИЙ
ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ АЭРОКОСМИЧЕСКОГО ПРИБОРОСТРОЕНИЯ"
Работа с BMP - изображениями
по курсу: Основы
мультимедиатехнологий
Санкт-Петербург
2015
. Цель работы
Написать программу для обработки изображения, выполняющую функции:
. загрузить интерфейс изображением формата BMP;
. осуществить отражение изображение по вертикали и горизонтали;
. применить к изображению черно-белый фильтр;
. применить сглаживающий фильтр и фильтр подчеркивания границ;
. а также один фильтр по желанию (Медианный фильтр).
интерфейс формат изображение фильтр
2. Формализация
Для выполнения задания воспользуемся средой разработки MS Visual C#.(от англ. Bitmap Picture) - формат хранения растровых
изображений.
При открытии изображения размер поля для отображения подбирается таким
образом, чтобы картинка не была обрезана и растянута, т.е. были соблюдены
пропорции. Так же на этом этапе данные о битовой карте изображения помещаем в 4
переменные:
bmp1 -
отвечает за отображение исходного изображения,
bmp2 -
отвечает за отображение результирующего изображения,
bmp3 -
вспомогательная карта для более корректной обработки изображения.
bmp4 -
вспомогательная карта для более корректной обработки изображения.
Зачем нужны 2 вспомогательные карты?
На bmp3 не применяются
удаление/восстановление цветовых каналов, а так же черно-белые режимы.
Переменная bmp3 необходима нам для восстановления
цветовых каналов, в случае снятия галочек с определенных элементов с
сохранением использованных фильтров
На bmp4 не применяются черно-белые режимы.
Переменная bmp4 служит для корректной работы
удаления/восстановления каналов и включении/выключении черно-белых режимов.
Сглаживающий фильтр
Назначение: Сглаживания - технология, используемая для устранения шумов
или "зубчатости", возникающего на краях объектов выводимых на
изображении.
Основывается на следующем принципе: Обрабатывается рабочее окно
изображения двумерной матрицей (2n+1)x(2n+1) ("+1" - потому что матрица не должна быть
размером менее 3х3), n -
целое положительное число, определяемое коэффициент усиления сглаживания (В
нашем случае n=1, то есть матрица сглаживания 3х3).
Находится среднее значение матрицы по каждому цветовому каналу в отдельности,
исключая значение цветового канала центрального пикселя, по формуле:
(1)
Где, i - индекс строки матрицы,
j -
индекс столбца матрицы,
C -
значение цветового RGB-канала,
n -
количество элементов как в столбце, так и в строке матрицы.
Полученное значение и будет новым значением цветового канала центрального
пикселя матрицы (для матрицы 3х3 это будет элемент P1,1, для матрицы 5х5 - Р2,2 и т.д.)
Примечание: в нашем варианте пиксели, находящиеся по краям изображения,
не обрабатываются. Чтобы обойти данный эффект можно:
) При искусственном зашумлении границы изображения преднамеренно
не зашумлять.
) Обрабатывать каким-то образом частный случай крайних точек
(например, для угла изображения при апертуре 3 суммировать не 9 точек, а 4, и
результат отправлять в этот самый угол или значения крайних точек дублировать
до заполнения квадратной матрицы нужных размеров).
Подчеркивание границ
Назначение: подчеркивание границ служит для отделения участков
различного тонадруг от друга темной или светлой линией.
Основывается на следующем принципе: Обрабатывается рабочее окно
изображения двумерной матрицей (2n+1)x(2n+1) ("+1" - потому что матрица не должна быть
размером менее 3х3), n -
целое положительное число, определяемое коэффициент усиления подчеркивания (В
нашем случае n=1, то есть матрица подчеркивания
3х3). Находится среднее значение матрицы по каждому цветовому каналу в
отдельности по формуле:
(2)
Где, i - индекс строки матрицы,
j -
индекс столбца матрицы,
C -
значение цветового RGB-канала,
n -
количество элементов как в столбце, так и в строке матрицы.
К значению центрального пикселя прибавляем разность среднего значения
соседних пикселей и центрального пикселя:
(3)
Где, NewPix - новое значение центрального
пикселя,
Pix -
старое значение центрального пикселя,
F -
среднее значение соседних пикселей, вычисленное по формуле (2).
Примечание: в нашем варианте пиксели, находящиеся по краям изображения,
не обрабатываются. Чтобы обойти данный эффект можно обрабатывать каким-то
образом частный случай крайних точек (например, для угла изображения при
апертуре 3 брать не 9 точек, а 4, и результат отправлять в этот самый угол или
значения крайних точек дублировать до заполнения квадратной матрицы нужных
размеров).
Отражение изображения
Основывается на следующем принципе: При отражении по вертикали меняем
местами левые и правые пиксели, при отражении по горизонтали - верхние и
нижние.
Нам необходим буфер для хранения одного пикселя, пока другой пиксель не
поставим на место первого.
Изображение делится на две равные части: верхнюю и нижнюю (отражение по
горизонтали), левую и правую (отражение по вертикали).
Алгоритм отражения:
) Верхний (левый) пиксель заносим в буфер,
) нижний (правый) пиксель переносим на симметричное верхнее
(левое) место (откуда был взят пиксель в буфер),
) пиксель из буфера помещаем на нижнее (правое) место (откуда был
перенесен пиксель на втором шаге).
Примечание: Как уже было сказано выше, изображение делится на 2 равные
части. Если у нас размер изображения - нечетное число, то integer(целое число) разделить на константу
2 будет в результате целое число без остатка (остаток отброшен). Таким образом,
средняя полоска пикселей (остаток от деления) будет отброшен, при отражении это
полосу пикселей трогать не будем, чего нам и не требуется.
Черно-белый режим
Цветное изображение преобразуется в монохромное(черно-белое).
Монохромное изображение - выполненное в одном цвете; излучающее один цвет
или цвета, различающиеся по яркости, но не по спектру(в нашем случае
черно-белое).
Нами реализовано 2 способа представления черно-белого изображения:
1 способ (Черно-белый1): Многим известно, что цвет можно задать тройкой RGB.
Значение каждого оттенка занимает байт, а значит лежит в диапазоне от 0 до 255
включительно. (R=0,G=0,B=0 - черный, R=255,G=255,B=255 - белый).
Определим среднее значение всех оттенков по формуле:
(4)
Где R - (Red) Красный канал
G - (Green)Зеленый канал
B - (Blue) Синий канал
Зададим некоторый порог P из диапазона 0 - 255 (Р=100), и укажем правило,
что если среднее значение всех оттенков К <= порога P, то наш пиксель в
монохромном изображении будет черный, в противном случае пиксель будет белым.
2 способ (Черно-белый2): отображение черно-белого изображения с оттеками серого
разной яркости ("темно- и светло- серый")
Это значение заносим в каждый канал пикселя.
Примечание: При включении/выключении этих режимов сохраняются
использованные фильтры, удаленные/восстановленные цветовые каналы.
Медианная фильтрация
Назначение: Медианный фильтр - один из видов цифровых фильтров, широко
используемый в цифровой обработке сигналов и изображений для уменьшения уровня
шума.
Основывается на следующем принципе: Обрабатываются данные
вспомогательной битовой карты изображения(bmp3) двумерной матрицей (2n+1)x(2n+1) ("+1" - потому что
матрица не должна быть размером менее 3х3), n - целое положительное число, определяемое коэффициент
усиления подчеркивания (В нашем случае n=1, то есть матрица 3х3). Элементы матрицы сортируются в
порядке возрастания. Значение находящееся в центре матрицы помещается в битовую
карту обрабатываемого изображения (bmp2) по тем же координатам, где находился центр матрицы в bmp3.
Примечание: в нашем варианте пиксели, находящиеся по краям изображения,
не обрабатываются. Чтобы обойти данный эффект можно обрабатывать каким-то
образом частный случай крайних точек (например, для угла изображения при
апертуре 3 брать не 9 точек, а 4, и результат отправлять в этот самый угол или
значения крайних точек дублировать до заполнения квадратной матрицы нужных размеров).
3. Блок-схема
4. Листинг программы
//отражение по вертикали
private void button6_Click(object sender, EventArgs e)
{(int i = 0; i < bmp2.Width; i++)
{(int j = 0; j < bmp2.Height / 2; j++)
{
//запомниаем текущий пиксель обрабатываемого изображенияbufR =
bmp2.GetPixel(i, j).R;
int bufG = bmp2.GetPixel(i, j).G;bufB = bmp2.GetPixel(i,
j).B;
//присваиваем цветам пикселя обрабатываемого изодражения новые значения
bmp2.SetPixel(i, j, Color.FromArgb(bmp2.GetPixel(i,
bmp2.Height - 1 - j).R, bmp2.GetPixel(i, bmp2.Height - 1 - j).G,
bmp2.GetPixel(i, bmp2.Height - 1 - j).B));.SetPixel(i, bmp2.Height - 1 - j,
Color.FromArgb(bufR, bufG, bufB));
//запомниаем текущий пиксель вспомогательной цветовой карты
bufR = bmp3.GetPixel(i, j).R;= bmp3.GetPixel(i, j).G;=
bmp3.GetPixel(i, j).B;
//присваиваем цветам пикселя вспомогательной цветовой карты новые
значения
bmp3.SetPixel(i, j, Color.FromArgb(bmp3.GetPixel(i,
bmp3.Height - 1 - j).R, bmp3.GetPixel(i, bmp3.Height - 1 - j).G,
bmp3.GetPixel(i, bmp3.Height - 1 - j).B));.SetPixel(i, bmp3.Height - 1 - j,
Color.FromArgb(bufR, bufG, bufB));
//запомниаем текущий пиксель вспомогательной цветовой карты
bufR = bmp4.GetPixel(i, j).R;= bmp4.GetPixel(i, j).G;=
bmp4.GetPixel(i, j).B;
//присваиваем цветам пикселя вспомогательной цветовой карты новые
значения
bmp4.SetPixel(i, j, Color.FromArgb(bmp4.GetPixel(i,
bmp4.Height - 1 - j).R, bmp4.GetPixel(i, bmp3.Height - 1 - j).G,
bmp4.GetPixel(i, bmp4.Height - 1 - j).B));.SetPixel(i, bmp4.Height - 1 - j,
Color.FromArgb(bufR, bufG, bufB));
}
}.Image = bmp2;
}
//отражение по горизонтали
//происходит так же, как и отражение по вертикали
private void button7_Click(object sender, EventArgs e)
{(int i = 0; i < bmp2.Width / 2; i++)
{(int j = 0; j < bmp2.Height; j++)
{bufferR = bmp2.GetPixel(i, j).R;bufferG = bmp2.GetPixel(i,
j).G;bufferB = bmp2.GetPixel(i, j).B;.SetPixel(i, j,
Color.FromArgb(bmp2.GetPixel(bmp2.Width - 1 - i, j).R, bmp2.GetPixel(bmp2.Width
- 1 - i, j).G, bmp2.GetPixel(bmp2.Width - 1 - i, j).B));.SetPixel(bmp2.Width -
1 - i, j, Color.FromArgb(bufferR, bufferG, bufferB));= bmp3.GetPixel(i, j).R;=
bmp3.GetPixel(i, j).G;= bmp3.GetPixel(i, j).B;.SetPixel(i, j, Color.FromArgb(bmp3.GetPixel(bmp2.Width
- 1 - i, j).R, bmp3.GetPixel(bmp3.Width - 1 - i, j).G, bmp3.GetPixel(bmp3.Width
- 1 - i, j).B));.SetPixel(bmp3.Width - 1 - i, j, Color.FromArgb(bufferR,
bufferG, bufferB));= bmp4.GetPixel(i, j).R;= bmp4.GetPixel(i, j).G;=
bmp4.GetPixel(i, j).B;.SetPixel(i, j, Color.FromArgb(bmp4.GetPixel(bmp4.Width -
1 - i, j).R, bmp4.GetPixel(bmp4.Width - 1 - i, j).G, bmp4.GetPixel(bmp4.Width -
1 - i, j).B));.SetPixel(bmp4.Width - 1 - i, j, Color.FromArgb(bufferR, bufferG,
bufferB));
}
}.Image = bmp2;
}
//сглаживаниеvoid button10_Click(object
sender, EventArgs e)
{
//инициализируем переменные для хранения цветов соседних пикселей
//(верхнего, нижнего, левого, правого)RedC, RedL, RedR, RedU, RedD,
RedLU, RedRU, RedLD, RedRD, NewRed,
GreenC, GreenL, GreenR, GreenU, GreenD, GreenLU, GreenRU,
GreenLD, GreenRD, NewGreen,, BlueL, BlueR, BlueU, BlueD, BlueLU, BlueRU,
BlueLD, BlueRD, NewBlue;
//в каждом пикселе (если он не крайний) для каждого цвета
//находим среднее значение глубины(int i = 0; i < bmp2.Width; i++)
for (int j = 0; j < bmp2.Height; j++)
{((i != 0) && (j != 0) && (i != bmp2.Width -
1) && (j != bmp2.Height - 1))
{
//нахождение значений соседних пикселей
RedC =
bmp2.GetPixel(i , j ).R;
RedL = bmp2.GetPixel(i , j - 1).R;= bmp2.GetPixel(i , j +
1).R;= bmp2.GetPixel(i - 1, j ).R;= bmp2.GetPixel(i + 1, j ).R;=
bmp2.GetPixel(i - 1, j - 1).R;= bmp2.GetPixel(i - 1, j + 1).R;= bmp2.GetPixel(i
+ 1, j - 1).R;= bmp2.GetPixel(i + 1, j + 1).R;
//нахождение среднего значения= (RedC + RedL + RedR +
RedU + RedD + RedLU + RedRU + RedLD + RedRD) / 9;= bmp2.GetPixel(i , j ).G;=
bmp2.GetPixel(i , j - 1).G;= bmp2.GetPixel(i , j + 1).G;= bmp2.GetPixel(i - 1,
j ).G;= bmp2.GetPixel(i + 1, j ).G;= bmp2.GetPixel(i - 1, j - 1).G;=
bmp2.GetPixel(i - 1, j + 1).G;= bmp2.GetPixel(i + 1, j - 1).G;= bmp2.GetPixel(i
+ 1, j + 1).G;= (GreenC + GreenL + GreenR + GreenU + GreenD + GreenLU + GreenRU
+ GreenLD + GreenRD) / 9;= bmp2.GetPixel(i , j ).B;= bmp2.GetPixel(i , j -
1).B;= bmp2.GetPixel(i , j + 1).B;= bmp2.GetPixel(i - 1, j ).B;=
bmp2.GetPixel(i + 1, j ).B;= bmp2.GetPixel(i - 1, j - 1).B;= bmp2.GetPixel(i -
1, j + 1).B;= bmp2.GetPixel(i + 1, j - 1).B;= bmp2.GetPixel(i + 1, j + 1).B;=
(BlueC + BlueL + BlueR + BlueU + BlueD + BlueLU + BlueRU + BlueLD + BlueRD) /
9;
//присваиваем цветам
пикселя новые значения.SetPixel(i, j,
Color.FromArgb(NewRed, NewGreen, NewBlue));
//тоже самое проделываем для вспомогательной цветовой карты
RedC = bmp3.GetPixel(i , j ).R;= bmp3.GetPixel(i , j - 1).R;=
bmp3.GetPixel(i , j + 1).R;= bmp3.GetPixel(i - 1, j ).R;= bmp3.GetPixel(i + 1,
j ).R;= bmp3.GetPixel(i - 1, j - 1).R;= bmp3.GetPixel(i - 1, j + 1).R;=
bmp3.GetPixel(i + 1, j - 1).R;= bmp3.GetPixel(i + 1, j + 1).R;= (RedC + RedL +
RedR + RedU + RedD + RedLU + RedRU + RedLD + RedRD) / 9;= bmp3.GetPixel(i , j
).G;= bmp3.GetPixel(i , j - 1).G;= bmp3.GetPixel(i , j + 1).G;= bmp3.GetPixel(i
- 1, j ).G;= bmp3.GetPixel(i + 1, j ).G;= bmp3.GetPixel(i - 1, j - 1).G;=
bmp3.GetPixel(i - 1, j + 1).G;= bmp3.GetPixel(i + 1, j - 1).G;= bmp3.GetPixel(i
+ 1, j + 1).G;= (GreenC + GreenL + GreenR + GreenU + GreenD + GreenLU + GreenRU
+ GreenLD + GreenRD) / 9;= bmp3.GetPixel(i , j ).B;= bmp3.GetPixel(i , j -
1).B;= bmp3.GetPixel(i , j + 1).B;= bmp3.GetPixel(i - 1, j ).B;=
bmp3.GetPixel(i + 1, j ).B;= bmp3.GetPixel(i - 1, j - 1).B;= bmp3.GetPixel(i -
1, j + 1).B;= bmp3.GetPixel(i + 1, j - 1).B;= bmp3.GetPixel(i + 1, j + 1).B;=
(BlueC + BlueL + BlueR + BlueU + BlueD + BlueLU + BlueRU + BlueLD + BlueRD) /
9;.SetPixel(i, j, Color.FromArgb(NewRed, NewGreen, NewBlue));
//тоже самое проделываем для вспомогательной цветовой карты
RedC = bmp4.GetPixel(i, j).R;= bmp4.GetPixel(i, j - 1).R;=
bmp4.GetPixel(i, j + 1).R;= bmp4.GetPixel(i - 1, j).R;= bmp4.GetPixel(i + 1,
j).R;= bmp4.GetPixel(i - 1, j - 1).R;= bmp4.GetPixel(i - 1, j + 1).R;=
bmp4.GetPixel(i + 1, j - 1).R;= bmp4.GetPixel(i + 1, j + 1).R;= (RedC + RedL +
RedR + RedU + RedD + RedLU + RedRU + RedLD + RedRD) / 9;= bmp4.GetPixel(i,
j).G;= bmp4.GetPixel(i, j - 1).G;= bmp4.GetPixel(i, j + 1).G;= bmp4.GetPixel(i
- 1, j).G;= bmp4.GetPixel(i + 1, j).G;= bmp4.GetPixel(i - 1, j - 1).G;=
bmp4.GetPixel(i - 1, j + 1).G;= bmp4.GetPixel(i + 1, j - 1).G;= bmp4.GetPixel(i
+ 1, j + 1).G;= (GreenC + GreenL + GreenR + GreenU + GreenD + GreenLU + GreenRU
+ GreenLD + GreenRD) / 9;= bmp4.GetPixel(i, j).B;= bmp4.GetPixel(i, j - 1).B;=
bmp4.GetPixel(i, j + 1).B;= bmp4.GetPixel(i - 1, j).B;= bmp4.GetPixel(i + 1,
j).B;= bmp4.GetPixel(i - 1, j - 1).B;= bmp4.GetPixel(i - 1, j + 1).B;=
bmp4.GetPixel(i + 1, j - 1).B;= bmp4.GetPixel(i + 1, j + 1).B;= (BlueC + BlueL
+ BlueR + BlueU + BlueD + BlueLU + BlueRU + BlueLD + BlueRD) / 9;.SetPixel(i,
j, Color.FromArgb(NewRed, NewGreen, NewBlue));
}
}.Image = bmp2;
}
//подчеркиваниеvoid button11_Click(object
sender, EventArgs e)
{
//инициализируем переменные для хранения цветов соседних пикселей
//(верхнего, нижнего, левого, правого)RedC, RedL, RedR, RedU, RedD,
RedLU, RedRU, RedLD, RedRD, NewRed,
GreenC, GreenL, GreenR, GreenU, GreenD, GreenLU, GreenRU,
GreenLD, GreenRD, NewGreen,, BlueL, BlueR, BlueU, BlueD, BlueLU, BlueRU,
BlueLD, BlueRD, NewBlue;
//коэффициент усиления подчеркивания границk = 2;
for (int i = 0; i < bmp2.Width; i++)
{((i != 0) && (j != 0) && (i != bmp2.Width -
1) && (j != bmp2.Height - 1))
{
//нахождение значений соседних пикселей
RedC =
bmp2.GetPixel(i , j ).R;
RedL = bmp2.GetPixel(i , j - 1).R;= bmp2.GetPixel(i , j +
1).R;= bmp2.GetPixel(i - 1, j ).R;= bmp2.GetPixel(i + 1, j ).R;=
bmp2.GetPixel(i - 1, j - 1).R;= bmp2.GetPixel(i - 1, j + 1).R;= bmp2.GetPixel(i
+ 1, j - 1).R;= bmp2.GetPixel(i + 1, j + 1).R;
//нахождение среднего значенияmodRed = (RedC + (RedC -
(RedU + RedD + RedL + RedR + RedLU + RedRU + RedLD + RedRD) / 8) * k);= modRed
< 0 ? RedC : modRed > 255 ? RedC : modRed;= bmp2.GetPixel(i , j ).G;=
bmp2.GetPixel(i , j - 1).G;= bmp2.GetPixel(i , j + 1).G;= bmp2.GetPixel(i - 1,
j ).G;= bmp2.GetPixel(i + 1, j ).G;= bmp2.GetPixel(i - 1, j - 1).G;=
bmp2.GetPixel(i - 1, j + 1).G;= bmp2.GetPixel(i + 1, j - 1).G;= bmp2.GetPixel(i
+ 1, j + 1).G;modGreen = (GreenC + (GreenC - (GreenU + GreenD + GreenL + GreenR
+ GreenLU + GreenRU + GreenLD + GreenRD) / 8) * k);= modGreen < 0 ? GreenC :
modGreen > 255 ? GreenC : modGreen;= bmp2.GetPixel(i , j ).B;=
bmp2.GetPixel(i , j - 1).B;= bmp2.GetPixel(i , j + 1).B;= bmp2.GetPixel(i - 1,
j ).B;= bmp2.GetPixel(i + 1, j ).B;= bmp2.GetPixel(i - 1, j - 1).B;=
bmp2.GetPixel(i - 1, j + 1).B;= bmp2.GetPixel(i + 1, j - 1).B;= bmp2.GetPixel(i
+ 1, j + 1).B;modBlue = (BlueC + (BlueC - (BlueU + BlueD + BlueL + BlueR +
BlueLU + BlueRU + BlueLD + BlueRD) / 8) * k);= modBlue < 0 ? BlueC : modBlue
> 255 ? BlueC : modBlue;
//присваиваем цветам
пикселя новые значения.SetPixel(i, j,
Color.FromArgb(NewRed, NewGreen, NewBlue));
//тоже самое проделываем для вспомогательной цветовой карты
RedC = bmp3.GetPixel(i , j ).R;= bmp3.GetPixel(i , j - 1).R;=
bmp3.GetPixel(i , j + 1).R;= bmp3.GetPixel(i - 1, j ).R;= bmp3.GetPixel(i + 1,
j ).R;= bmp3.GetPixel(i - 1, j - 1).R;= bmp3.GetPixel(i - 1, j + 1).R;=
bmp3.GetPixel(i + 1, j - 1).R;= bmp3.GetPixel(i + 1, j + 1).R;= (RedC + (RedC -
(RedU + RedD + RedL + RedR + RedLU + RedRU + RedLD + RedRD) / 8) * k);= modRed
< 0 ? RedC : modRed > 255 ? RedC : modRed;= bmp3.GetPixel(i , j ).G;=
bmp3.GetPixel(i , j - 1).G;= bmp3.GetPixel(i , j + 1).G;= bmp3.GetPixel(i - 1,
j ).G;= bmp3.GetPixel(i + 1, j ).G;= bmp3.GetPixel(i - 1, j - 1).G;=
bmp3.GetPixel(i - 1, j + 1).G;= bmp3.GetPixel(i + 1, j - 1).G;= bmp3.GetPixel(i
+ 1, j + 1).G;= (GreenC + (GreenC - (GreenU + GreenD + GreenL + GreenR +
GreenLU + GreenRU + GreenLD + GreenRD) / 8) * k);= modGreen < 0 ? GreenC :
modGreen > 255 ? GreenC : modGreen;= bmp3.GetPixel(i , j ).B;=
bmp3.GetPixel(i , j - 1).B;= bmp3.GetPixel(i , j + 1).B;= bmp3.GetPixel(i - 1,
j ).B;= bmp3.GetPixel(i + 1, j ).B;= bmp3.GetPixel(i - 1, j - 1).B;=
bmp3.GetPixel(i - 1, j + 1).B;= bmp3.GetPixel(i + 1, j - 1).B;= bmp3.GetPixel(i
+ 1, j + 1).B;= (BlueC + (BlueC - (BlueU + BlueD + BlueL + BlueR + BlueLU +
BlueRU + BlueLD + BlueRD) / 8) * k);= modBlue < 0 ? BlueC : modBlue > 255
? BlueC : modBlue;.SetPixel(i, j, Color.FromArgb(NewRed, NewGreen, NewBlue));
//тоже самое проделываем для вспомогательной цветовой карты
RedC = bmp4.GetPixel(i, j).R;= bmp4.GetPixel(i, j - 1).R;=
bmp4.GetPixel(i, j + 1).R;= bmp4.GetPixel(i - 1, j).R;= bmp4.GetPixel(i + 1, j).R;=
bmp4.GetPixel(i - 1, j - 1).R;= bmp4.GetPixel(i - 1, j + 1).R;= bmp4.GetPixel(i
+ 1, j - 1).R;= bmp4.GetPixel(i + 1, j + 1).R;= (RedC + (RedC - (RedU + RedD +
RedL + RedR + RedLU + RedRU + RedLD + RedRD) / 8) * k);= modRed < 0 ? RedC :
modRed > 255 ? RedC : modRed;= bmp4.GetPixel(i, j).G;= bmp4.GetPixel(i, j -
1).G;= bmp4.GetPixel(i, j + 1).G;= bmp4.GetPixel(i - 1, j).G;= bmp4.GetPixel(i
+ 1, j).G;= bmp4.GetPixel(i - 1, j - 1).G;= bmp4.GetPixel(i - 1, j + 1).G;=
bmp4.GetPixel(i + 1, j - 1).G;= bmp4.GetPixel(i + 1, j + 1).G;= (GreenC +
(GreenC - (GreenU + GreenD + GreenL + GreenR + GreenLU + GreenRU + GreenLD +
GreenRD) / 8) * k);= modGreen < 0 ? GreenC : modGreen > 255 ? GreenC :
modGreen;= bmp4.GetPixel(i, j).B;= bmp4.GetPixel(i, j - 1).B;= bmp4.GetPixel(i,
j + 1).B;= bmp4.GetPixel(i - 1, j).B;= bmp4.GetPixel(i + 1, j).B;=
bmp4.GetPixel(i - 1, j - 1).B;= bmp4.GetPixel(i - 1, j + 1).B;= bmp4.GetPixel(i
+ 1, j - 1).B;= bmp4.GetPixel(i + 1, j + 1).B;= (BlueC + (BlueC - (BlueU +
BlueD + BlueL + BlueR + BlueLU + BlueRU + BlueLD + BlueRD) / 8) * k);= modBlue
< 0 ? BlueC : modBlue > 255 ? BlueC : modBlue;.SetPixel(i, j,
Color.FromArgb(NewRed, NewGreen, NewBlue));
}
}
}.Image = bmp2;
}
//медианная фильтрацияvoid button9_Click(object sender, EventArgs e)
{[] massR = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };[] massG = { 0, 0,
0, 0, 0, 0, 0, 0, 0 };[] massB = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
//для избавления от помех, находим среднее значение цвета в матрице 3х3
вспомогательной карты и присваиваем значение пикселю обрабатывааемого
изображения
for (int i = 1; i < bmp2.Width - 1; i++)
{(int j = 1; j < bmp2.Height - 1; j++)
{p = 0;(int x = -1; x <= 1; x++)
{(int y = -1; y <= 1; y++)
{[p] = bmp3.GetPixel(i + x, j + y).R;[p] = bmp3.GetPixel(i +
x, j + y).G;[p] = bmp3.GetPixel(i + x, j + y).B;++;
}
}(int x = 0; x <= 8; x++)
{(int y = 0; y <= 7; y++)
{(massR[y] > massR[y + 1])
{buf = massR[y];[y] = massR[y + 1];[y + 1] = buf;
}(massG[y] > massG[y + 1])
{buf = massG[y];[y] = massG[y + 1];[y + 1] = buf;
}(massB[y] > massB[y + 1])
{buf = massB[y];[y] = massB[y + 1];[y + 1] = buf;
}
}
}n = 4;.SetPixel(i, j, Color.FromArgb(massR[n], massG[n],
massB[n]));.SetPixel(i, j, Color.FromArgb(massR[n], massG[n], massB[n]));
}
}.Image = bmp2;
//затем копируем карту обрабатываемого изображения во вспомогательную
карту
for (int i = 0; i < bmp2.Width; i++)
{(int j = 0; j < bmp2.Height; j++)
{.SetPixel(i, j, Color.FromArgb(bmp2.GetPixel(i, j).R,
bmp2.GetPixel(i, j).G, bmp2.GetPixel(i, j).B));
}
}
}
//Черно-белый1
//входные данные - координаты пикселя
//изменяется цветовая схема только обрабатываемого изображения, что бы
сохранить информацию о истинных значениях цветов во вспомогательной карте
private void BlackWhite(int i, int j)
{
//найти среднее значение яркости трех цветов пикселя - R,G,B
int NewColor = (bmp2.GetPixel(i, j).R + bmp2.GetPixel(i, j).G
+ bmp2.GetPixel(i, j).B) / 3;
//присвоить R,G,B цветам пикселя среднее значение
if (NewColor <= 100)= 0;= 255;.SetPixel(i, j,
Color.FromArgb(NewColor, NewColor, NewColor));
}
//переключатель черно-белого1void checkBox4_CheckedChanged(object
sender, EventArgs e)
{
//если стоит галочка, переводим изображение в черно-белый
режим(checkBox4.Checked == true)
{
//изменить цвета в карте изображения
for (int i = 0; i < bmp2.Width; i++)
{(int j = 0; j < bmp2.Height; j++)
{(i, j);
}
}
}
//если галочка снята, то возвращяем истинные значения цветов из
вспомогательной карты, проверяя состояние галочек для удаления цветового канала
else
{(int i = 0; i < bmp2.Width; i++)
{(int j = 0; j < bmp2.Height; j++)
{
int red = bmp3.GetPixel(i, j).R,= bmp3.GetPixel(i, j).G,=
bmp3.GetPixel(i, j).B;
//затем проверяем состояние галочек для удаления цветовых каналов,
//если галочка стоит, цветовому каналу присваиваем значение ноль
if (checkBox1.Checked == true)
{= 0;
}(checkBox2.Checked == true)
{= 0;
}(checkBox3.Checked == true)
{= 0;
}
//карте обрабатываемого изображения присваиваем новые значения цветовых
каналов
bmp2.SetPixel(i, j, Color.FromArgb(red, green, blue));(checkBox5.Checked
== true)(i, j);
}
}
}.pictureBox2.Image = bmp2;
}
//Черно-белый1
//входные данные - координаты пикселя
//изменяется цветовая схема только обрабатываемого изображения, что бы
сохранить информацию о истинных значениях цветов во вспомогательной карте
private void GreyBox(int i, int j)
{
//найти среднее значение яркости трех цветов пикселя - R,G,B
int NewColor = (bmp2.GetPixel(i, j).R + bmp2.GetPixel(i, j).G
+ bmp2.GetPixel(i, j).B) / 3;
//присвоить R,G,B цветам пикселя среднее значение
bmp2.SetPixel(i, j, Color.FromArgb(NewColor, NewColor,
NewColor));
}
//переключатель черно-белого2void
checkBox5_CheckedChanged(object sender, EventArgs e)
{
//если стоит галочка, переводим изображение в черно-белый
режим(checkBox5.Checked == true)
{
//изменить цвета в карте изображения
for (int i = 0; i < bmp2.Width; i++)
{(int j = 0; j < bmp2.Height; j++)
{(i, j);
}
}
}
//если галочка снята, то возвращяем истинные значения цветов из
вспомогательной карты, проверяя состояние галочек для удаления цветового канала
else
{(int i = 0; i < bmp2.Width; i++)
{(int j = 0; j < bmp2.Height; j++)
{
//сначала присваиваем переменным значения цветов вспомогательной карты
int red = bmp3.GetPixel(i, j).R,= bmp3.GetPixel(i, j).G,=
bmp3.GetPixel(i, j).B;
//затем проверяем состояние галочек для удаления цветовых каналов,
//если галочка стоит, цветовому каналу присваиваем значение ноль
if (checkBox1.Checked == true)
{= 0;
}(checkBox2.Checked == true)
{= 0;
}(checkBox3.Checked == true)
{= 0;
}
//карте обрабатываемого изображения присваиваем новые значения цветовых
каналов
bmp2.SetPixel(i, j, Color.FromArgb(red, green,
blue));(checkBox4.Checked == true)(i, j);
}
}
}.pictureBox2.Image = bmp2;
}
}
}
. Результаты работы программы
Отражение горизонтали
Черно-белый фильтр
Сглаживание
Медианная фильтрация
Вывод
В результате выполнения лабораторной работы было разработано приложение,
с помощью которого можно модифицировать изображение, путем изменения bitmap
изображения. Также были реализованы несколько фильтров для изменения
изображения: черно-белый фильтр, сглаживающий фильтр, подчеркивание границ и
медианная фильтрация.
После применения каждого из фильтров, для каждого канала изображения были
построены гистограммы, по которым можно оценивать общие изменения количества
пикселей определенной яркости.
Например, при применении черно-белого фильтра, гистограммы для каждого из
цветов одинаковы, так как мы в каждом пикселе, каждому каналу присваиваем
среднее значение трех каналов пикселя.
На гистограмме для изображения с примененным фильтром сглаживания мы
видим, что относительно оригинала, количество пикселей с наиболее часто
встречающейся яркостью канала в изображении растет. То есть, происходит рост
гистограммы и ее сужение. А при применении фильтра подчеркивания границ, гистограмма
расширяется и становится ниже.
Фильтр медианной фильтрации предназначен, для того, чтобы устранять
помехи изображения. Если сравнить гистограмму изображения с помехами с
гистограммой этого же изображения, только, с примененным медианным фильтром, то
можно увидеть, что вероятность появления помехи в изображении резко
уменьшается.
Литература
. Гербердт Шилдт. Полный справочник по С#;
. Программирование на С#. Методические указания к
лабораторным работам. А.Ю. Демин, В.А. Дорофеев.