Быстрое сшивание панорамы

 

Download paper as PDF

Введение

Панорамная съемка уже давно получила широкое распространение, она поддерживается встроенными приложениями для работы с камерой на большинстве смартфонов и планшетов. Приложения, сшивающие панорамы, работают так: они получают несколько изображений, находят совпадающие элементы и соединяют их. Обычно производители устройств используют для сшивания собственные методы, работающие очень быстро. Существует также несколько альтернативных решений с открытым исходным кодом

Дополнительные сведения о реализации сшивания панорам, а также о новом подходе, когда для снятия полной круговой панорамы используются две камеры, см. в моей предыдущей публикации: http://software.intel.com/ru-ru/articles/dual-camera-360-panorama-application. В этом документе приводится краткое сравнение двух популярных библиотек, а затем следует подробное описание создания приложения, способного быстро сшивать изображения в панораму.

OpenCV* и PanoTools*

Я протестировал две самых популярных библиотеки с открытым исходным кодом: OpenCV и PanoTools. Я начал с PanoTools — это достаточно развитая библиотека для сшивания, доступная для Windows*, Mac OS* и Linux*. В ней поддерживается множество расширенных возможностей, обеспечивается стабильное качество. Вторая рассмотренная библиотека — OpenCV. OpenCV — это очень крупный проект, содержащий несколько библиотек по обработке изображений, с обширной базой пользователей. Он выпускается для Windows, Mac OS, Linux, Android* и iOS*. Обе библиотеки включают образцы приложений для сшивания. Приложение в составе PanoTools выполнило работу за 1 минуту 44 секунды. Приложение в составе OpenCV — за 2 минуты 16 секунд. Хотя скорость у PanoTools выше, мы решили использовать OpenCV в качестве отправной точки, учитывая значительную пользовательскую базу этой библиотеки и ее доступность на мобильных платформах.

Описание первоначального приложения и сценария тестирования

Мы будем использовать образец приложения OpenCV cpp-example-stitching_detailed в качестве отправной точки. Приложение запускает конвейер сшивания, который включает несколько раздельных этапов. Вот краткое назначение этих этапов.

  1. Импорт изображений.
  2. Поиск элементов.
  3. Попарное сравнение.
  4. Деформация изображений.
  5. Составление.
  6. Смешение.

Для тестирования мы использовали планшет с четырехъядерной «системой на кристалле» Intel® Atom™ Z3770 с 2 ГБ оперативной памяти под управлением Windows 8.1. Нагрузка состояла в сшивании 16 изображений с разрешением 1280 х 720.

Многопоточный поиск элементов с помощью OpenMP*

Большая часть этапов конвейера состоит из повторяющейся работы, которая осуществляется с изображениями, не зависящими одно от другого. Вследствие этого данные этапы отлично подходят для многопоточной обработки. Все эти этапы используют цикл for, поэтому можно очень просто распараллелить эти блоки кода с помощью OpenMP.

Первый этап, который мы распараллеливаем, — поиск элементов. Сначала добавляем директиву компилятора OpenMP над циклом for:

#pragma omp parallel for
for (int i = 0; i < num_images; ++i)

Теперь цикл будет выполняться в несколько потоков. Но в цикле мы задаем значения переменных fullj'mg и img. Из‑за этого возникнет конкуренция между потоками, и это повлияет на результат. Самый простой способ решить эту проблему — преобразовать переменные в векторы. Берем следующие объявления переменных:

Mat full_img, img;

и заменяем их на:

vector<Mat> full_img(num_images);
vector<Mat> img(num_images);

Теперь в цикле мы изменим каждое вхождение каждой переменной на ее новое имя.

full_img becomes full_img[i]
img becomes img[i]

Содержимое, загруженное в full_img и img, используется позже в приложении, поэтому для ускорения не будем высвобождать память. Удалите эти строки:

full_img.release();
img.release();

Затем можно удалить эту строку из этапа составления:

full_img = imread(img_names[img_idx]);

На full_img мы снова ссылаемся при масштабировании в цикле составления. Снова изменяем имена переменных:

full_img становится full_img[img_idx]

img становится img[img_idx]

Итак, первый цикл распараллелен. Теперь нужно распараллелить цикл деформации. Сначала добавляем директиву компилятора, чтобы сделать цикл параллельным:

#pragma omp parallel for
for (int i = 0; i < num_images; ++i)

Это все, что необходимо, чтобы цикл стал параллельным, но можно еще немного оптимизировать этот раздел. Существует второй цикл for сразу после первого. Мы можем перенести работу из него в первый цикл, чтобы сократить количество запускаемых потоков. Переместите эту строку в первый цикл for:

images_warped[i].convertTo(images_warped_f[i], CV_32F);

