читать последовательные кадры OpenCV с помощью cvQueryframe - PullRequest
4 голосов
/ 31 декабря 2010

У меня есть основной вопрос относительно cvQueryFrame () в OpenCV.

У меня есть следующий код:

<code>IplImage *frame1,*frame2;
frame1 = cvQueryFrame(capture);
frame2 = cvQueryFrame(capture);

Теперь мой вопросявляется: * если frame1 является указателем на первый кадр, является ли frame2 указателем на 2-й кадр?Так будут ли два вызова cvQueryFrame() читать последовательные кадры?

Я подумал, что сначала проверю себя, но указатели frame1, frame2, похоже, имеют одинаковое шестнадцатеричное значение.: s Мне просто нужно захватывать два кадра за раз, а затем обрабатывать их.

Заранее спасибо

РЕДАКТИРОВАТЬ: я обнаружил в Google, что вызов cvQueryFrame () дважды возвращает один и тот же указатель,теперь я немного растерялся.Если я использую call it только один раз в цикле while, кадры прогрессируют, но нет, если я вызываю его дважды?Есть ли простой способ получить два кадра?

Ответы [ 3 ]

9 голосов
/ 31 декабря 2010

cvQueryFrame() возвращает указатель на «закрытый» внутренний буфер OpenCV, который он всегда заполняет последним захваченным кадром.
Если вы хотите 2 кадра, вам нужно будет кэшировать копию.Как только вы выделите (например, cvCloneImage()) место для предыдущего кадра, вы можете использовать cvCopy(), чтобы скопировать только данные изображения. не используйте cvCloneImage() внутри цикла, поскольку это очень неэффективно из-за выделения внутренней памяти (и освобождения, иначе у вас также будут утечки памяти).

Обновление: код будет выглядеть примерно так:

IplImage* currFrame = 0;
IplImage* prevFrame = 0;
CvCapture* cap = cvCaptureFromAVI("sample.avi");   
currFrame = cvQueryFrame( cap );

 // Clone the frame to have an identically sized and typed copy
prevFrame  = cvCloneImage( currFrame );

while(currFrame = cvQueryFrame( cap ))
{
    // process the video using currFrame and prevFrame...

    // ...


    // When done, overwrite prevFrame with current copy in preparation
    // for the next frame.
    cvCopy( currFrame , prevFrame); 
} 

cvReleaseImage( &img1 );
cvReleaseCapture( &cap );

Примечание: Часто вы можете избежать этого "избыточного" времени копированиявыполнив преобразование вместо этого.
Например, скажем, ваш дисплей цветной, но ваша обработка в оттенках серого.Вам нужны только 2 последовательных копии в оттенках серого.Так как вам все равно потребуется преобразовать в оттенки серого, вы можете сделать это прямо из захваченного кадра, избегая, таким образом, избыточного cvCopy().Чтобы сохранить предыдущий кадр, нужно просто поменять местами указатели между двумя выделенными изображениями в оттенках серого.

1 голос
/ 31 декабря 2010

хорошо, следуя ответу Лорана: я считаю, что ключ - это cvCloneImage ().cvCloneImage создает новую копию исходного изображения, включая заголовок, ROI, imageData и т. д., а затем указывает frame2 на эти новые данные.

Поскольку cvQueryFrame является оболочкой для cvGrabFrame и cvRetrieveFrame, я не хотел разделять функции, поэтому с небольшой модификацией я все еще могу использовать cvQueryFrame.

Ниже мое модифицированное решение.

<code>
IplImage *frame = cvQueryFrame(capture); //to read properties of frame.
IplImage *frame2 = NULL;</p>

<p>while (1){
    if(frame2) 
        frame = cvCloneImage(frame2); // copy image to allow grabbing next frame
    frame2 = cvQueryFrame(capture); //read next frame
    if(!frame2) break; //if frame cannot be read, EOF so break from loop
}

Надеюсь, вы понимаете, что я здесь сделал.Не стесняйтесь задавать больше вопросов.

1 голос
/ 31 декабря 2010

Хорошо!

Вы должны сделать копию своего кадра.frame1 = cvQueryFrame (capture);это указатель, как вы сказали.

Код, который я нашел:

IplImage* img1(null), img2(null);
CvCapture* cap = cvCaptureFromAVI("mavideo.avi");
img2 = cvQueryFrame( cap );
img1 = cvCloneImage( img2 ); // on alloue une nouvelle image

while( cvGrabFrame( cap ) )
{
    cvCopy( img2, img1 ); // copie de l'image, pas du pointeur
    img2 = cvRetrieveFrame( cap );
} 

cvReleaseCapture( &cap );
cvReleaseImage( &img1 );

Вы можете заменить время ключом ожидания или чем угодно, но если вы сделаете это, используйте

img2 = cvQueryFrame( cap ); 

вместо

img2 = cvRetrieveFrame( cap );

потому что у вас больше не будет

cvGrabFrame( cap )

Я не знаю, ясно ли я, так что ..Я остаюсь здесь ^^

Наслаждайся;)

Лоран

...