Подтвердить что ты не робот

Сравнение производительности OpenCV: С++ и C

В настоящее время я разрабатываю приложение с использованием API OpenCV (C++). Это приложение обрабатывает видео.

На ПК все работает очень быстро. И сегодня я решил перенести это приложение на Android (чтобы использовать камеру в качестве видеовстречи). К счастью, есть OpenCV для Android, поэтому я просто добавил свой собственный код для примера приложения для Android. Все работает отлично, кроме исполнения. Я сравнивал свое приложение и обнаружил, что приложение работает с 4-5 кадрами в секунду, что на самом деле неприемлемо (у моего устройства один процессор 1 Гц) - я хочу, чтобы он работал со скоростью около 10 кадров в секунду.

Имеет ли смысл полностью переписать мое приложение на C? Я знаю, что использование таких вещей, как std::vector, очень удобно для разработчиков, но меня это не волнует.

Кажется, что интерфейс OpenCV C имеет те же функции/методы, что и интерфейс C++.

Я искал этот вопрос, но ничего не нашел.

Спасибо за любой совет.

4b9b3361

Ответ 1

Я много работал с Android и оптимизацией (я написал приложение для обработки видео, которое обрабатывает фрейм в 4 мс), поэтому я надеюсь, что дам вам некоторые подходящие ответы.

Между интерфейсом C и C++ в OpenCV нет большой разницы. Часть кода написана на C и имеет обертку C++, а также некоторую прокрутку. Любые существенные различия между ними (как измеряется Shervin Emami) - это либо регрессии, либо исправления ошибок, либо улучшения качества. Вы должны придерживаться последней версии OpenCV.

Почему бы не переписать?

Вы потратите много времени, которое вы могли бы использовать намного лучше. Интерфейс C громоздкий, и вероятность появления ошибок или утечек памяти высока. На мой взгляд, вы должны избегать этого.

Советы по оптимизации

A. Включите оптимизацию.

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

B. Профилируйте свое приложение.

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

C. Сосредоточьтесь на алгоритмах.

Более быстрый алгоритм может повысить производительность на порядки (100x). Трюк C++ даст вам, возможно, повышение производительности в 2 раза.

Классические методы:

  • Измените размер ваших видеокадров меньше. Часто вы можете извлечь информацию из изображения 200x300px, а не 1024x768. Площадь первого в 10 раз меньше.

  • Используйте более простые операции вместо сложных. Используйте целые числа вместо float. И никогда не используйте double в матрице или цикле for который выполняется тысячи раз.

  • Сделайте как можно меньше вычислений. Вы можете отслеживать объект только в определенной области изображения, а не обрабатывать его для всех фреймов? Можете ли вы сделать грубое/приблизительное обнаружение на очень маленьком изображении, а затем уточнить его на ROI в полном кадре?

D. Используйте C, где это важно

В цикле может быть смысл использовать стиль C вместо C++. Указатель на матрицу данных или массив с плавающей точкой намного быстрее, чем mat.at или std :: vector <>. Часто узким местом является вложенный цикл. Сфокусируйтесь на этом. Не имеет смысла заменять вектор <> по всему месту и спагеттизировать код.

E. Избегайте скрытых расходов

Некоторые функции OpenCV преобразуют данные в двойные, обрабатывают их, а затем конвертируют обратно в формат ввода. Остерегайтесь их, они убивают производительность на мобильных устройствах. Примеры: деформирование, масштабирование, преобразование типов. Кроме того, преобразования цветового пространства, как известно, ленивы. Предпочитает полутоновое сечение, полученное непосредственно из нативного YUV.

F. Использование векторизации

Процессоры ARM реализуют векторизацию с помощью технологии NEON. Научитесь использовать его. Это мощно!

Небольшой пример:

float* a, *b, *c;
// init a and b to 1000001 elements
for(int i=0;i<1000001;i++)
    c[i] = a[i]*b[i];

можно переписать следующим образом. Это более многословно, но намного быстрее.

