Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.12.27;
Скачать: CL | DM;

Вниз

Удаление шума на изображении   Найти похожие ветки 

 
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 вся ветка

Текущий архив: 2009.12.27;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.012 c
2-1257755267
night_light
2009-11-09 11:27
2009.12.27
не запускается отладчик одного из проектов


8-1200828685
artkil
2008-01-20 14:31
2009.12.27
Способы вывода видео на экран


2-1257500197
Бульбаш
2009-11-06 12:36
2009.12.27
Переключение между гридами на этапе проектирования


2-1257739169
Андрей Смирнов
2009-11-09 06:59
2009.12.27
Как правильно передать массив URL в Функцию (WinInet)


2-1257928226
1987
2009-11-11 11:30
2009.12.27
Handle s