Програма фільтрації шумів
Завдання.
Створити програму, що здійснює фільтрацію шумів в растрових зображеннях
методами усереднювати, порогового і медіанного фільтрів.
Програма написана на мові Object Pascal і виконується в середовищі Win32. Загальний вигляд
програми показано на рис. № 1.
Рис. № 2. Загальний вигляд головного вікна програми c завантаженим вихідним зображенням.
1. Усереднюють фільтp.
Алгоритм роботи усереднюються фільтра полягає в заміні значення яскравості в
поточному пікселі на середню яскравість, обчислену за його 8 околицях, включаючи і
сам елемент. Цей фільтр є найпростішим. До недоліків його можна віднести
згладжування східчастих і пилоподібним функцій. Крім того пікселі, що має
істотно відмінне значення яскравості і які є шумовими можуть вносити
значний внесок у результат обробки.
Реалізація фільтра представлена у вигляді процедури:
Procedure AverageFilter (Value: Integer);
Дана процедура здійснює алгоритм усереднюються фільтра стосовно
об'єкту TBitmap. У нього попередньо повинна бути додано зображення (Рис. №
2). Результат роботи усереднюються фільтра можна побачити на рис. № 3. Параметр
Value - поріг при якому виробляються маніпуляції з пікселів.
Procedure TMainForm.AverageFilter;
var
PrevisionLine: pByteArray;
CurrentLine: pByteArray;
NextLine: pByteArray;
I, J: Integer;
Summ: Integer;
begin
if 9262_1.Picture.Bitmap.PixelFormat = pf8bit then
begin
for I: = 0 to 9262_1.Picture.Bitmap.Height - 1 do
begin
CurrentLine: = 9262_1.Picture.Bitmap.ScanLine [I];
for J: = 0 to 9262_1.Picture.Bitmap.Width - 1 do
begin
Summ: = 0;
if I> 0 then
begin
PrevisionLine: = 9262_1.Picture.Bitmap.ScanLine [I - 1];
if J> 0 then
begin
Summ: = Summ + PrevisionLine ^ [J - 1];
end;
Summ: = Summ + PrevisionLine ^ [J];
if J + 1 <9262_1.Picture.Bitmap.Width then>
begin
Summ: = Summ + PrevisionLine ^ [J + 1];
end;
end;
if J> 0 then
begin
Summ: = Summ + CurrentLine ^ [J - 1];
end;
Summ: = Summ + CurrentLine ^ [J];
if J + 1 <9262_1.Picture.Bitmap.Width then>
begin
Summ: = Summ + CurrentLine ^ [J + 1];
end;
if I + 1 <9262_1.Picture.Bitmap.Height then>
begin
NextLine: = 9262_1.Picture.Bitmap.ScanLine [I + 1];
if J> 0 then
begin
Summ: = Summ + NextLine ^ [J - 1];
end;
Summ: = Summ + NextLine ^ [J];
if J + 1 <9262_1.Picture.Bitmap.Width then>
begin
Summ: = Summ + NextLine ^ [J + 1];
end;
end;
if (Summ div 9)
CurrentLine ^ [J]: = Summ div 9;
end;
end;
9262_1.Visible: = False;
9262_1.Visible: = True;
N4.Enabled: = True;
end
else
MessageBox (Handle, 'Такий формат файлу поки не підтримують ...',< br />
'Слабенько я поки ...', MB_OK or MB_ICONSTOP or MB_APPLMODAL);
end;
Рис. № 3. Результат роботи усереднюються фільтра.
2. Пороговий фільтр.
Пороговий фільтр є модифікацією усереднювати, і відмінність полягає
те, що заміна значення яскравості на середнє здійснюється лише в тому випадку,
якщо різниця між значенням яскравості і отриманим середнім перевищує
встановлений поріг. Вибір порога здійснюється в спеціальному діалоговому вікні
(Рис. 4). Для твори фільтрації використовується процедура AverageFilter,
показана в пункті 1.
Рис. № 4.Вибор коефіцієнта усереднення порогового фільтра.
Рис. № 5. Результат роботи порогового фільтра.
3. Медіанний фільтр.
Одновимірна медіанний фільтр є ковзне вікно охоплює
непарне число елементів зображення. Центральний елемент замінюється медіаною
елементів зображення у вікні. Медіаною дискретної послідовності М елементів
при непарній 1 називають елемент, для якого існує (М-1)/2 елементі
менших або рівних йому за величиною і (М-1)/2 елементів більших або рівних йому по
величиною.
Медіанний фільтр в одних випадках забезпечує придушення шуму, а в інших -
викликає небажане придушення сигналу. Медіанний фільтр не впливає на
пилкоподібні і ступінчасті функції, що зазвичай є корисною властивістю,
однак він пригнічує імпульсні сигнали, тривалість яких складає менше
половини ширини вікна. Фільтр також викликає сплощення вершини трикутної
функції.
Можливі різні стратегії застосування медіанного фільтру для придушення шумів.
Одна з них рекомендує починати з медіанного фільтра, вікно якого охоплює
три елементи зображення. Якщо ослаблення сигналу незначно, то вікно
розширюється до п'яти елементів. Так надходять до тих пір, поки медіанна
фільтрація почне приносити більше шкоди, ніж користі. Інша можливість полягає
в каскадної медіанної фільтрації сигналу з використанням фіксованого або
змінної ширини вікна. У загальному випадку ті області, які залишаються без
зміни після одноразової обробки, не змінюються і після повторної обробки.
Галузі, в яких тривалість імпульсних сигналів становить менше половини
ширини вікна, будуть піддаватися змінам після кожного циклу обробки.
Концепцію медіанного фільтра можна легко узагальнити на два виміри, застосовуючи
вікно прямокутної або близькою до кругової форми.
Для реалізації медіанного фільтру використовується наступний код:
procedure TMainForm.N16Click (Sender: TObject);
var
PixelArray: array of Byte;
Value: Byte;
CurrentLine: pByteArray;
BoxCurrentLine: pByteArray;
Vert, Hor: Integer;
VertB, HorB: Integer;
Counter: Integer;
Temp: Byte;
begin
ValueForm.Caption: = 'Розмір вікна фільтра n X n';
ValueForm.TrackBar1.Min: = 3;
ValueForm.TrackBar1.Max: = 9;
ValueForm.TrackBar1.Frequency: = 2;
ValueForm.Edit1.ReadOnly: = True;
if ValueForm.Execute (Value) then
begin
SetLength (PixelArray, Value * Value);
if 9262_1.Picture.Bitmap.PixelFormat = pf8bit then
begin
for Vert: = 0 to 9262_1.Picture.Bitmap.Height - 1 do
begin
CurrentLine: = 9262_1.Picture.Bitmap.ScanLine [Vert];
for Hor: = 0 to 9262_1.Picture.Bitmap.Width - 1 do
begin
//Заносить всі пікселі віконця в масив
Counter: = 0;
for VertB: = (Vert - (Value div 2)) to (Vert + (Value div 2)) do
begin
if (VertB> = 0) and (VertB <9262_1.Picture.Bitmap.Height) then>
BoxCurrentLine: = 9262_1.Picture.Bitmap.ScanLine [VertB];
for HorB: = (Hor - (Value div 2)) to (Hor + (Value div 2)) do
begin
if (HorB> = 0) and (VertB> = 0) and
(HorB <9262_1.Picture.Bitmap.Width) and>
(VertB <9262_1.Picture.Bitmap.Height) then>
PixelArray [Counter]: = BoxCurrentLine ^ [HorB]
else
PixelArray [Counter]: = 0;
Inc (Counter);
end;
end;
//Сортуємо масив
for VertB: = 0 to Value * Value - 1 do
begin
for HorB: = VertB to Value * Value - 1 do
begin
if PixelArray [VertB]> PixelArray [HorB] then
begin
Temp: = PixelArray [VertB];
PixelArray [VertB]: = PixelArray [HorB];
PixelArray [HorB]: = Temp;
end;
end;
end;
//Беремо те що посередині і присвоюємо поточному пікселю
CurrentLine ^ [Hor]: = PixelArray [((Value * Value) div 2) + 1];
end;
end;
9262_1.Visible: = False;
9262_1.Visible: = True;
N4.Enabled: = True;
end
else
MessageBox (Handle, 'Такий формат файлу поки не підтримується ...',< br />
'Слабенько я поки ...', MB_OK or MB_ICONSTOP or MB_APPLMODAL);
end;
end;
Результат роботи фільтру можна побачити на рис. № 6.
Рис. № 6. Початок роботи медіанного фільтру - запит на розмір вікна фільтра.
4. Заповнення об'єкта іншим кольором.
Для спрощення алгоритму слудующая процедура заповнює графічні об'єкти тільки
білим кольором, однак шляхом простого додавання діалогового вікна з питанням про
кольорі заповнення можна домогтися заповнення об'єктів будь-яким кольором.
procedure TMainForm.9262_1MouseDown (Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
TargetPixel: Byte;
ChangeCount: Integer;
CurrentLine: pByteArray;
PrevLine: pByteArray;
NextLine: pByteArray;
YOffset, XOffset: Integer;
begin
if 9262_1.Picture.Bitmap.PixelFormat = pf8bit then
begin
//Запам'ятовуємо значення пікселя на якому клацнули мишкою
TargetPixel: = pByteArray (9262_1.Picture.Bitmap.ScanLine [Y]) ^ [X];
YOffset: = 0;
//Пока кількість замін не стане рівним 0 рухаємося вгору
repeat
ChangeCount: = 0;
if Y - YOffset <0 then>
Break;
//Беремо лінію
CurrentLine: = 9262_1.Picture.Bitmap.ScanLine [Y - YOffset];
PrevLine: = 9262_1.Picture.Bitmap.ScanLine [Y - YOffset - 1];
if PrevLine [X] TargetPixel then
Break;
XOffset: = 0;
//Заповнюємо вліво її поки не дійдемо до кордону об'єкта
if X - 1> = 0 then
while CurrentLine ^ [X - XOffset - 1] = TargetPixel do
begin
CurrentLine ^ [X - XOffset]: = 255;
Inc (XOffset);
Inc (ChangeCount);
if X - XOffset - 1 <0 then>
Break;
end;
XOffset: = 0;
//Заповнюємо вправо її поки не дійдемо до кордону об'єкта
if X + 1 <9262_1.Picture.Bitmap.Width - 1 then>
while CurrentLine ^ [X + XOffset + 1] = TargetPixel do
begin
CurrentLine ^ [X + XOffset]: = 255;
Inc (XOffset);
Inc (ChangeCount);
if X + XOffset + 1> 9262_1.Picture.Bitmap.Width - 1 then
Break;
end;
Inc (YOffset);
until ChangeCount = 0;
YOffset: = 1;
//Пока кількість замін не стане рівним 0 рухаємося вниз
repeat
ChangeCount: = 0;
if Y + YOffset> 9262_1.Picture.Bitmap.Width - 1 then
Break;
//Беремо лінію
CurrentLine: = 9262_1.Picture.Bitmap.ScanLine [Y + YOffset];
NextLine: = 9262_1.Picture.Bitmap.ScanLine [Y + YOffset + 1];
if NextLine [X] TargetPixel then
Break;
XOffset: = 0;
//Заповнюємо вліво її поки не дійдемо до кордону об'єкта
if X - 1> = 0 then
while CurrentLine ^ [X - XOffset - 1] = TargetPixel do
begin
CurrentLine ^ [X - XOffset]: = 255;
Inc (XOffset);
Inc (ChangeCount);
if X - XOffset - 1 <0 then>
Break;
end;
XOffset: = 0;
//Заповнюємо вправо її поки не дійдемо до кордону об'єкта
if X + 1 <9262_1.Picture.Bitmap.Width - 1 then>
while CurrentLine ^ [X + XOffset + 1] = TargetPixel do
begin
CurrentLine ^ [X + XOffset]: = 255;
Inc (XOffset);
Inc (ChangeCount);
if X + XOffset + 1> 9262_1.Picture.Bitmap.Width - 1 then
Break;
end;
Inc (YOffset);
until ChangeCount = 0;
9262_1.Visible: = False;
9262_1.Visible: = True;
end;
end;
Результати роботи програми можна побачити на рис. № 8 і № 9.
Рис. № 8. Початкове зображення для заповнення.
Рис. № 9. Результат заповнення.
5. Інверсія.
Ну і наприкінці зробимо інверсію нашого зображення (Рис. 10, 11):
procedure TMainForm.N7Click (Sender: TObject);
var
Line: pByteArray;
I, J: Integer;
Bits: Byte;
begin
Bits: = 1;
for I: = 0 to 9262_1.Picture.Bitmap.Height - 1 do
begin
Line: = 9262_1.Picture.Bitmap.ScanLine [I];
case 9262_1.Picture.Bitmap.PixelFormat of
pf4bit: Bits: = 1;
pf8bit: Bits: = 1;
pf15bit: Bits: = 2;
pf16bit: Bits: = 2;
pf24bit: Bits: = 3;
pf32bit: Bits: = 4;
end;
for J: = 0 to 9262_1.Picture.Bitmap.Width * Bits - 1 do
Line ^ [J]: = 255 - Line ^ [J];
end;
9262_1.Visible: = False;
9262_1.Visible: = True;
N4.Enabled: = True;
end;
Рис. № 10. Початкове зображення для інверсії.
Рис. № 11. Результат інверсії зображення.