Опубликован: 20.08.2013 | Уровень: для всех | Доступ: платный | ВУЗ: Новосибирский Государственный Университет
Самостоятельная работа 2:

Базовые операции обработки изображений

3. Программная реализация

3.1. Разработка консольного редактора изображений

3.1.1. Требования к приложению

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

  1. Организация диалога с пользователем. Предполагается вывод перечня пунктов меню (загрузка изображения и набор операций) и возможность выбора определенной операции. Отметим, что программа должна обеспечивать многократное выполнение различных операций.
  2. Отображение исходного изображения.
  3. Отображение результата применения операции.
  4. Контроль корректности вводимых пользователем данных.
3.1.2. Структура консольного приложения

Сначала необходимо создать и настроить проект в среде Mcrosoft Visual Studio. Процедура подробно была описана ранее в работе "Сборка и установка библиотеки OpenCV. Использование библиотеки в среде Microsoft Visual Studio", поэтому в данном разделе остановимся на разработке структуры приложения.

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

Для упрощения разработки введем несколько констант:

  • kMenuTabs – количество пунктов меню (фактически число допустимых операций);
    const int kMenuTabs = 12; 
              
  • menu – массив строк, содержащий описание пунктов меню;
    const char* menu[] = 
    { 
      "0 - Read image", 
      "1 - Apply linear filter", 
      "2 - Apply blur(...)", 
      "3 - Apply medianBlur(...)", 
      "4 - Apply GaussianBlur(...)", 
      "5 - Apply erode(...)", 
      "6 - Apply dilate(...)", 
      "7 - Apply Sobel(...)", 
      "8 - Apply Laplacian(...)", 
      "9 - Apply Canny(...)", 
      "10 - Apply calcHist(...)", 
      "11 - Apply equalizeHist(...)" 
    }; 
              
  • winNames – массив строк, содержащий названия окон, которые будут использованы при отображении результата выполнения той или иной операции;
    const char* winNames[] = 
    { 
      "Initial image", 
      "filter2d", 
      "blur", 
      "medianBlur", 
      "GaussianBlur", 
      "erode", 
      "dilate", 
      "Sobel", 
      "Laplacian", 
      "Canny", 
      "calcHist", 
      "equalizeHist" 
    }; 
              
  • maxFileNameLen – максимальная длина строки, содержащей название файла с изображением;
    const int maxFileNameLen = 1000; 
              
  • escCode – код символа ESC для организации выхода из приложения.
    const int escCode = 27; 
              

Рассмотрим структуру основной функции. По сути, данная функция содержит цикл опроса пользователя до момента необходимости выхода из программы. Выход из программы организован посредством нажатия клавиши ESC. Цикл включает в себя выполнение нескольких операций:

  1. Выбор пункта меню. Отметим, что выбор операции обработки изображения не должен быть доступен до тех пор, пока оно не будет загружено. Реализуется посредством функции chooseMenuTab, которая обеспечивает печать пунктов меню с использованием функции printMenu, контроль ввода данных и загрузку изображения с помощью функции библиотеки OpenCV loadImage.
  2. Применение операции обработки изображения, отображение исходного и результирующего изображений. Выполняется при вызове функции applyOperation.
  3. Ожидание нажатия произвольной клавиши для продолжения работы приложения, либо нажатия ESC для выхода из приложения. Для реализации ожидания используется встроенная функция OpenCV waitKey.
    void printMenu(); 
    void chooseMenuTab(int &activeMenuTab, Mat &srcImg); 
    void loadImage(Mat &srcImg); 
     
    int main(int argc, char** argv) 
    { 
      Mat srcImg; // исходное изображение 
      char ans; 
      int activeMenuTab = -1; 
      do 
      { 
        // вызов функции выбора пункта меню 
        chooseMenuTab(activeMenuTab, srcImg); 
        // применение операций 
        applyOperation(srcImg, activeMenuTab); 
        // вопрос о необходимости продолжения 
        printf("Do you want to continue? ESC - exit\n"); 
        // ожидание нажатия клавиши 
        ans = waitKey(); 
      } 
      while (ans != escCode); 
      destroyAllWindows(); // закрытие всех окон 
      srcImg.release(); // освобожение памяти 
      return 0; 
    }
              

