Логотип StingRay

Социальные сети
FacebookInstagramRSSTwitterYouTubeВ контактеОдноклассники
FacebookInstagramRSSTwitterYouTubeВ контактеОдноклассники
Силуэт человека

Курсовая работа по обработке изображений

Настоящие методические указания предназначены, прежде всего, для студентов моей специальности 230101 «Вычислительные машины, комплексы, системы и сети», которые хотели бы успешно выполнить курсовую работу по дисциплине с громким названием «Обработка изображений, распознавание образов и мультимедиа». Также они могут быть полезны для студентов и других специальностей и вообще всех интересующихся обработкой изображений и распознаванием текста.

Наложение шума и фильтры шумоподавления (сглаживания) Зашумлённое изображение

Речь пойдёт, в основном, о фильтрах шумоподавления, но для того чтобы можно было быстрее и нагляднее оценивать их работу, требуется реализовать ещё и возможность искусственного зашумления изображения.

Зашумление можно выполнять любым способом, изменяющим каким-либо образом значения каких-то точек изображения. Например, так:

var
  Image: TImage;
  I, X, Y: Integer;

begin
  for I := 1 to 100 do
    begin
      X := Random (Image.Width);
      Y := Random (Image.Height);
      Image.Canvas.Pixels [X, Y] := clBlack; // Случайные точки становятся чёрными
    end;
end;

Для начала введём один специальный термин: апертура фильтра – это размер окна (части изображения), с которым фильтр работает непосредственно в данный момент времени; окно это постепенно передвигается по изображению слева направо и сверху вниз на один пиксель (то есть на следующем шаге фильтр работает с окном, состоящим не только из элементов исходного изображения, но и из элементов, ранее подвергнувшихся преобразованию, – своего рода «принцип снежного кома»).

Кроме того, заметим, что если речь идёт об окне, представляющем собой строку элементов изображения ([X][X][X]), то такое преобразование называется одномерным; соответственно, существует и двумерное преобразование.

Сглаживающий фильтр

Основывается на следующем принципе: находится среднее арифметическое значение всех элементов рабочего окна изображения (отдельно по каждому из каналов), после чего это среднее значение становится значением среднего элемента (речь идёт о нечётной апертуре фильтра; для двумерного случая средним элементом будет средний элемент по горизонтали и вертикали, то есть центр квадрата). Выглядит это примерно так:

var
  Image: TImage;
  X, Y: Integer;

begin
  for X := 1 to Image.Width - 2 do
    for Y := 1 to Image.Height - 2 do with Image.Canvas do
      Pixels [X, Y] := (
        Pixels [X - 1, Y - 1] + Pixels [X - 1, Y] + Pixels [X - 1, Y + 1] +
        Pixels [X,     Y - 1] + Pixels [X,     Y] + Pixels [X,     Y + 1] +
        Pixels [X + 1, Y - 1] + Pixels [X + 1, Y] + Pixels [X + 1, Y + 1]) div 9;
end;

Внимание! Под действие фильтра могут не попадать крайние элементы изображения (так получается в приведённом примере), поэтому при искусственном зашумлении их лучше преднамеренно не зашумлять, либо обрабатывать каким-то образом частный случай крайних точек (например, для угла изображения при апертуре 3 суммировать не 9 точек, а 4, и результат отправлять в этот самый угол).

Медианный фильтр

Основывается на нахождении медианы – среднего элемента (но не среднего арифметического) последовательности в результате её упорядочения по возрастанию/убыванию и присваиванию найденного значения только среднему элементу (речь снова о нечётной апертуре). Например, для той же апертуры 3 и двумерного фильтра (как в примере выше) мы должны упорядочить 9 точек (например, по возрастанию), после чего значение 5й точки упорядоченной последовательности отправить в центр окна фильтра (3х3). Для упорядочения можно использовать любой из известных методов сортировки, например, быструю сортировку Хоара:

procedure SortBytes (var Bytes: array of Byte; Left, Right: Integer);
  var
    I, J: Integer;
    W, X: Byte;
  begin
    I := Left;
    J := Right;
    X := Bytes [(Left + Right) div 2];
    repeat
      while Bytes [I] < X do I := I + 1;
      while X < Bytes [J] do J := J – 1;
      if I lt;= J then
        begin
          W := Bytes [I];
          Bytes [I] := Bytes [J];
          Bytes [J] := W;
          I := I + 1;
          J := J – 1;
        end;
    until I > J;
    if Left < J then
      SortBytes (Bytes, Left, J);
    if I < Right then
      SortBytes (Bytes, I, Right);
  end;

Для фиксированной малой апертуры можно использовать какой-либо вырожденный (частный) вариант сортировки, построенный на операторах условия.