float* a, *b, *c;
// init a and b to 1000001 elements
float32x4_t _a, _b, _c;
int i;
for(i=0;i<1000001;i+=4)
{  
    a_ = vld1q_f32( &a[i] ); // load 4 floats from a in a NEON register
    b_ = vld1q_f32( &b[i] );
    c_ = vmulq_f32(a_, b_); // perform 4 float multiplies in parrallel
    vst1q_f32( &c[i], c_); // store the four results in c
}
// the vector size is not always multiple of 4 or 8 or 16. 
// Process the remaining elements
for(;i<1000001;i++)
    c[i] = a[i]*b[i];

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

Еще один способ начать с нуля - сконфигурировать кодированный SSE-оптимизированный код в OpenCV в NEON. SSE является эквивалентом NEON в процессорах Intel, и многие функции OpenCV используют его, как здесь. Это код фильтрации изображений для uchar-матриц (обычный формат изображения). Вы должны слепо преобразовывать инструкции один за другим, но примите это как пример для начала.

Вы можете больше узнать о NEON в этом блоге и следующих сообщениях.

G. Обратите внимание на захват изображения.

Это может быть удивительно медленным на мобильном устройстве. Оптимизация - это специфическое устройство и ОС.

Ответ 2

Прежде чем принимать какое-либо решение, подобное этому, вы должны прокомментировать свой код, чтобы найти горячие точки в вашем коде. Без этой информации любые изменения, которые вы делаете, чтобы ускорить работу, будут догадками. Вы пробовали этот профайлер Android NDK?

Ответ 3

Есть некоторые тесты производительности, выполненные hervin imami на его веб-сайте. Вы можете проверить это, чтобы получить некоторые идеи.

http://www.shervinemami.info/timingTests.html

Надеюсь, что это поможет.

(И также было бы неплохо, если бы вы поделились своими собственными результатами где-нибудь, если у вас есть какой-то способ повышения производительности.)

Ответ 4

Я предполагаю, что вопрос должен быть сформулирован так: C быстрее, чем С++? И ответ нет. Оба скомпилированы на собственный машинный язык, а С++ - так быстро, как C Что касается STL (особенно стандарт ISO), также разработаны и позаботились о том, чтобы они были такими же быстрыми, как указатели +, они обеспечивают гибкость. Единственная причина использования C - ваша платформа не поддерживает С++ В моем скромном открытии не конвертируйте все в C, так как вы, вероятно, получите почти такую ​​же производительность. и попробуйте вместо этого улучшить свой код или использовать другие функции opencv, чтобы делать то, что вы хотите.

Не уверен? ну тогда напишите простую функцию, один раз в C и один раз на С++, и запустите ее в цикле 100 миллионов раз и сами измерьте время. Возможно, это поможет вам принять правильное решение.

Ответ 5

Я никогда не использовал C или С++ в Android. Но на ПК вы можете заставить С++ работать так же быстро, как C-код (иногда даже быстрее). Большая часть С++ была разработана специально для предоставления большего количества функций, но не за счет скорости (шаблоны решаются во время компиляции). Большинство компиляторов довольно хорошо оптимизируют ваш код, и ваши вызовы std::vector будут встроены, и код будет почти таким же, как с использованием собственного массива C.

Я бы посоветовал вам искать другой способ повысить производительность. Возможно, есть некоторые мультимедийные аппаратные расширения в Android, к которым вы можете получить доступ и использовать для оптимизации кода.

Ответ 6

В нескольких тестах я заметил, что:

  • Интерфейс C (IplImage) в несколько раз быстрее при обращении к пикселям непосредственно вместо использования метода Mat.at(x, y), когда я преобразовал свое приложение на С++ в C, у меня было увеличение производительности в 3 раза в моей процедуре обнаружения blob

  • Интерфейс С++ сбой в определенных процедурах при вызове из внешних приложений (например, LabView), тогда как он работает при вызове тех же подпрограмм в C. Пример этого - FindContours и cvFindContours

  • C гораздо более совместим со встроенными устройствами. Тем не менее, я еще ничего не делал в этой области.

Ответ 7

У меня были подобные проблемы на устройствах IOS и обсуждение Максимальная скорость от IOS/iPad/iPhone включает в себя некоторые подсказки, применимые и к другим мобильным платформам.