Jump to content
Compvision.ru
Sign in to follow this  
RinOS

Многопоточность и OpenCV

Recommended Posts

Всем привет! Кто ни будь программировал многопоточные приложения, с OpenCV?

Какие подводные камни? Нормально ли сочетаются такие вещи как OpenCV и многопоточность?

Share this post


Link to post
Share on other sites
Всем привет! Кто ни будь программировал многопоточные приложения, с OpenCV?

Какие подводные камни? Нормально ли сочетаются такие вещи как OpenCV и многопоточность?

C++ Builder приложение является многопоточным :)

Писал еще приложение работающее с Ethernet отдельным потоком, работает вполне хорошо.

Проблем быть не должно.

Share this post


Link to post
Share on other sites
Всем привет! Кто ни будь программировал многопоточные приложения, с OpenCV?

Какие подводные камни? Нормально ли сочетаются такие вещи как OpenCV и многопоточность?

Проблем с многопоточностью не будет. Да и исходники открыты-то, можно самому убедиться: потоки лишние не создаются, локальный стек потока для внутренних целей также не используется (в отличие от той же Intel jpeg library, будь она неладна).

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

Share this post


Link to post
Share on other sites
Однако покотобезопасной, в классическом смысле этого слова, библиотека не является:

Это плохо((

обращения к одному объекту из разных потоков надо синхронизировать.

К примеру о каких объектах идет речь?

К примеру возьмем функцию cvCanny, десяток потоков вызывают эту функцию, со своими данными (одновременно). Будут ли тут какие нибудь траблы?

У меня в ПО архитектура такая:

Есть программа в ней N потоков, в цикле обращаются к DLL, и вызывают функцию.

Вот схема:

HpvXR4vOVG.gif

Если что то не понятно, поясню!

Так вот, когда вызыватся process через некоторе время сыпяться ексепшены из cxcore.dll ((

Если расставить критические секции перед вызовом process(), то все нормально, но тк эта функция выполняется некотое время, другие потоки ждут, и получается не многопоточность, а последовательно... имхо

Share this post


Link to post
Share on other sites
Это плохо((

К примеру о каких объектах идет речь?

К примеру возьмем функцию cvCanny, десяток потоков вызывают эту функцию, со своими данными (одновременно). Будут ли тут какие нибудь траблы?

У меня в ПО архитектура такая:

Есть программа в ней N потоков, в цикле обращаются к DLL, и вызывают функцию.

Вот схема:

HpvXR4vOVG.gif

Если что то не понятно, поясню!

Так вот, когда вызыватся process через некоторе время сыпяться ексепшены из cxcore.dll ((

Если расставить критические секции перед вызовом process(), то все нормально, но тк эта функция выполняется некотое время, другие потоки ждут, и получается не многопоточность, а последовательно... имхо

Похоже что критические секции это единственный путь, но согласен что это уже не многопоточность.

Share this post


Link to post
Share on other sites
К примеру о каких объектах идет речь?

К примеру возьмем функцию cvCanny, десяток потоков вызывают эту функцию, со своими данными (одновременно). Будут ли тут какие нибудь траблы?

C cvCanny проблем не будет. Проблемы при многопоточности возникают, если в функции используются static переменные (не помню, есть ли аналог в Делфи), всевозможные глобальные состояния. В cvCanny же всё чисто.

Так вот, когда вызыватся process через некоторе время сыпяться ексепшены из cxcore.dll ((

Если расставить критические секции перед вызовом process(), то все нормально, но тк эта функция выполняется некотое время, другие потоки ждут, и получается не многопоточность, а последовательно... имхо

Если говорить об архитектуре, то она у тебя не многопоточная именно из-за единой функции Process. Как правило, единая функция/объект-менеджер занимается только созданием/удалением объектов. Алгоритм примерно таков:

1. Поток запрашивает о необходимости создания объекта/функции.

2. Запрашиваемый объект/функция создаётся в менеджере, указатель или интерфейс передаётся потоку. Менеджер также хранит у себя данный указатель и идентификатор потока. Этот этап необходимо синхронизировать критическими секциями/мьютексами.

3. Далее поток, минуя менеджер, работает с указателем/интерфейсом. Тут синхронизация не нужна.

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

На разных языках сделать такое можно с разными трудозатратами. Зачастую помогает автоматическая сборка мусора, всякие умные указатели в С++ или всё делать вручную.

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

Про вылеты в cxcore трудно сказать. Я бы скомпилировал её с отладочной информацией и посмотрел в дебаггере место вылета и стек вызовов.

Share this post


Link to post
Share on other sites
C cvCanny проблем не будет. Проблемы при многопоточности возникают, если в функции используются static переменные (не помню, есть ли аналог в Делфи), всевозможные глобальные состояния. В cvCanny же всё чисто.

Мда...) в одной функции memstorage был объявлен как статик :)

2. Запрашиваемый объект/функция создаётся в менеджере, указатель или интерфейс передаётся потоку. Менеджер также хранит у себя данный указатель и идентификатор потока. Этот этап необходимо синхронизировать критическими секциями/мьютексами.

Классно) подумаю над тем что бы сделать через интерфейс) Спасибо!

Share this post


Link to post
Share on other sites
Мда...) в одной функции memstorage был объявлен как статик :)

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

1. Поставляешь с программой эту xxx.dll.

2. Для каждого своего i-го потока создаёшь физическую копию этой длл: xxx_i.dll. Подключаешь её в этом потоке динамически (LoadLibrary и т.д), статическая линковка не подходит.

3. Поток завершается, делается FreeLibrrary и xxx_i.dll удаляется с диска.

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

Share this post


Link to post
Share on other sites
2. Для каждого своего i-го потока создаёшь физическую копию этой длл: xxx_i.dll. Подключаешь её в этом потоке динамически (LoadLibrary и т.д), статическая линковка не подходит.

Да такая идея, посещала меня) Ну это на крайний случай))

Share this post


Link to post
Share on other sites

А как сделать, чтобы вывод изображения с камеры не было замедленным?

while(1)

{

capimg=cvQueryFrame(video);

...

}

получается, что не все кадры обрабатываются и видеовывод получается замедленным. (ну не настолько медленным)

Реально ли сделать чтобы 30fps было?

Например организовать с помощью потоков.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Точнее я не так выразился- не "замедленное" движение, а не плавное движение. То есть не все кадры захватываются.

проц 3ГГц камера 30кадров\сек 640х480 пикселей.(Logitech E1000)

ситуация такая - пока openCV обрабатывает участок кода между вызовами QueryFrame, то естественно она теряет кадры если не выполняет этот участок кода хотя бы за 1/30 секунды.

Вот например, когда я вывожу изображение с камеры в MPLAYER, то сообщается сколько фреймов получено, а сколько сброшено :

mplayer -vf mirror -fps 6 tv:// -tv driver=v4l2:device=/dev/video0

v4l2: 62 frames successfully processed, 189 frames dropped.

Mplayer показывает плавные движения.

И сравнил сколько фреймов отработала моя программа с количеством фреймов, захваченные mplayer`ом

программа - 40 фреймов за 10 секунд

mplayer 62 фрейма за 10 секунд

Share this post


Link to post
Share on other sites

Если процессор хотя бы двухъядерный, то можно сделать 2 потока.

Вариант 1.

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

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

Вариант 2.

Сделать очередь, в которую первый поток будет складывать захваченные кадры. Второй поток, соответственно, будет из неё читать и обрабатывать. Если размер очереди будет превышать некоторые разумные пределы (скажем 150 кадров), то выбрасывать кадры из очереди, но не подряд, а равномерно. Таким образом, пропадание кадров не приведёт к "дёрганию" картинки.

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

Share this post


Link to post
Share on other sites

Здравствуйте уважаемые.

Вопрос короткий и по существу:

Имеется скажем 2, 3 или 4 камеры, необходимо работать с каждой в своем потоке.

Кто решал подобный вопрос, как реализовать многопоточность ?

Спасибо.

Share this post


Link to post
Share on other sites

Насколько я знаю, в OpenCV не механизма создания и управления потоками.

Share this post


Link to post
Share on other sites

Здравствуйте уважаемые.

Вопрос короткий и по существу:

Имеется скажем 2, 3 или 4 камеры, необходимо работать с каждой в своем потоке.

Кто решал подобный вопрос, как реализовать многопоточность ?

Спасибо.

На каждый поток(Например Boost::thread или pthread) создавйте свой Iplimage cvCapture и своё окошко воспроизведения , если вообщих чертах.

Share this post


Link to post
Share on other sites

тут так и ничего не сказали про многопоточность(или я не понял).

все таки как она реализована в opencv?

т.е. распараллелены ли функции уже заранее? (у меня все время только 1 ядро загружается)

или надо самому использовать Openmp или какие то треды?

Share this post


Link to post
Share on other sites

Это другой аспект многопоточности - здесь говорилось о потокобезопасности.

1. OpenMP, вроде, подключить можно. Во всяком случае в коде OpenCV есть максросы _OPENMP и USE_OPENMP. Надо их включить и перекомпилировать OpenCV. Попробуешь?

2. Судя по параметрам CMake, OpenCV может использовать Intel Threading Building Blocks - более удобный аналог OpenMP. Надо их поставить, переконфигурировать с помощью CMake OpenCV и перекомпилировать.

3. Можно самому использовать потоки (например из boost'а).

Share this post


Link to post
Share on other sites

А у меня такой вопрос...

Захватываю видео в основном потоке процесса(который создан изначально) все остальное поотключал, нагрузка на проц 12 процентов

Зпхватываю видео в потоке, остальную всю обработку изображения поотключал, тоже. нагрузка 50 - 60. Это как? работа выполняется одна и таже

Share this post


Link to post
Share on other sites

1. Лучше выложить код, чтобы не гадать.

2. Как передаёшь изображения из потока захвата в поток отрисовки?

Share this post


Link to post
Share on other sites

вообщем поэкспериментирую с opencv2.1 перенесу на ноут(т.к. там 4 ядра и есть вебка) попробую перекомпилировать библиотеку интеловским компилятором и с поддержкой IPP и многопоточности.

Share this post


Link to post
Share on other sites

Компилировал Microsoft'овским компилятором, хотелось бы узнать поподробней, как её откомпилировать с поддержкой многопоточности?

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

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

завязка происходит следующим образоб

IplImage * in_1 = &out_2; индексы обозначают библиотеки

И С СОБЫТИЯМИ HANDLE inE_1 = outE_2;

Не это упрощённый вариант могу выложить просто архив, с исходниками, что б помсмотрели

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×