image-processing - docs - opencv tutorials
leer marcos sucesivos OpenCV usando cvQueryframe (3)
Tengo una pregunta básica con respecto a cvQueryFrame () en OpenCV.
Tengo el siguiente código:
IplImage *frame1,*frame2;
frame1 = cvQueryFrame(capture);
frame2 = cvQueryFrame(capture);
Ahora mi pregunta es: si frame1
es un puntero al primer fotograma, ¿ frame2
es un puntero al segundo fotograma? ¿Las dos llamadas a cvQueryFrame()
leerán cuadros sucesivos?
Pensé en verificarme primero, pero los punteros frame1
, frame2
parecen tener el mismo valor hexadecimal. : s Solo necesito capturar dos cuadros a la vez y luego necesito procesarlos.
Gracias por adelantado
EDITAR: encontré desde google que llamar a cvQueryFrame () devuelve dos veces el mismo puntero. ahora estoy un poco confundido. Si uso call solo una vez en un ciclo while, los cuadros progresan pero no si lo llamo dos veces? ¿Hay alguna manera fácil de obtener dos marcos?
Okay !
Tienes que hacer una copia de tu marco. frame1 = cvQueryFrame (captura); es un puntero como dijiste.
El código que encontré es:
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 );
Puede reemplazar el tiempo con un waitkey o cualquier cosa, pero si lo hace, use
img2 = cvQueryFrame( cap );
en lugar de
img2 = cvRetrieveFrame( cap );
porque no tendrás la
cvGrabFrame( cap )
nunca más
No sé si estoy claro, así que ... me quedo aquí ^^
Disfrutar;)
Laurent
ok siguiendo la respuesta de Laurent: creo que la clave es cvCloneImage (). cvCloneImage crea una nueva copia de la imagen original que incluye el encabezado, ROI, imageData, etc. y luego apunta a frame2 a esta nueva información.
Como cvQueryFrame es un contenedor para cvGrabFrame y cvRetrieveFrame, no quería dividir las funciones, por lo que con una pequeña modificación aún puedo usar cvQueryFrame.
A continuación está mi solución modificada.
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
}
IplImage *frame = cvQueryFrame(capture); //to read properties of frame.
IplImage *frame2 = NULL;
Espero que entiendas lo que he hecho aquí. Siéntase libre de hacer más preguntas.
cvQueryFrame()
devuelve el puntero al búfer interno "privado" de OpenCV que siempre llena con el último marco capturado.
Si quiere 2 cuadros necesitará guardar una copia en caché. Una vez que asigna (por ejemplo, usando el cvCloneImage()
) para su cuadro anterior, puede usar cvCopy()
para copiar solo los datos de la imagen. No use cvCloneImage()
dentro del bucle ya que es muy ineficiente debido a las asignaciones de memoria interna (y desasignaciones, de lo contrario también tendrá fugas de memoria).
Actualización: el código se verá más o menos así:
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 );
Nota: a menudo, puede evitar este tiempo de copia "redundante" haciendo una conversión.
Por ejemplo, supongamos que su pantalla está en color, pero su procesamiento está en escala de grises. Solo necesita las 2 copias consecutivas en escala de grises. Ya que necesitará convertir a escala de grises de todos modos, puede hacerlo directamente desde el fotograma capturado, evitando así la redundante cvCopy()
. Para guardar el cuadro anterior, simplemente intercambie los punteros entre las 2 imágenes asignadas en escala de grises.