Перейдем к реализации необходимых функций.

  1. printMenu – функция вывода пунктов меню на консоль. Реализуется в виде прохода по элементам константного массива, содержащего описания пунктов меню.
    void printMenu() 
    { 
      int i = 0; 
      printf("Menu items:\n"); 
      for (i; i < kMenuTabs; i++) 
      { 
        printf("\t%s\n", menu[i]); 
      } 
      printf("\n"); 
    } 
              
  2. chooseMenuTab – функция выбора пункта меню. Функция выполняет запрос ввода идентификатора пункта меню до тех пор, пока не будет введено корректное значение. Заметим, что операции обработки изображения не могут быть выбраны, пока не загружено изображение. Функция возвращает индекс выбранного меню activeMenuTab и загруженное изображение srcImg.
    void chooseMenuTab(int &activeMenuTab, Mat &srcImg) 
    { 
      int tabIdx; 
      while (true) 
      { 
        // print menu items 
        printMenu(); 
        // get menu item identifier to apply operation 
        printf("Input item identifier to apply \ 
          operation: "); 
        scanf("%d", &tabIdx); 
        if (tabIdx == 0) 
        { 
          // read image 
          loadImage(srcImg); 
        } 
        else if (tabIdx >=1 && tabIdx < kMenuTabs && 
          srcImg.data == 0) 
        { 
          // read image 
          printf("The image should be read to apply\ 
            operation!\n"); 
          loadImage(srcImg); 
        } 
        else if (tabIdx >=1 && tabIdx < kMenuTabs) 
        { 
          activeMenuTab = tabIdx; 
          break; 
        } 
      } 
    } 
              
  3. loadImage – функция загрузки изображения. Функция реализована в виде цикла, в котором выполняется запрос на ввод полного имени изображения и контроль корректности операции чтения изображения. Возвращает загруженное изображение srcImg.
    void loadImage(Mat &srcImg) 
    { 
      char fileName[maxFileNameLen]; 
      do 
      { 
        printf("Input full file name: "); 
        scanf("%s", &fileName); 
        srcImg = imread(fileName, 1); 
      } 
      while (srcImg.data == 0); 
      printf("The image was succesfully read\n\n"); 
    } 
              
  4. applyOperation – функция применения операции обработки изображения. Принимает на вход исходное изображение src и индекс операции operationIdx. Функция содержит оператор множественного выбора, предполагается, что в зависимости от выбранной операции выполняется вызов той или иной функции обработки с предварительным вводом входных параметров этих функций. Далее осуществляется отображение исходного и результирующего изображений. Объявление и реализацию данной функции поместим в отдельный модуль.
    int applyOperation(const Mat &src, const int operationIdx) 
    { 
      char key = -1; 
      Mat dst; 
      switch (operationIdx) 
      { 
      case 1: 
        { 
          // TODO: "1 - Apply linear filter" 
          break; 
        } 
      // TODO: Apply another operations (from 2 to 11) 
      } 
      // show initial image 
      namedWindow(winNames[0], 1); 
      imshow(winNames[0], src); 
     
      // show processed image 
      namedWindow(winNames[operationIdx]); 
      imshow(winNames[operationIdx], dst); 
     
      return 0; 
    }   
              

Реализацию функций операций обработки изображений с организацией ввода необходимых параметров предоставляем читателю в качестве самостоятельной работы. Пример организации диалога с пользователем показан ниже (рис. 7.12).

Диалог с пользователем

Рис. 7.12. Диалог с пользователем

*Разработка редактора изображений с графическим интерфейсом с использованием функций OpenCV, реализованных на базе Qt

Разработка редактора изображений с графическим интерфейсом на базе Qt требует выполнения ряда предварительных действий:

  1. Установка библиотек Qt. Для установки необходимо загрузить Qt libraries 4.x for Windows (VS 2010) с официальной страницы проекта [11] и далее следовать подсказкам инсталлятора.
  2. Сборка исходных кодов библиотеки OpenCV с опцией (-D WITH_QT=YES), предусматривающей возможность последующего использования интерфейсных компонент на базе Qt. Подробнее процедура сборки OpenCV описана в лабораторной работе "Сборка и установка библиотеки OpenCV. Использование библиотеки в среде Microsoft Visual Studio". Отметим, что установочный файл содержит сборку исходных кодов, не предусматривающую возможность использования Qt-компонент.
  3. Создание консольного приложения в среде Microsoft Visual Studio и установка свойств проекта, обеспечивающих использование функционала библиотеки OpenCV.

После предварительной подготовки инфраструктуры необходимо выполнить создание и настройку проекта в Visual Studio по схеме, описанной ранее. Далее можно использовать все доступные функции библиотеки OpenCV, реализованные на базе Qt [12]. Количество доступных функций ограничено, тем не менее, для создания минимального графического интерфейса предоставляемого набора вполне достаточно: создание окон с базовым набором операций просмотра (сохранение, масштабирование изображения и т.п., рис. 7.13), создание кнопочных элементов, полос прокрутки и др.

Создание окна просмотра изображения с использованием функции namedWindow, реализованной на базе Qt

Рис. 7.13. Создание окна просмотра изображения с использованием функции namedWindow, реализованной на базе Qt

Читателю предлагается самостоятельно продумать структуру приложения и разработать его программную реализацию.

4. Контрольные вопросы

  1. Какой эффект наблюдается в результате применения операции эрозии к бинарному изображению?
  2. Какой эффект наблюдается в результате применения операции дилатации к бинарному изображению?
  3. В каких ситуациях имеет смысл применять операции замыкания и размыкания?
  4. Какую информацию позволяет получить гистограмма изображения?
  5. Что позволяет получить применение оператора Собеля с ядром
    \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1\end{bmatrix}?
  6. Что позволяет получить применение оператора Собеля с ядром
    \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1\end{bmatrix}?
  7. Перечислите основные способы повышения контраста изображений. Приведите принципиальные отличия в вычислительных схемах.
  8. Перечислите некоторые способы выделения ребер на изображении, предложенные в настоящей работе. Приведите последовательность операций, которые необходимо выполнить для реализации каждого из рассмотренных способов.

5. Дополнительные задания

  1. Добавьте в разработанную структуру консольного графического редактора поддержку операций, описанных в данной лабораторной работе.
  2. Добавьте в разработанный консольный графический редактор возможность сохранения изображений, которые получены в результате применения различных операций.
  3. Добавьте возможность рисования геометрических примитивов в разработанный консольный редактор. Предусмотрите возможность удаления отрисованных примитивов.
  4. Разработайте редактор изображений с использованием графических компонент библиотеки OpenCV, реализованных на базе Qt.
Александра Максимова
Александра Максимова

При прохождении теста 1 в нем оказались вопросы, который во-первых в 1 лекции не рассматривались, во-вторых, оказалось, что вопрос был рассмаотрен в самостоятельно работе №2. Это значит, что их нужно выполнить перед прохождением теста? или это ошибка?
 

Алена Борисова
Алена Борисова

В лекции по обработке полутоновых изображений (http://www.intuit.ru/studies/courses/10621/1105/lecture/17979?page=2) увидела следующий фильтр:


    \begin{array}{|c|c|c|}
    \hline \\
    0 & 0 & 0 \\
    \hline \\
    0 & 2 & 0 \\
    \hline \\
    0 & 0 & 0 \\
    \hline 
    \end{array} - \frac{1}{9} \begin{array}{|c|c|c|}
    \hline \\
    0 & 0 & 0 \\
    \hline \\
    0 & 1 & 0 \\
    \hline \\
    0 & 0 & 0 \\
    \hline 
    \end{array}

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

Что вижу я в конструкции фильтра (скорее всего ошибочно): F(x, y) = 2 * I(x, y) - 1/9 I(x, y) = 17/9 * I(x, y), где F(x, y) - яркость отфильтрованного пикселя, а I(x, y) - яркость исходного пикселя с координатами (x, y). Что означает обычное повышение яркости изображения, при этом без учета соседних пикселей (так как их множители равны 0).

Объясните, пожалуйста, как данный фильтр может повышать четкость изображения?

Сергей Кротов
Сергей Кротов
Россия
Дмитрий Донсков
Дмитрий Донсков
Россия, Москва, Московский Авиационный Институт