Также нужно перенести определение переменной images_warped_f выше первого цикла:

vector<Mat> images_warped_f(num_images);


Теперь можно распараллелить цикл составления. Добавляем директиву компилятора перед циклом for:

#pragma omp parallel for
for (int img_idx = 0; img_idx < num_images; ++img_idx)

Третий цикл распараллелен. После всех этих изменений нагрузка выполняется за 2 минуты 8 секунд, то есть на 8 секунд быстрее, чем раньше.

Оптимизация алгоритма попарного сравнения

Попарное сравнение элементов реализовано так, что каждое изображение сравнивается с каждым другим изображением, из-за чего объем работы возрастает по формуле O(n^2). В этом нет необходимости, поскольку нам известен порядок, в котором следуют изображения. Надо переписать алгоритм так, чтобы каждое изображение сравнивалось только с соседними по порядку изображениями.

Для этого изменяем вот этот блок:

vector<MatchesInfo> pairwise_matches;
BestOf2NearestMatcher matcher(try_gpu, match_conf);
matcher(features, pairwise_matches);
matcher.collectGarbage();

на это:

vector<MatchesInfo> pairwise_matches;
BestOf2NearestMatcher matcher(try_gpu, match_conf);
Mat matchMask(features.size(),features.size(),CV_8U,Scalar(0));
for (int i = 0; i < num_images -1; ++i)
{
    matchMask.at<char>(i,i+1) =1;
}
matcher(features, pairwise_matches,matchMask);
matcher.collectGarbage();

Теперь время обработки уменьшилось до 1 минуты 54 секунд, то есть мы выиграли 14 секунд. Обратите внимание, что изображения необходимо импортировать в последовательном порядке.

Оптимизация параметров

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

Мы изменили параметры по умолчанию:

double work_megapix = 0.6;
double seam_megapix = 0.1;
float conf_thresh = 1.f;
string warp_type = "spherical";
int expos_comp_type = ExposureCompensator::GAIN_BLOCKS;
string seam_find_type = "gc_color";

на это:

double work_megapix = 0.08;
double seam_megapix = 0.08;
float conf_thresh = 0.5f;
string warp_type = "cylindrical";
int expos_comp_type = ExposureCompensator::GAIN;
string seam_find_type = "dp_colorgrad";

После изменения этих параметров обработка нагрузки заняла 22 секунды, что на 1 минуту 40 секунд быстрее. Такое ускорение обусловлено главным образом изменением значений параметров work_megapix и seam_megapix. Обработка существенно ускорилась, поскольку теперь мы выполняем сравнение и сшивание для очень маленьких изображений. При этом уменьшается количество отличительных элементов, которые можно найти и сравнить, но за счет усовершенствованного алгоритма сравнения мы можем слегка пожертвовать точностью.

Удаление ненужной работы

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

if (!is_compose_scale_set)
{
    …               
}

if (blender.empty())
{
    …
}

Обратите внимание, что в коде деформации есть одна строка, где нужно заменить full_img[img_idx] на full_img[0]. За счет этого изменения мы можем ускорить обработку на 2 секунды: теперь она занимает 20 секунд.

Перемещение поиска элементов

Мы сделали еще одно изменение, но его реализация зависит от того, как именно работает приложение сшивания. В нашем случае приложение снимает изображения, а затем сшивает их сразу после съемки всех изображений. Если в вашем приложении такая же ситуация, можно перенести ту часть конвейера, которая отвечает за поиск элементов, на этап съемки изображений. Для этого нужно запускать алгоритм поиска элементов сразу же после съемки первого изображения и сохранять данные до того момента, когда они понадобятся. В наших экспериментах это обусловило ускорение сшивания примерно на 20 %, то есть в данном случае время сшивания сокращается до 16 секунд.

Логирование

Изначально логирование не включено, но отметим, что при его включении несколько снижается производительность. Мы обнаружили, что, если включить логирование, время сшивания возрастает примерно на 10 %. Поэтому в итоговой версии приложения важно отключить логирование.

Заключение

Учитывая популярность приложений для панорамной съемки на мобильных платформах, важно располагать решением с открытым исходным кодом, способным быстро сшивать изображения в панораму. Ускорив сшивание изображений, мы сделали приложение более удобным для конечных пользователей. Благодаря всем этим изменениям нам удалось сократить общее время сшивания с 2 минут 18 секунд до 16 секунд, то есть ускорить обработку приблизительно в 8,5 раза. Подробная информация приведена в этой таблице.

Изменение

Уменьшение времени

Многопоточность с OpenMP*

0:08

Алгоритм попарного сравнения

0:14

Оптимизация начальных параметров

1:40

Удаление ненужной работы

0:02

Перемещение поиска элементов

0:04

