Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "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
2-1256271770
Delphi2020
2009-10-23 08:22
2009.12.27
Проблема с сохранением Raw в exe


2-1257865044
monyk
2009-11-10 17:57
2009.12.27
Время в delphi


3-1227877267
Xmen
2008-11-28 16:01
2009.12.27
Таблица из текстового файла


2-1257412157
zorik
2009-11-05 12:09
2009.12.27
xml отчеты word


15-1256236718
Kolan
2009-10-22 22:38
2009.12.27
Статья на хабаре про Делфи «создание и уничтожение объектов...»





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский