Отображать изображение во втором потоке, OpenCV?
У меня есть петля, чтобы снимать изображения с высокоскоростного framegrabbger со скоростью 250 кадров в секунду.
/** Loop processes 250 video frames per second **/
while(1){
AcquireFrame();
DoProcessing();
TakeAction();
}
В то же время я хотел бы, чтобы пользователь мог следить за тем, что происходит. Пользователь должен видеть только изображения со скоростью около 30 кадров в секунду (или меньше). Как настроить второй поток, который так часто отображает текущий кадр?
Thread(){
cvShowImage();
Wait(30); /** Wait for 30 ms **/
}
Я нахожусь на Windows на четырехъядерном процессоре Intel с использованием MinGW, gcc и OpenCV 1.1. Основными критериями являются то, что поток отображения должен занимать как можно меньше времени от моего основного цикла обработки. Каждые миллисекунды считаются.
Я попытался использовать CreateThread()
для создания нового потока с cvShowImage()
и cvWaitKey()
, но очевидно, что эти функции не являются потокобезопасными,
Я рассматриваю возможность использования OpenMP, но некоторые люди сообщают о проблемах с OpenMP и OpenCV. Я также рассматриваю возможность использования DirectX DirectDraw, потому что, по-видимому, это очень быстро. но выглядит сложным и, очевидно, существуют проблемы с использованием Windows DLL с MinGw.
Какое из этих направлений было бы лучшим местом для начала?
Ответы
Ответ 1
Ok. Настолько неловко мой вопрос - это также собственный ответ.
Используя CreateThread()
, CvShowImage()
и CvWaitKey()
, как описано в моем вопросе, фактически работает - вопреки некоторым публикациям в Интернете, которые предлагают иначе.
В любом случае я реализовал что-то вроде этого:
/** Global Variables **/
bool DispThreadHasFinished;
bool MainThreadHasFinished;
iplImage* myImg;
/** Main Loop that loops at >100fps **/
main() {
DispThreadHasFinished = FALSE;
MainThreadHasFinished = FALSE;
CreateThread(..,..,Thread,..);
while( IsTheUserDone() ) {
myImg=AcquireFrame();
DoProcessing();
TakeAction();
}
MainThreadHasFinished = TRUE;
while ( !DisplayThreadHasFinished ) {
CvWaitKey(100);
}
return;
}
/** Thread that displays image at ~30fps **/
Thread() {
while ( !MainThreadHasFinished ) {
cvShowImage(myImg);
cvWaitKey(30);
}
DispThreadHasFinished=TRUE;
return;
}
Когда я изначально разместил этот вопрос, мой код терпел неудачу по несвязанным причинам. Надеюсь, это поможет!
Ответ 2
Поскольку для захвата фрейма не требуется использовать пользовательский интерфейс, я бы установил дополнительный поток для обработки захвата кадра и имел исходный поток, который обрабатывает пользовательский интерфейс, отображает образцы кадров. Если вы попытаетесь отобразить захваченный в данный момент кадр, вам придется заблокировать данные (что обычно довольно медленно). Чтобы этого избежать, я бы отобразил фрейм-один (или, возможно, два) "за" тот, который в настоящее время захвачен, поэтому нет конкуренции между захватом и отображением данных. Вам все равно придется следить за тем, чтобы приращение текущего номера кадра было потокобезопасным, но это довольно просто - используйте InterlockedIncrement в потоке захвата.
Ответ 3
Извините, я не могу дать вам лучший ответ прямо сейчас, но кажется, что ваш вопрос касается не структуры вашей программы, а скорее инструмента, который вы должны использовать для реализации многопоточности. Для этого я бы рекомендовал Qt. Я использую Qt какое-то время, но сейчас я получаю многопоточность.
Мне кажется, что ваш лучший выбор может быть QReadWriteLock. Это позволяет вам читать с изображения, но поток читателя откажется от его блокировки, когда поток писателя приходит. В этом случае вы можете сохранить копию последнего изображения и отобразить его, если изображение заблокировано для записи.
Извините еще раз, что я не могу быть более подробным, но, как я уже сказал, я просто вникаю в это. Я в основном стараюсь делать то же, что и вы, но не так быстро:). Удачи!
Ответ 4
Я не уверен, почему это происходит, но я добавил cvWaitKey после каждого cvShowImage, и изображение было правильно отображено.
cvShowImage(myImage);
cvWaitKey(1);