Логотип 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));
    }
}
Добавьте свой комментарий, почитайте уже добавленные комментарии или войдите, чтобы подписаться/отписаться.
OpenId
Предпросмотр
Улыбка Подмигивание Дразнит Оскал Смех Огорчение Сильное огорчение Шок Сумасшествие Равнодушие Молчание Крутизна Злость Бешенство Смущение Сожаление Влюблённость Ангел Демон Задумчивость Рука-лицо Не могу смотреть Жирный Курсив Подчёркивание Зачёркивание Размер шрифта Гиперссылка Цитата
Загрузка…