OpenCV: processa ogni frame

Voglio scrivere un’applicazione multipiattaforma usando OpenCV per l’acquisizione video. In tutti gli esempi, ho trovato che i fotogrammi della telecamera sono stati elaborati usando la funzione Grab e aspettando un po ‘. E voglio elaborare ogni fotogramma in una sequenza. Voglio definire la mia funzione di callback, che verrà eseguita ogni volta, quando un nuovo frame è pronto per essere elaborato (come in directshow per Windows, quando si definisce e si inserisce nel grafico il proprio filtro per tali scopi).

Quindi la domanda è: come posso fare questo?

Secondo il codice qui sotto, tutti i callback dovrebbero seguire questa definizione:

IplImage* custom_callback(IplImage* frame); 

Questa firma significa che il callback verrà eseguito su ogni frame recuperato dal sistema. Nel mio esempio, make_it_gray () assegna una nuova immagine per salvare il risultato della conversione in scala di grigi e la restituisce. Ciò significa che è necessario liberare questo frame più avanti nel codice. Ho aggiunto commenti sul codice al riguardo.

Si noti che se la richiamata richiede molta elaborazione, il sistema potrebbe saltare alcuni fotogrammi dalla fotocamera. Considera i suggerimenti di Paul R e di diverscuba23 .

 #include  #include "cv.h" #include "highgui.h" typedef IplImage* (*callback_prototype)(IplImage*); /* * make_it_gray: our custom callback to convert a colored frame to its grayscale version. * Remember that you must deallocate the returned IplImage* yourself after calling this function. */ IplImage* make_it_gray(IplImage* frame) { // Allocate space for a new image IplImage* gray_frame = 0; gray_frame = cvCreateImage(cvSize(frame->width, frame->height), frame->depth, 1); if (!gray_frame) { fprintf(stderr, "!!! cvCreateImage failed!\n" ); return NULL; } cvCvtColor(frame, gray_frame, CV_RGB2GRAY); return gray_frame; } /* * process_video: retrieves frames from camera and executes a callback to do individual frame processing. * Keep in mind that if your callback takes too much time to execute, you might loose a few frames from * the camera. */ void process_video(callback_prototype custom_cb) { // Initialize camera CvCapture *capture = 0; capture = cvCaptureFromCAM(-1); if (!capture) { fprintf(stderr, "!!! Cannot open initialize webcam!\n" ); return; } // Create a window for the video cvNamedWindow("result", CV_WINDOW_AUTOSIZE); IplImage* frame = 0; char key = 0; while (key != 27) // ESC { frame = cvQueryFrame(capture); if(!frame) { fprintf( stderr, "!!! cvQueryFrame failed!\n" ); break; } // Execute callback on each frame IplImage* processed_frame = (*custom_cb)(frame); // Display processed frame cvShowImage("result", processed_frame); // Release resources cvReleaseImage(&processed_frame); // Exit when user press ESC key = cvWaitKey(10); } // Free memory cvDestroyWindow("result"); cvReleaseCapture(&capture); } int main( int argc, char **argv ) { process_video(make_it_gray); return 0; } 

MODIFICARE:

Ho modificato il codice sopra in modo da stampare il framerate corrente ed eseguire una conversione manuale in scala di grigi . Sono piccole modifiche al codice e l’ho fatto a scopo didattico, quindi si sa come eseguire operazioni a livello di pixel.

 #include  #include  #include "cv.h" #include "highgui.h" typedef IplImage* (*callback_prototype)(IplImage*); /* * make_it_gray: our custom callback to convert a colored frame to its grayscale version. * Remember that you must deallocate the returned IplImage* yourself after calling this function. */ IplImage* make_it_gray(IplImage* frame) { // New IplImage* to store the processed image IplImage* gray_frame = 0; // Manual grayscale conversion: ugly, but shows how to access each channel of the pixels individually gray_frame = cvCreateImage(cvSize(frame->width, frame->height), frame->depth, frame->nChannels); if (!gray_frame) { fprintf(stderr, "!!! cvCreateImage failed!\n" ); return NULL; } for (int i = 0; i < frame->width * frame->height * frame->nChannels; i += frame->nChannels) { gray_frame->imageData[i] = (frame->imageData[i] + frame->imageData[i+1] + frame->imageData[i+2])/3; //B gray_frame->imageData[i+1] = (frame->imageData[i] + frame->imageData[i+1] + frame->imageData[i+2])/3; //G gray_frame->imageData[i+2] = (frame->imageData[i] + frame->imageData[i+1] + frame->imageData[i+2])/3; //R } return gray_frame; } /* * process_video: retrieves frames from camera and executes a callback to do individual frame processing. * Keep in mind that if your callback takes too much time to execute, you might loose a few frames from * the camera. */ void process_video(callback_prototype custom_cb) { // Initialize camera CvCapture *capture = 0; capture = cvCaptureFromCAM(-1); if (!capture) { fprintf(stderr, "!!! Cannot open initialize webcam!\n" ); return; } // Create a window for the video cvNamedWindow("result", CV_WINDOW_AUTOSIZE); double elapsed = 0; int last_time = 0; int num_frames = 0; IplImage* frame = 0; char key = 0; while (key != 27) // ESC { frame = cvQueryFrame(capture); if(!frame) { fprintf( stderr, "!!! cvQueryFrame failed!\n" ); break; } // Calculating framerate num_frames++; elapsed = clock() - last_time; int fps = 0; if (elapsed > 1) { fps = floor(num_frames / (float)(1 + (float)elapsed / (float)CLOCKS_PER_SEC)); num_frames = 0; last_time = clock() + 1 * CLOCKS_PER_SEC; printf("FPS: %d\n", fps); } // Execute callback on each frame IplImage* processed_frame = (*custom_cb)(frame); // Display processed frame cvShowImage("result", processed_frame); // Release resources cvReleaseImage(&processed_frame); // Exit when user press ESC key = cvWaitKey(10); } // Free memory cvDestroyWindow("result"); cvReleaseCapture(&capture); } int main( int argc, char **argv ) { process_video(make_it_gray); return 0; } 

I pensieri rapidi consistono nell’avere 2 thread, il primo thread è responsabile dell’acquisizione dei frame e della notifica del secondo thread quando sono disponibili (li inserisce in una coda di elaborazione), il secondo thread esegue l’elaborazione in un tipo di ciclo di eventi.

Vedere boost :: thread e boost :: signals2 poiché questi due insieme dovrebbero fornire la maggior parte del framework (eccetto la coda) per ciò che ho descritto sopra.