Сглаживание с помощью гауссиана

Дискретное гауссово ядро сглаживания (апертуру фильтра) можно получить, построив массив размером (2k + 1) x (2k + 1), значение элемента (i, j) которого равно

Симметричное гауссово ядро в 3-мерном пространстве
Элемент массива для гауссиана,

где Сигма – это среднеквадратическое отклонение гауссиана.

Название ядра объясняется тем, что именно такой вид имеет плотность вероятности для двумерной нормальной (или гауссовой) случайной переменной с заданной ковариантностью. Данное ядро сглаживания образует такое взвешенное среднее, для которого в центре ядра весовые коэффициенты пикселей намного больше, чем на его границах.

Этот подход можно обосновать качественно: сглаживание подавляет шум, поддерживая требование, чтобы пиксели были похожи на своих соседей. Уменьшая весовые коэффициенты для отдалённых пикселей, можно быть уверенным, что для них это требование будет не таким жёстким. Качественный анализ приводит к таким выводам:

  • Если Сигма очень мала (например, < 1), то сглаживание даст незначительный результат, поскольку весовые коэффициенты всех пикселей, находящихся не в центре, будут очень малыми.
  • Для большей Сигма у соседних пикселей весовые коэффициенты при применении схемы взвешенного среднего будут больше, что, в свою очередь, означает, что среднее значение будет сильно стремиться к согласованию с соседями – это будет хорошая оценка значения пикселя, а за счёт размывания исчезнет бо́льшая часть шума.
  • Ядро с большой Сигма приведёт к тому, что вместе с шумом исчезнет и бо́льшая часть элементов изображения.

Если Сигма слишком мала, то ненулевым будет только один элемент матрицы. Если же Сигма велика, то k также должно быть больши́м, иначе не будет учтён вклад пикселей, которые должны входить со значительными весовыми коэффициентами.

Ниже приведён пример реализации данного типа сглаживания на языке C#.

//----------------------------------------------------------------------------
// Функция:  Gauss (C) 2007 Павел Денисов
// Описание: Сглаживание с помощью гауссиана. Для правильного расчёта краевых
//           точек Поверхность увеличивается по ширине и высоте на 2k.
//           Значение точек в расширенной области заполняются значениями
//           краевых точек.
// Вход:     bmp   – объект Bitmap;
//           sigma – "сигма" в формуле гауссиана;
//           k     – k в формуле гауссиана.
//----------------------------------------------------------------------------

public void Gauss(ref Bitmap bmp, double sigma, short k)
{
  int       kk;
  int       x, y, u, v;
  double    p;
  byte[,]   M;
  double[,] H;
  Color     cl;

  kk = 2 * k;
  sigma *= sigma;

  H = new double[kk + 1, kk + 1];
  M = new byte[bmp.Width + kk, bmp.Height + kk];

  // Формирование ядра
  for(x = 0; x <= kk; x++) // "=" – захватить саму точку
    for(y = 0; y <= kk; y++)
    {
      p = -((x - k - 1) * (x - k - 1) + (y - k - 1) * (y - k - 1));
      H[x, y] = (1.0 / (2.0 * Math.PI * sigma) * Math.Exp(p / (2.0 * sigma)));
    }

  // Формирование вспомогательной матрицы
  for(x = 0; x < bmp.Width + kk; x++)
    for(y = 0; y < bmp.Height + kk; y++)
    {
      if(y <= k)
      {
        if(x < k)                     cl = bmp.GetPixel(0, 0);
        else if(x >= (bmp.Width + k)) cl = bmp.GetPixel(bmp.Width - 1, 0);
        else                          cl = bmp.GetPixel(x - k, 0);
      }
      else if(y >= (bmp.Height + k))
      {
        if(x < k)                     cl = bmp.GetPixel(0, bmp.Height - 1);
        else if(x >= (bmp.Width + k)) cl = bmp.GetPixel(bmp.Width - 1, bmp.Height - 1);
        else                          cl = bmp.GetPixel(x - k, bmp.Height - 1);
      }
      else
      {
        if(x < k)                     cl = bmp.GetPixel(0, y - k);
        else if(x >= (bmp.Width + k)) cl = bmp.GetPixel(bmp.Width - 1, y - k);
        else                          cl = bmp.GetPixel(x - k, y - k );
      }
      M[x, y] = cl.R;
    }

  // Свёртка
  for(x = 0; x < bmp.Width; x++)
    for(y = 0; y < bmp.Height; y++)
    {
      p = 0.0;
      for(u = 0; u <= kk; u++)
        for(v = 0; v <= kk; v++)
          p += H[u, v] * M[u + x, v + y];
      bmp.SetPixel(x, y, Color.FromArgb((byte)p, (byte)p, (byte)p));
    }
}
05.12.2007 18:06:07 Илья (IP) Цитата #1
Всё бы хорошо, только не описан метод сглаживания Гаусса, со значениями «сигма» = 1,0 и k = 3, на который ссылается основная страница… а ведь он, как я понимаю, один из основных, если не самый.🤪
06.12.2007 05:34:30 Станислав (IP) Цитата #2
Что Вы понимаете под «основной страницей»? Если статью «Распознавание текста на примере защитной картинки SMS-отправки», в которой написано:
Сглаживание (размытие) изображения с целью шумоподавления осуществляем с помощью одного из методов раздела «Наложение шума и фильтры шумоподавления», например, по Гауссу со значениями «сигма» = 1,0 и k = 3.
Так в этом контексте указанная статья является не основной, а прикладной к данному описанию методов обработки изображений.
Но Вы, Илья, в любом случае несомненно правы в том, что отсутствие в указанном разделе описания сглаживания по Гауссу есть упущение – я попробую в ближайшее время его устранить своими силами, силами автора статьи, ну или Вашими силами – если Вы найдёте его описание раньше и пришлёте мне. А пока могу предложить Вам воспользоваться любым другим методом сглаживания – среди них много хороших. 😊
07.12.2007 17:41:51 Илья (IP) Цитата #3
И есть еще у меня одно маленькое замечание (или совет для начинающих). В свете того, что 3-я Delphi уже канула в Лету, и у Canvas'а по умолчанию палитра 24-битная, то приведённый код:
var
  Image: TImage;
  X, Y: Integer;
