Белорусский Государственный Университет
Информатики и Радиоэлектроники
Контрольная работа
по
МАГИ
Выполнил студент группы 500501
Балахонов Е.В.
Задание.
Создать программу, осуществляющую фильтрацию шумов в растровых изображениях методами усредняющего, порогового и медианного фильтров.
Програма написана на языке Object Pascal и выполняется в среде Win32.
Общий вид программы показан на рис. № 1.
[pic]
Рис. № 1. Общий вид главного окна программы.
[pic]
Рис. № 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 Image1.Picture.Bitmap.PixelFormat = pf8bit then begin for I := 0 to Image1.Picture.Bitmap.Height - 1 do begin
CurrentLine := Image1.Picture.Bitmap.ScanLine[I]; for J := 0 to Image1.Picture.Bitmap.Width - 1 do begin
Summ := 0;
if I > 0 then begin
PrevisionLine := Image1.Picture.Bitmap.ScanLine[I - 1]; if J > 0 then begin
Summ := Summ + PrevisionLine^[J - 1]; end;
Summ := Summ + PrevisionLine^[J];
if J + 1 < Image1.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 < Image1.Picture.Bitmap.Width then begin
Summ := Summ + CurrentLine^[J + 1]; end;
if I + 1 < Image1.Picture.Bitmap.Height then begin
NextLine := Image1.Picture.Bitmap.ScanLine[I + 1]; if J > 0 then begin
Summ := Summ + NextLine^[J - 1]; end;
Summ := Summ + NextLine^[J];
if J + 1 < Image1.Picture.Bitmap.Width then begin
Summ := Summ + NextLine^[J + 1]; end; end;
if (Summ div 9) = 0) and (VertB < Image1.Picture.Bitmap.Height) then
BoxCurrentLine := Image1.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 < Image1.Picture.Bitmap.Width) and
(VertB < Image1.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;
Image1.Visible := False;
Image1.Visible := True;
N4.Enabled := True; end else
MessageBox(Handle,'Такой формат файла пока не подерживается...',
'Слабоват я пока...',MB_OK or MB_ICONSTOP or
MB_APPLMODAL); end; end;
Результат работы фильтра можно увидеть на рис. № 6.
[pic]
Рис. № 6. Начало работы медианного фильтра – запрос на размер окна фильтра.
[pic]
Рис. № 7.Результат работы медианного фильтра с окном 3 на 3.
4. Заполнение объекта другим цветом.
Для упрощения алгоритма слудующая процедура заполняет графические объекты только белым цветом, однако путем простого добавления диалогового окна с вопросом о цвете заполнения можно добиться заполнения объектов любым цветом.
procedure TMainForm.Image1MouseDown(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 Image1.Picture.Bitmap.PixelFormat = pf8bit then begin
// Запоминаем значение пиксела на котором щелкнули мышкой
TargetPixel := pByteArray(Image1.Picture.Bitmap.ScanLine[Y])^[X];
YOffset := 0;
// Пока число замен не станет равным 0 двигаемся вверх repeat
ChangeCount := 0;
if Y - YOffset < 0 then
Break;
// Берем линию
CurrentLine := Image1.Picture.Bitmap.ScanLine[Y - YOffset];
PrevLine := Image1.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 < Image1.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 > Image1.Picture.Bitmap.Width - 1 then
Break; end;
Inc(YOffset); until ChangeCount = 0;
YOffset := 1;
// Пока число замен не станет равным 0 двигаемся вниз repeat
ChangeCount := 0;
if Y + YOffset > Image1.Picture.Bitmap.Width - 1 then
Break;
// Берем линию
CurrentLine := Image1.Picture.Bitmap.ScanLine[Y + YOffset];
NextLine := Image1.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 < Image1.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 > Image1.Picture.Bitmap.Width - 1 then
Break; end;
Inc(YOffset); until ChangeCount = 0;
Image1.Visible := False;
Image1.Visible := True; end; end;
Результаты работы программы можно увидеть на рис. № 8 и № 9.
[pic]
Рис. № 8. Исходное изображение для заполнения.
[pic]
Рис. № 9. Результат заполнения.
5. Инверсия.
Ну и напоследок сделаем инверсию нашего изображения (Рис. 10, 11):
procedure TMainForm.N7Click(Sender: TObject); var
Line:pByteArray;
I,J:Integer;
Bits:Byte; begin
Bits := 1; for I :=0 to Image1.Picture.Bitmap.Height - 1 do begin
Line := Image1.Picture.Bitmap.ScanLine[I];
case Image1.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 Image1.Picture.Bitmap.Width * Bits - 1 do
Line^[J] := 255 - Line^[J];
end;
Image1.Visible := False;
Image1.Visible := True;
N4.Enabled := True; end;
[pic]
Рис. № 10. Исходное изображение для инверсии.
[pic]
Рис. № 11. Результат инверсии изображения.