Форум: "Media";
Текущий архив: 2009.12.27;
Скачать: [xml.tar.bz2];
ВнизУдаление шума на изображении Найти похожие ветки
← →
shart © (2007-02-27 20:56) [0]Какой есть алгоритм для быстрого удаления шума на изображении? Изображение берётся с DV-камеры и соответственно слишким много шума...
← →
MBo © (2007-02-28 06:18) [1]медианная фильтрация, гауссово сглаживание
← →
shart © (2007-02-28 11:48) [2]MBo, спасибо! А реализации нигде не найдётся? )
← →
Jeer © (2007-02-28 13:23) [3]Реализация медианного фильтра примитивна.
Выбирается размер окна, например 3*3 pix = 9 pix
Извлекается массив из 9 pix и производится его сортировка, извлекается значение среднего по номеру пикселя т.е. 5 -го и возвращается в исходное изображение на место среднего элемента окна, т.е. px[2,2].
Процесс повторяется со сдвигом на 1 px для всего изображения раздельно для каждого из каналов RGB.
Краевые точки (контур) остается необработанным, либо дообрабатывается одномерной медианой.
← →
SamBrook © (2007-03-01 00:01) [4]
> Реализация медианного фильтра примитивна.
В таком виде - конечно :)
В правильном - сортировки вообще не используются.
А вообще-то, для устранения шума нужно, как минимум, знать его характеристики.
А то вместе с водой и младенец увяжется.
← →
Jeer © (2007-03-01 10:34) [5]
> В правильном
"Правильный" <> "Эффективный", к тому же для уяснения понятия "эффективный" должны быть озвучены критерии, а понятие "правильный" вообще не является техническим.
Приведенное мной словесное описание алгоритма медианной фильтрации основано на классическом определении медианы и легко для понимания начинающими сути вопроса и реализации алгоритма.
Разновидностей же реализации медианной фильтрации много, достаточно привести пример м.фильтрации с произвольной апертурой (не только не квадратной, но и не прямоугольной), основанный на разовом вычислении гистограммы и медианы для начального положения апертуры и последующей их корректировкой.
Данный алгоритм, по количеству элементарных операций, имеет заметное преимущество перед классическими.
> А вообще-то, для устранения шума нужно, как минимум, знать
> его характеристики.
Бесспорно, но это можно тоже сделать выполнив съемку в темноте (или при различных уровнях монотонной засветки) и проанализировав статистические и спектральные характеристики шума.
В общем случае нормальные элементы фото-матриц имеют шум класса "белый", а аномальные - шум класса 1/f.
← →
Shart © (2007-03-01 23:42) [6]Ещё раз спасибо! Пока реализовал только "примитивный" алгоритм медианной фильтрации. И тут же возник ещё один вопрос : как избавится от цветового шума, т.е. если на жёлтой стене появляются небольшие синие, зелёные и красные пятна?
← →
Jeer © (2007-03-02 10:00) [7]Можно так, для общего случая цветового шума:
- перейти в Lab-цветовое пространство
- gaussian blur каналов a и b
- обратно в RGB
← →
Shart © (2007-03-03 00:39) [8]Вобщем, сделал я прогу... только работает она долго. По-идее, я придумал новый способ фильтрации...назову его темпоральный медианный фильтр (а может не новый, где-то я его видел).
Вот файл - http://www.sendspace.com/file/tutp6a (весит ~2метра)
Короче, надо ложить несколько (а лучше много) последовательных съёмок одного кадра (т.е. чтоб камера не двигалась, в архиве есть пример, там...эээ...мой стол:) ) в папку с:\ca\ названия у файлов - shotN.bmp, где N номер кадра от 0.
Потом в программе надо изменить константы FRAMES (кол-во кадров), W(ширина), H(высота кадра), скопилить и запустить...
сейчас вопрос - как это всё дело ускорить?
← →
Shart © (2007-03-03 00:41) [9]А, забыл написать описание алгоритма:
1. Во всех кадрах один пиксель добавляю в массив
2. Нахожу медиану
3. Ставлю пиксель на конечное изображение
← →
Pavia © (2007-03-03 02:15) [10]Оптимизация.
Я бы всетаки использовал доступ к пикселям через ScanLine и пользовался бы стандартным TBitmap.
Не обязательно делать медианную фильтрацию от большого числа кадров.
Или можно заменить медианную фильтрациию на усредненние(ищем среднее арефметическое).
Предложение.
Адаптивный фильтр. Делаем размытие с сохронением краев.
← →
Jeer © (2007-03-05 10:52) [11]Улучшение изображения по серии однотипных снимков - это немного другое.
Можно попробовать медианный фильтр к каждому снимку для устранения "горячих" пикселей, а затем осреднение однокоординатных точек по серии снимков.
Вот, что примерно должно получиться:
http://webfile.ru/1335346
← →
Kikky © (2008-01-17 19:33) [12]Очень надо! Срочно! Объясните пожалуйчта программу построчно! Такое требование преподавателя! Буду очень признательна!
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Math;
type
TScanlines = class
private
FScanLine0 : PByte;
FScanLineIncrement : integer;
FMaxRow : integer;
function GetRowPtr(Index: integer): PByte;
public
constructor Create(Bitmap: TBitmap);
destructor Destroy; override;
property RowPtr[Index: Integer]: PByte read GetRowPtr; default;
end;
TForm1 = class(TForm)
Panel1: TPanel;
Image1: TImage;
Button1: TButton;
Button2: TButton;
Button3: TButton;
OpenDialog1: TOpenDialog;
SaveDialog1: TSaveDialog;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then Image1.Picture.LoadFromFile(OpenDialog1.FileName);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if SaveDialog1.Execute then Image1.Picture.SaveToFile(SaveDialog1.FileName);
end;
procedure TForm1.Button3Click(Sender: TObject);
procedure AntiAliasRect(clip: tbitmap; XOrigin, YOrigin, XFinal, YFinal: Integer);
var
Memo, x, y : Integer; (* Composantes primaires des points environnants *)
p0, p1, p2 : pbytearray;
SL : TScanlines;
begin
if XFinal<XOrigin then begin Memo := XOrigin; XOrigin := XFinal; XFinal := Memo; end; (* Inversion des valeurs *)
if YFinal<YOrigin then begin Memo := YOrigin; YOrigin := YFinal; YFinal := Memo; end; (* si diff,rence n,gative*)
XOrigin := max(1,XOrigin);
YOrigin := max(1,YOrigin);
XFinal := min(clip.width-2,XFinal);
YFinal := min(clip.height-2,YFinal);
clip.PixelFormat := pf24bit;
SL := TScanlines.Create(clip);
try
for y := YOrigin to YFinal do begin
//p0 := clip.ScanLine [y-1];
//p1 := clip.scanline [y];
//p2 := clip.ScanLine [y+1];
p0 := PByteArray(SL[y-1]);
p1 := PByteArray(SL[y]);
p2 := PByteArray(SL[y+1]);
for x := XOrigin to XFinal do begin
p1[x*3] := (p0[x*3]+p2[x*3]+p1[(x-1)*3]+p1[(x+1)*3])div 4;
p1[x*3+1] := (p0[x*3+1]+p2[x*3+1]+p1[(x-1)*3+1]+p1[(x+1)*3+1])div 4;
p1[x*3+2] := (p0[x*3+2]+p2[x*3+2]+p1[(x-1)*3+2]+p1[(x+1)*3+2])div 4;
end;
end;
finally
SL.Free;
end;
end;
begin
AntiAliasRect(Image1.Picture.Bitmap, 0, 0, Image1.Picture.Bitmap.Width, Image1.Picture.Bitmap.Height);
end;
{ TScanlines }
constructor TScanlines.Create(Bitmap: TBitmap);
begin
inherited Create;
FScanLine0 := nil;
FScanLineIncrement := 0;
FMaxRow := 0;
if Bitmap <> nil then begin
FScanLine0 := Bitmap.ScanLine[0];
FScanLineIncrement := integer(Bitmap.Scanline[1]) -integer(FScanLine0);
FMaxRow := Bitmap.Height;
end;
end;
destructor TScanlines.Destroy;
begin
inherited;
end;
function TScanlines.GetRowPtr(Index: integer): PByte;
begin
if (Index >= 0) and (Index < FMaxRow) then begin
result := FScanLine0;
Inc(result, FScanLineIncrement *Index);
end else
result := nil;
end;
end.
← →
antonn © (2008-01-17 22:42) [13]
> Объясните пожалуйчта программу построчно! Такое требование
> преподавателя!
> { TScanlines }
это комментарий, он ничего не делает в программе %)
> //p0 := clip.ScanLine [y-1];
> //p1 := clip.scanline [y];
> //p2 := clip.ScanLine [y+1];
это тоже комментарии...
> (* Inversion des valeurs *)
и это.
← →
homm © (2008-01-17 23:05) [14]> [12] Kikky © (17.01.08 19:33)
> Очень надо! Срочно! Объясните пожалуйчта программу построчно!
А не пойти бы тебе… учится.
← →
Kenny (2008-01-18 14:12) [15]// Декларирование названия модуля
unit Unit1;
// Начало интерфейсной части
interface
// Список изпользуемых модулей
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Math;
// Объявление класса TScanlines
type
TScanlines = class
// Приватная (видимая только внутри класса) часть
private
FScanLine0 : PByte;
FScanLineIncrement : integer;
FMaxRow : integer;
function GetRowPtr(Index: integer): PByte;
// Публичная (видимая) часть
public
constructor Create(Bitmap: TBitmap);
destructor Destroy; override;
property RowPtr[Index: Integer]: PByte read GetRowPtr; default;
end;
// Класс формы
TForm1 = class(TForm)
Panel1: TPanel;
Image1: TImage;
Button1: TButton;
Button2: TButton;
Button3: TButton;
OpenDialog1: TOpenDialog;
SaveDialog1: TSaveDialog;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
// Глобальная переменная класса TForm1
var
Form1: TForm1;
// Начало части реализации
implementation
// Прикрепление ресурса в виде dfm файла (Unit1.dfm)
{$R *.dfm}
// обработчик нажатия кнопки Button1
procedure TForm1.Button1Click(Sender: TObject);
begin
// Если в диалоге открытия файла был выбран файл, то загрузаем картинку в Image1
if OpenDialog1.Execute then Image1.Picture.LoadFromFile(OpenDialog1.FileName);
end;
// обработчик нажатия кнопки Button2
procedure TForm1.Button2Click(Sender: TObject);
begin
// Если в диалоге сохранения файла ввели имя файла и нажали Сохранить, то сохраняем картинку из Image1
if SaveDialog1.Execute then Image1.Picture.SaveToFile(SaveDialog1.FileName);
end;
// обработчик нажатия кнопки Button3
procedure TForm1.Button3Click(Sender: TObject);
// Функция антиалиаслинга (сглаживания изображения)
// К слову сказать, процедура работает неправильно, т.к. берет значения из уже измененных пикселей
procedure AntiAliasRect(clip: tbitmap; XOrigin, YOrigin, XFinal, YFinal: Integer);
// объявление переменных
var
Memo, x, y : Integer; // Memo - временная переменная, [x, y] - координаты указывающие точку на изображении
p0, p1, p2 : pbytearray; // указатели на массивы байтов (по сути на строки картинки)
SL : TScanlines; // объект класса TScanlines
begin
// Если правая точка по оси абсцисс левее левой, то меняем их значения
if XFinal<XOrigin then begin Memo := XOrigin; XOrigin := XFinal; XFinal := Memo; end;
// Если верхняя точка по оси ординат ниже нижней, то меняем их значения
if YFinal<YOrigin then begin Memo := YOrigin; YOrigin := YFinal; YFinal := Memo; end;
// Ограничение левой точки по оси абсциссы - минимальное значение 1
XOrigin := max(1,XOrigin);
// Ограничение верхней точки по оси ординат - минимальное значение 1
YOrigin := max(1,YOrigin);
// Ограничение правой точки по оси абсцисс - максимальное значение - это ширина картинки минус 2
XFinal := min(clip.width-2,XFinal);
// Ограничение нижней точки по оси ординат - максимальное значение - это высота картинки минус 2
YFinal := min(clip.height-2,YFinal);
// устанавливаем глубину цветов картинки 24 бит (3 байта)
clip.PixelFormat := pf24bit;
// Создаем объект класса TScanlines
SL := TScanlines.Create(clip);
// Блок try - "Пытаемся делать то-то"
try
// Цикл обработки изображения по строкам сверху вниз
for y := YOrigin to YFinal do begin
// Указателю p0 присваиваем ссылку на строку предыдущую строке y
p0 := PByteArray(SL[y-1]);
// Указателю p1 присваиваем ссылку на строку y
p1 := PByteArray(SL[y]);
// Указателю p1 присваиваем ссылку на строку следующую после y
p2 := PByteArray(SL[y+1]);
// Цикл обработки строки слева направо
for x := XOrigin to XFinal do begin
// Первому байту (синяя компонента цвета, по-моемц) пикселя в точке [x, y]
// присвается усредненное значение синих компонент соседних пикселей (слева, справа, сверху и снизу)
p1[x*3] := (p0[x*3]+p2[x*3]+p1[(x-1)*3]+p1[(x+1)*3])div 4;
// То же самое для второго байта пикселя (зеленая состовляющая)
p1[x*3+1] := (p0[x*3+1]+p2[x*3+1]+p1[(x-1)*3+1]+p1[(x+1)*3+1])div 4;
// То же самое для третьего байта пикселя (красная состовляющая)
p1[x*3+2] := (p0[x*3+2]+p2[x*3+2]+p1[(x-1)*3+2]+p1[(x+1)*3+2])div 4;
end;
end;
// Финальная часть блока try - "В любом случае выполняем это"
finally
// Уничтожаем объект SL
SL.Free;
// Конец блока try
end;
end;
begin
// Вызов функции сглаживания изображения
AntiAliasRect(Image1.Picture.Bitmap, 0, 0, Image1.Picture.Bitmap.Width, Image1.Picture.Bitmap.Height);
end;
// Реализация методов класса TScanlines - он сделан для быстрого высчитывания
// указателя на конкретную строку растра, т.к. обычная функция TBitmap.ScanLine[] работает несколько тормознута из-за универсальности
{ TScanlines }
// Конструктор класса
constructor TScanlines.Create(Bitmap: TBitmap);
begin
// Выхов конструктора класса-предка
inherited Create;
// Инициализация переменных (полей)
FScanLine0 := nil; // К слову сказать, это лишнее Delphi сама присвоит nil
FScanLineIncrement := 0; // К слову сказать, это лишнее Delphi сама присвоит 0
FMaxRow := 0; // // К слову сказать, это лишнее Delphi сама присвоит 0
// Если растр не равен nil (т.е. существует обект, на который Bitmap ссылается), то
if Bitmap <> nil then begin
// указателю FScanLine0 присваиваем ссылку на нулевую строку
FScanLine0 := Bitmap.ScanLine[0];
// полю FScanLineIncrement присваиваем длину строки в байтах (разница между адресом первой и нулевой строки)
FScanLineIncrement := integer(Bitmap.Scanline[1]) -integer(FScanLine0);
// Полю FMaxRow присваиваем высоту растра (картинки)
FMaxRow := Bitmap.Height;
end;
end;
// Деструктор
destructor TScanlines.Destroy;
begin
// Вызов деструктора класса-предка
inherited;
end;
// Реализация функции GetRowPtr - возвращает указатель на строку с номером Index
function TScanlines.GetRowPtr(Index: integer): PByte;
begin
// Если Index больше либо равен нулю и больше FMaxRow
if (Index >= 0) and (Index < FMaxRow) then begin
// то result присваиваем указатель на нулевую строку FScanLine0
result := FScanLine0;
// и смещаем полученный указатель на число строк (Index)
Inc(result, FScanLineIncrement *Index);
end else
// иначе возвращаем nil
result := nil;
end;
// конец
end.
← →
antonn © (2008-01-18 21:58) [16]так ведь у TBitmap уже есть scanline О_о
← →
Kenny (2008-01-18 22:29) [17]Ты видел исходник этого сканлайна? Такое выполнять H*3 раз расточительно. Читай коменты )
← →
homm © (2008-01-19 00:02) [18]> [17] Kenny (18.01.08 22:29)
> Такое выполнять H*3 раз расточительно
Достаточно 2-х вызовов для полного счастья.
← →
Kenny (2008-01-19 12:43) [19]> Достаточно 2-х вызовов для полного счастья.
Да никто не спорит. Но задача была прокомментировать приведенный код :)
← →
Kenny (2008-01-19 12:43) [20]Кстати для картинок высотой 1 пиксель будет ошибка.
← →
homm © (2008-01-19 20:33) [21]> [20] Kenny (19.01.08 12:43)
> Кстати для картинок высотой 1 пиксель будет ошибка.
Дотаточность 2-х вызовов для наступления счастья, еще не означает недостаточность одного вызова для наступления его же, поэтому слово «будет» считаю несколько неуместным.
← →
Kenny (2008-01-19 21:24) [22]> homm © (19.01.08 20:33) [21]
Это относилось к приведенному выше коду )
← →
cerber (2008-02-05 22:30) [23]shart
Динамическая борьба с шумами это не батоны рисовать. Тут важно знать характеристики как шума так и полезного изображения. Эффективная фильтрация изображения возможна только при весьма жестких ограничениях на отношение сигнал/шум. Способ фильтрации описанный выше ничть иное как сгалаживание вычокочастоных шумов за счет инерности визуального восприятия. При такой фильтрации идет незначительная для телевизора и заметная для ЖК панели потеря резкости изображения. Лучший способ фильтрации только через статистические методы обработки изоражения и спектральные преобразования. Минус этих методов - большие "трудозатраты". Неплохие методы фильтрации реализованы в пакете Матлаб - с функциональным описанием. Читай и пробуй...
Страницы: 1 вся ветка
Форум: "Media";
Текущий архив: 2009.12.27;
Скачать: [xml.tar.bz2];
Память: 0.55 MB
Время: 0.006 c