begin
  for X := 1 to Image.Width - 2 do
    for Y := 1 to Image.Height - 2 do with Image.Canvas do
      Pixels [X, Y] := (
        Pixels [X - 1, Y - 1] + Pixels [X - 1, Y] + Pixels [X - 1, Y + 1] +
        Pixels [X,     Y - 1] + Pixels [X,     Y] + Pixels [X,     Y + 1] +
        Pixels [X + 1, Y - 1] + Pixels [X + 1, Y] + Pixels [X + 1, Y + 1]) div 9;
end;

утратил свой смысл, и суммирование нужно действительно производить по каналам, как и указано в статье, предварительно разложив TColor по ним с помощью функций GetXValue. 😉
27.12.2007 01:51:04 Станислав (IP) Цитата #4
Илья, благодарю Вас за внимательность и замечание об отсутствии здесь описания одного из сглаживающих фильтров (Гаусса). Я связался Павлом Денисовым, автором статьи, в которой этот, не описанный ранее метод был упомянут, и он подготовил дополнение, которое уже на данной странице и опубликовано (см. выше под заголовком «Сглаживание с помощью гауссиана») – пользуйтесь на здоровье! 😊
19.10.2009 23:32:08 ч0 (IP) Цитата #5
В разделе про гаусовское размытие в приведенном примере, написанном на C# есть неточность, ибо после применения фильтра изображение чуть-чуть съезжает в левый-верхний угол…
20.11.2009 07:26:29 Станислав (IP) Цитата #6
Я написал автору данного кода письмо с изложением предполагаемой Вами неточности – если он проверит, подтвердит и исправит её, то мы внесём изменения тут. Спасибо.
15.02.2010 12:46:16 Павел Денисов (IP) Цитата #7
Нельзя сказать что "после применения фильтра изображение чуть-чуть съезжает в левый-верхний угол", потому что после применения фильтра это уже другое изображение. Пиксели исходного изображения, по сути, не соответствуют пикселям получившегося изображения. Да, на некоторых изображениях после применения фильтра можно заметить визуальный эффект незначительного смещения изображения, причем на разных изображениях "движение" происходит в разные стороны.
Верность алгоритма легко проверить, указав k = 0, для того чтобы гауссово ядро имело размер в один пиксель и, присвоив этому пикселю значение 1.0, тем самым, исключив какое-либо влияние ядра на формирующее изображение. В итоге легко убедится, что исходное и сформированное изображения идентичны.
Добавьте свой комментарий или войдите, чтобы подписаться/отписаться.
OpenId
Предпросмотр
Улыбка Подмигивание Дразнит Оскал Смех Огорчение Сильное огорчение Шок Сумасшествие Равнодушие Молчание Крутизна Злость Бешенство Смущение Сожаление Влюблённость Ангел Демон Задумчивость Рука-лицо Не могу смотреть Жирный Курсив Подчёркивание Зачёркивание Размер шрифта Гиперссылка Цитата
Загрузка…