Программное обеспечение и нагрузки, использованные в тестах производительности, могли быть оптимизированы для достижения высокой производительности только на микропроцессорах Intel. Тесты производительности, такие как SYSmark* и MobileMark*, проводятся на определенных компьютерных системах, компонентах, программах, операциях и функциях. Любые изменения любого из этих элементов могут привести к изменению результатов. При выборе приобретаемых продуктов следует обращаться к другой информации и тестам производительности, в том числе к тестам производительности определенного продукта в сочетании с другими продуктами.

Конфигурации: четырехъядерная «система на кристалле» Intel® Atom™ Z3770 с 2 ГБ оперативной памяти под управлением Windows 8.1. Дополнительные сведения см. на сайте http://www.intel.com/performance

 

Примечания

ИНФОРМАЦИЯ В ДАННОМ ДОКУМЕНТЕ ПРИВЕДЕНА ТОЛЬКО В ОТНОШЕНИИ ПРОДУКТОВ INTEL. ДАННЫЙ ДОКУМЕНТ НЕ ПРЕДОСТАВЛЯЕТ ЯВНОЙ ИЛИ ПОДРАЗУМЕВАЕМОЙ ЛИЦЕНЗИИ, ЛИШЕНИЯ ПРАВА ВОЗРАЖЕНИЯ ИЛИ ИНЫХ ПРАВ НА ИНТЕЛЛЕКТУАЛЬНУЮ СОБСТВЕННОСТЬ. КРОМЕ СЛУЧАЕВ, УКАЗАННЫХ В УСЛОВИЯХ И ПРАВИЛАХ ПРОДАЖИ ТАКИХ ПРОДУКТОВ, INTEL НЕ НЕСЕТ НИКАКОЙ ОТВЕТСТВЕННОСТИ И ОТКАЗЫВАЕТСЯ ОТ ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ ГАРАНТИЙ В ОТНОШЕНИИ ПРОДАЖИ И/ИЛИ ИСПОЛЬЗОВАНИЯ СВОИХ ПРОДУКТОВ, ВКЛЮЧАЯ ОТВЕТСТВЕННОСТЬ ИЛИ ГАРАНТИИ ОТНОСИТЕЛЬНО ИХ ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ, ОБЕСПЕЧЕНИЯ ПРИБЫЛИ ИЛИ НАРУШЕНИЯ КАКИХ-ЛИБО ПАТЕНТОВ, АВТОРСКИХ ПРАВ ИЛИ ИНЫХ ПРАВ НА ИНТЕЛЛЕКТУАЛЬНУЮ СОБСТВЕННОСТЬ.

КРОМЕ СЛУЧАЕВ, СОГЛАСОВАННЫХ INTEL В ПИСЬМЕННОЙ ФОРМЕ, ПРОДУКТЫ INTEL НЕ ПРЕДНАЗНАЧЕНЫ ДЛЯ ИСПОЛЬЗОВАНИЯ В СИТУАЦИЯХ, КОГДА ИХ НЕИСПРАВНОСТЬ МОЖЕТ ПРИВЕСТИ К ТРАВМАМ ИЛИ ЛЕТАЛЬНОМУ ИСХОДУ.

Корпорация Intel оставляет за собой право вносить изменения в технические характеристики и описания своих продуктов без предварительного уведомления. Проектировщики не должны полагаться на отсутствующие характеристики, а также характеристики с пометками «зарезервировано» или «не определено». Эти характеристики резервируются Intel для будущего использования, поэтому отсутствие конфликтов совместимости для них не гарантируется. Информация в данном документе может быть изменена без предварительного уведомления. Не используйте эту информацию в окончательном варианте дизайна.

Продукты, описанные в данном документе, могут содержать ошибки и неточности, из-за чего реальные характеристики продуктов могут отличаться от приведенных здесь. Уже выявленные ошибки могут быть предоставлены по запросу.

Перед размещением заказа получите последние версии спецификаций в региональном офисе продаж Intel или у местного дистрибьютора.

Копии документов с порядковым номером, ссылки на которые содержатся в этом документе, а также другую литературу Intel можно получить, позвонив по телефону 1-800-548-4725 либо на сайте: http://www.intel.com/design/literature.htm

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

Intel, эмблема Intel и Atom являются товарными знаками корпорации Intel в США и в других странах.

© Intel Corporation, 2014. Все права защищены.

*Прочие наименования и товарные знаки могут быть собственностью третьих лиц.

Для получения подробной информации о возможностях оптимизации компилятора обратитесь к нашему Уведомлению об оптимизации.
ВложениеРазмер
Иконка PDF Fast Panorama Stitching.pdf536.34 КБ
Возможность комментирования русскоязычного контента была отключена. Узнать подробнее.