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

Отображать изображение во втором потоке, 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.

Какое из этих направлений было бы лучшим местом для начала?

4b9b3361

Ответ 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);