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

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

2.3. Обучение словаря с использованием алгоритма кластеризации K-means

Одним из основных подходов к обучению словаря дескрипторов является использование алгоритмов кластеризации, в частности, K-means [5 ], который разбивает множество объектов на заранее известное число кластеров. В основе данного алгоритма лежит итерационная процедура, в рамках которой вычисляются центроиды кластеров (как математическое ожидание относящихся к данным кластерам объектов), а потом обновляется информация о принадлежности каждого объекта к кластерам путем выбора ближайшего центроида.

Для обучения словаря с использованием алгоритма K-means в библиотеке OpenCV реализован класс BOWKMeansTrainer, унаследованный от базового абстрактного класса BOWKMeansTrainer. Рассмотрим методы данного класса.

BOWKMeansTrainer(int clusterCount, 
  const TermCriteria& termcrit = TermCriteria(), 
  int attempts=3, int flags=KMEANS_PP_CENTERS) 
    

Параметры конструктора данного класса соответствуют параметрам функции kmeans библиотеки OpenCV.

  • сlusterCount – число слов в словаре (соответствует числу кластеров в алгоритме K-means).
  • termcrit – критерий остановки алгоритма кластеризации (максимальное число итераций или(и) достижение заданной точности). Точность задается в соответствующем поле criteria.epsilon. Если в результате очередной итерации алгоритма центроиды изменились на величину, меньше данного параметра, то алгоритм останавливает работу.
  • attempts – число запусков алгоритма кластеризации со случайно выбранными центроидами на начальной итерации алгоритма.
  • flags – параметр, определяющий способ инициализации центроидов на начальной итерации алгоритма. Возможные значения:

    • KMEANS_RANDOM_CENTERS – использовать случайно выбранные центроиды.
    • KMEANS_PP_CENTERS – использовать эвристику Arthur and Vassilvitskii [5 ]. Данный параметр показал лучшую эффективность на практике и используется по умолчанию.

Для формирования выборки объектов, на которой будет проходить обучение словаря, должен быть использован метод add:

void BOWTrainer::add(const Mat& descriptors) 
    

В качестве параметра данной функции передается набор (матрица) дескрипторов особых точек, вычисленных ранее.

После того, как выборка сформирована, обучение словаря выполняется с использованием метода cluster.

Mat BOWTrainer::cluster() 
    

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

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

// descriptors – предвычисленный набор дескрипторов 
// изображений, используемый при построении словаря; 
// vocSize – размер словаря; 
Mat BuildVocabulary(const std::vector<Mat>& descriptors, 
int vocSize) 
{ 
  // создаем объект класса BOWTrainer с числом 
  // кластеров, равным vocSize, и остальными 
  // параметрами, используемыми по умолчанию 
  BOWKMeansTrainer bowTrainer(vocSize); 
  // добавляем дескрипторы особых точек с изображений, 
  // используемых при обучении словаря 
  for (size_t i = 0; i < descriptors.size(); i++) 
  { 
    bowTrainer.add(descriptors[i]); 
  } 
  // вызываем метод обучения словаря 
  Mat voc = bowTrainer.cluster(); 
  return voc; 
} 
    

2.4. Вычисление признаковых описаний изображений

Большинство известных алгоритмов обучения с учителем требует описания каждого объекта в виде векторов одинаковой длины. В связи с этим напрямую использовать вычисленные значения дескрипторов, объединенные в один вектор, для решения задачи классификации не представляется возможным, т.к. в общем случае число ключевых точек на изображениях различно. К тому же, такое представление в любом случае не обладало бы инвариантностью относительно многих преобразований изображения, т.к. при этом обычно изменяется расположение данных точек и, следовательно, расположение дескрипторов внутри объединенного вектора. Данная проблема решается при использовании bag-of-words подхода [13 ], в котором изображение описывается не самими дескрипторами, а частотами встречаемости их различных типов на изображении. Типы дескрипторов описываются словарем, который содержит центроиды кластеров дескрипторов особых точек. Таким образом, в случае, когда словарь уже вычислен, признаковое описание изображения вычисляется по следующей схеме:

  • детектирование ключевых точек на изображении и вычисление их дескрипторов;
  • нахождение для каждого вычисленного дескриптора ближайшего к нему центроида кластера;
  • вычисление признакового описания изображения в виде нормированной гистограммы (i-ый бин гистограммы соответствует числу вхождений i-го слова из словаря в описание изображения, что соотвествует числу дескрипторов, отнесенных к i-му кластеру).

