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

Классификация изображений с использованием bag-of-words методов

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

3.1. Разработка программы классификации изображений с использованием bag-of-words методов

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

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

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

    • нахождение ключевых точек и вычисление их дескрипторов;
    • обучение словаря;
    • построение признакового описания изображений;
    • формирование обучающей выборки и обучение классификатора "случайный лес".
  • Выполнение следующей последовательности действий для каждого изображения из тестовой выборки:

    • нахождение ключевых точек и вычисление их дескрипторов;
    • построение признакового описания;
    • предсказание категории изображения с использованием обученного классификатора и вычисленных признаков;
  • Вывод результатов классификации изображений на тестовой выборке.
3.1.2. Структура приложения

Приложение будет состоять из набора вспомогательных функций (auxiliary.cpp/h), основного модуля, содержащего реализацию основных стадий bag-of-words подхода к классификации изображений с использованием функций OpenCV (bow.cpp/h), и файла c исходным кодом основной функции (main.cpp). В рамках лабораторной работы предлагается реализовать функции из основного модуля; вспомогательные функции и код основной функции поставляется в реализованном виде.

Рассмотрим вспомогательные функции.

void GetFilesInFolder(const string& dirPath, 
 std::vector<string>& filesList) 
      

Заполняет массив filesList списком всех файлов с расширением *.jpg из директории dirPath. Рассмотрим параметры данной функции:

  • dirPath – путь к директории, содержащей изображения
  • filesList – список всех файлов с расширением *.jpg, содержащихся в данной директории
void InitRandomBoolVector(vector<bool>& mask, double prob) 
      

Заполняет булевский вектор mask случайными значениями (true с вероятностью prob). Рассмотрим параметры данной функции:

  • mask – булевский вектор, который должен быть заполнен случайными значениями;
  • prob – вероятность того, что элементу булевского массива будет присвоено значение true.

Рассмотрим функции из модуля bow.cpp, которые необходимо реализовать в рамках лабораторной работы.

Mat TrainVocabulary(const std::vector<string>& filesList, 
    const std::vector<bool>& isVoc, 
    const Ptr<FeatureDetector>& keypointsDetector, 
    const Ptr<DescriptorExtractor>& dExtractor, 
    int vocSize) 
      

Функция возвращает построенный словарь дескрипторов особых точек и принимает на вход следующие аргументы:

  • filesList – список файлов;
  • isVoc – маска, описывающая набор изображений из filesList, используемых для построения словаря;
  • keypointsDetector – детектор ключевых точек;
  • dExtractor – алгоритм, используемый для вычисления дескрипторов ключевых точек;
  • vocSize – размер словаря.

Функция должна выполнять следующую последовательность действий:

  1. Создать объект класса BOWTrainer с размером словаря, равным vocSize и остальными параметрами по умолчанию.
  2. Для каждого изображения из filesList, которое используется для построения словаря выполнить следующие действия:

    • Прочитать изображение из файла.
    • Продетектировать на изображении ключевые точки с использованием детектора keypointsDetector.
    • Вычислить дескрипторы ключевых точек с использованием алгоритма dExtractor.
    • Добавить вычисленные дескрипторы в набор дескрипторов, используемых объектом класса BOWTrainer для обучения словаря
  3. Обучить словарь.
Mat ExtractFeaturesFromImage( 
    Ptr<FeatureDetector> keypointsDetector, 
    Ptr<BOWImgDescriptorExtractor> bowExtractor, 
    const string& fileName) 
      

Функция возвращает признаковое описание изображения и принимает на вход следующие аргументы:

  • keypointsDetector – детектор ключевых точек;
  • bowExtractor – алгоритм, используемый для вычисления признакового описания изображения;
  • fileName – входной файл.

Функция должна выполнять следующую последовательность действий:

  1. Прочитать изображение из файла fileName.
  2. Продетектировать на изображении ключевые точки с использованием детектора keypointsDetector.
  3. Вычислить признаковое описание изображения с использованием bowExtractor
void ExtractTrainData(const std::vector<string>& filesList, 
  const std::vector<bool>& isTrain, 
  const Mat& responses, 
  const Ptr<FeatureDetector>& keypointsDetector, 
  const Ptr<BOWImgDescriptorExtractor>& bowExtractor, 
  Mat& trainData, 
  Mat& trainResponses) 
      

