Програма фільтрації шумів
Завдання.
Створити програму, що здійснює фільтрацію шумів в растрових зображеннях методами усереднювати, порогового і медіанного фільтрів.
Програма написана на мові 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) = 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, 'Такий формат файлу поки не підтримується ...',
'Слабенько я поки ...', 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. Результат інверсії зображення.