Библиотека OpenCV содержит класс BOWImgDescriptorExtractor, реализующий данную схему. Рассмотрим подробнее методы данного класса.

BOWImgDescriptorExtractor::BOWImgDescriptorExtractor( 
      const Ptr<DescriptorExtractor>& dextractor, 
      const Ptr<DescriptorMatcher>& dmatcher) 
    

Рассмотрим параметры конструктора данного класса:

  • dextractor – алгоритм, вычисляющий дескрипторы в ключевых точках
  • dmatcher – алгоритм, используемый для нахождения ближайшего центроида к текущему дескриптору ключевой точки (обычно используется L2 метрика)

Для того чтобы задать словарь, используемый при вычислении признакового описания изображения, необходимо вызвать метод setVocabulary

void BOWImgDescriptorExtractor::setVocabulary(const Mat&
vocabulary) 
    

В качестве параметра данному методу передается матрица, содержащая центроиды кластеров (обычно это матрица возвращается методом cluster класса BOWTrainer).

Вычисление признакового описания изображения осуществляется при помощи метода compute.

void BOWImgDescriptorExtractor::compute(const Mat& image, 
    vector<KeyPoint>& keypoints, 
    Mat& imgDescriptor, 
    vector<vector<int>>* pointIdxsOfClusters=0, 
    Mat* descriptors=0 ) 
    

Рассмотрим параметры данного метода:

  • image – входное изображение.
  • keypoints – массив ключевых точек на изображении, в которых вычисляются дескрипторы.
  • imgDescriptor – вычисленное признаковое описание изображения.
  • pointIdxsOfClusters – набор индексов дескрипторов, относящихся к тому или иному кластеру.
  • descriptors – вычисленные значения дескрипторов ключевых точек.

Два последних параметра являются необязательными.

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

// img – исходное изображение 
// voc – словарь дескрипторов ключевых точек; 
// imgDesc – вычисленное признаковое описание изображения 
void ComputeImgDescriptor(Mat& img, Mat& voc, Mat& imgDesc) 
{ 
  // создаем SIFT детектор ключевых точек 
  Ptr<FeatureDetector> featureDetector = 
          FeatureDetector::create("SIFT"); 
  // создаем объект класса вычисления 
  // SIFT дескрипторов ключевых точек 
  Ptr<DescriptorExtractor> dExtractor = 
        DescriptorExtractor::create("SIFT"); 
  // создаем объект класса, находящего ближайший 
  // к дескриптору центроид (по L2 метрике) 
  Ptr<DescriptorMatcher> descriptorsMatcher = 
      DescriptorMatcher::create("BruteForce"); 
  // создаем объект класса, вычисляющего 
  // признаковое описание изображений 
  Ptr<BOWImgDescriptorExtractor> bowExtractor = new 
            BOWImgDescriptorExtractor( 
              dExtractor, 
              descriptorsMatcher); 
  // устанавливаем используемый словарь 
  // дескрипторов ключевых точек 
  bowExtractor->setVocabulary(voc); 
  // находим ключевые точки на изображении 
  vector<KeyPoint> keypoints; 
  featureDetector->detect(img, keypoints); 
  // вычисляем признаковое описание изображения 
  bowExtractor->compute(img, keypoints, imgDesc); 
} 
    
Александра Максимова
Александра Максимова

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

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

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