Функция предназначена для формирования обучающей выборки (trainData и trainResponses) для используемого алгоритма обучения с учителем; принимает на вход следующие аргументы:

  • filesList – список файлов;
  • isTrain – маска, описывающая набор изображений из filesList, используемых для обучения классификатора;
  • responses – ответы (категории) для файлов из filesList;
  • keypointsDetector – детектор ключевых точек;
  • bowExtractor – алгоритм, используемый для вычисления признакового описания изображения;
  • trainData (выходной параметр) – матрица, содержащая признаковые описания изображений из обучающей выборки;
  • trainResponses (выходной параметр) – матрица, содержащая ответы (категории) для изображений из обучающей выборки.

Функция должна выполнять следующую последовательность действий:

  1. Вычислить число изображений в обучающей выборке (оно равно числу элементов в массиве isTrain, значение которых равно true).
  2. Инициализировать матрицу trainData для хранения признакового описания изображений из обучающей выборки: число строк равно числу объектов в обучающей выборке, число столбцов равно размерности пространства признаков (числу слов в словаре дескрипторов особых точек, которое соответствует числу строк в словаре, который использует bowExtractor), элементами матрицы являются числа с плавающей запятой одинарной точности.
  3. Инициализировать матрицу trainResponses для хранения ответов (категорий) объектов из обучающей выборки: число строк равно числу объектов в обучающей выборке, число столбцов равно 1, элементами матрицы являются 32-битные целые числа со знаком.
  4. Для каждого изображения из filesList, которое используется для построения обучающей выборки:

    • Вычислить признаковое описание изображения.
    • Скопировать вычисленное признаковое описание изображения в соответствующую строку матрицы trainData.
    • Скопировать ответ (категорию) изображения в соответствующий элемент матрицы trainResponses.
Ptr<CvRTrees> TrainClassifier(const Mat& trainData, 
          const Mat& trainResponses) 
      

Функция возвращает обученный классификатор "случайный лес" и принимает на вход следующие аргументы:

  • trainData – матрица, содержащая признаковые описания изображений из обучающей выборки;
  • trainResponses – матрица, содержащая ответы (категории) для изображений из обучающей выборки.

Функция должна выполнять следующую последовательность действий:

  1. Создать структуру типа CvRTParams, описывающую параметры алгоритма обучения с учителем "случайный лес":

    • Критерий остановки работы алгоритма – по числу итераций.
    • Максимальное число деревьев – 200.
  2. Создать матрицу, описывающую типы входных переменных и ответа: число строк равно 1, число столбцов равно размерности пространства признаков (числу столбцов в матрице trainData) + 1, элементами матрицы являются 8-битные беззнаковые целые числа.
  3. Установить типы всех используемых признаковых переменных и ответа: все признаковые переменные являются вещественными (CV_VAR_ORDERED), ответ является категориальным (CV_VAR_CATEGORICAL).
  4. Создать объект класса CvRTrees (классификатор "случайный лес").
  5. Обучить классификатор.
float Predict(const Ptr<FeatureDetector> keypointsDetector, 
  const Ptr<BOWImgDescriptorExtractor> bowExtractor, 
  const Ptr<CvRTrees> classifier, 
  const string& fileName) 
      

Функция возвращает предсказанную категорию для изображения, хранящегося в файле fileName, и принимает на вход следующие параметры:

  • keypointsDetector – детектор ключевых точек;
  • bowExtractor – алгоритм, используемый для вычисления признакового описания изображения;
  • classifier – обученный классификатор ("случайный лес");
  • fileName – входной файл.

Функция должна выполнять следующую последовательность действий:

  1. Вычислить признаковое описание изображения.
  2. Предсказать категорию изображения с использованием обученного классификатора и вычисленного признакового описания.
Mat PredictOnTestData(const std::vector<string>& filesList, 
  const std::vector<bool>& isTrain, 
  const Ptr<FeatureDetector> keypointsDetector, 
  const Ptr<BOWImgDescriptorExtractor> bowExtractor, 
  const Ptr<CvRTrees> classifier) 
      

Функция возвращает матрицу, содержащую предсказанные категории для всех объектов из тестовой выборки, и принимает на вход следующие аргументы:

  • filesList – список файлов;
  • isTrain – маска, описывающая набор изображений из filesList, используемых для обучения классификатора;
  • keypointsDetector – детектор ключевых точек;
  • bowExtractor – алгоритм, используемый для вычисления признакового описания изображения;
  • classifier – обученный классификатор "случайный лес".

Функция должна выполнять следующую последовательность действий:

  1. Вычислить число изображений в тестовой выборке (оно равно числу элементов в массиве isTrain, значение которых равно false).
  2. Создать матрицу, используемую для хранения предсказанных категорий изображений: число строк равно числу объектов в тестовой выборке, число столбцов равно 1, элементами матрицы являются 32-битные целые числа со знаком.
  3. Для каждого изображения из тестовой выборки: предсказать его категорию и скопировать е? значение в соотвествующий элемент матрицы, хранящей предсказанные значения.
Mat GetTestResponses(const Mat& responses, 
    const vector<bool>& isTrain) 
      

Функция возвращает матрицу, содержащую правильные категории (ответы) для изображений из тестовой выборки, и принимает на вход следующие аргументы:

  • responses – ответы (категории) для всех изображений;
  • isTrain – маска, описывающая набор изображений, использованных для обучения классификатора.

Функция должна выполнять следующую последовательность действий:

  1. Вычислить число изображений в тестовой выборке (оно равно числу элементов в массиве isTrain, значение которых равно false).
  2. Создать матрицу, используемую для хранения категорий изображений: число строк равно числу объектов в тестовой выборке, число столбцов равно 1, элементами матрицы являются 32-битные целые числа со знаком.
  3. Для каждого объекта из тестовой выборки: скопировать категорию данного объекта в соотвествующий элемент матрицы, хранящей парвильные значения категорий объектов из тестовой выборки.
float CalculateMisclassificationError(Mat& responses, 
      Mat& predictions) 
      

Функция возвращает ошибку классификации (доля неправильно предсказанных категорий изображений) и принимает на вход следующие аргументы:

  • responses – правильные ответы (категории);
  • predictions – предсказанные ответы (категории).

Функция должна выполнять следующую последовательность действий:

  • Вычислить число несовпадений соответствующих элементов в массивах responses и predictions.
  • Вычислить отношение числа несовпадений к общему числу объектов.

Рассмотрим структуру основной функции приложения:

  1. Считать аргументы, переданные программе через командную строку:

    • string folder1 – путь к папке, содержащей объекты первой категории;
    • string folder2 – путь к папке, содержащей объекты второй категории;
    • string detectorType – тип детектора ключевых точек;
    • string descriptorType – тип дескрипторов ключевых точек;
    • int vocSize – размер словаря;
    • double trainProportion – доля объектов, используемых для построения словаря (и обучения классификатора "случайный лес").
  2. Инициализировать модуль nonfree, обеспечивающий работу с SIFT и SURF детекторами и дескрипторами.
  3. Создать объект класса, детектирующего ключевые точки (типа detectorType).
  4. Создать объект класса типа, вычисляющего дескрипторы ключевых точек (типа descriptorType).
  5. Создать объект класса, предназначенного для нахождения ближайшего к дескриптору "слова" из словаря дескрипторов ключевых точек (типа "BruteForce").
  6. Создать объект класса, предназначенного для вычисления признакового описания изображений.
  7. Создать массив, предназначенный для хранения списка, хранящего имена JPEG файлов из folder1 и folder2.
  8. Заполнить созданный список именами файлов из обеих категорий, вычислить число изображений, относящихся к первой и второй категории, и суммарное число изображений.
  9. Создать массив для хранения маски, описывающей разбиение изображений на тренировочную и тестовую выборки. Инициализировать его случайными значениями таким образом, чтобы доля объектов, относящихся к тренировочной выборке была равна trainProportion.
  10. Создать матрицу, содержащую категории изображений: число строк равно суммарному числу изображений, число столбцов равно 1, элементами матрицы являются 32-битные целые числа со знаком. Заполнить матрицу следующим образом: объектам, относящимся к первой категории, соотвествует значение 1, объектам, относящимся ко второй категории – -1.
  11. Обучить словарь дескрипторов ключевых точек на изображениях, относящихся к тренировочной выборке.
  12. Установить словарь.
  13. Сформировать тренировочную выборку для классификатора "случайный лес".
  14. Обучить классификатор "случайный лес" на сформированной выборке.
  15. Предсказать категории изображений, относящихся к тестовой выборке.
  16. Сформировать матрицу, содержащую правильные категории изображений из тестовой выборки.

    Вычислить и вывести ошибку классификации на тестовой выборке.

3.1.3. Параметры запуска приложения

Исходный вычислительный эксперимент необходимо провести со следующими параметрами:

  • folder1 – путь к папке crocodile;
  • folder2 – путь к папке leopards;
  • detectorType – SIFT;
  • descriptorType – SIFT;
  • vocSize – 25;
  • trainProportion – 0.5.
Александра Максимова
Александра Максимова

При прохождении теста 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).

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

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