2010-11-23 10 views
8

Estoy tratando de hacer un poco de procesamiento de imágenes en el iPhone. Estoy usando http://developer.apple.com/library/ios/#qa/qa2010/qa1702.html para capturar los marcos de la cámara.FPS bajo al acceder al buffer de imagen de salida de video del iPhone

Mi problema es que cuando intento acceder al búfer capturado, el FPS de la cámara cae de 30 a aproximadamente 20. ¿Alguien sabe cómo puedo solucionarlo?

Uso la calidad de captura más baja que pude encontrar (AVCaptureSessionPresetLow = 192x144) en formato kCVPixelFormatType_32BGRA. Si alguien conoce una calidad inferior que podría usar, estoy dispuesto a intentarlo.

Cuando hago el mismo acceso a la imagen en otras plataformas, como Symbian, funciona bien.

Aquí está mi código:

#pragma mark - 
#pragma mark AVCaptureSession delegate 
- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
    fromConnection:(AVCaptureConnection *)connection 
{ 
/*We create an autorelease pool because as we are not in the main_queue our code is 
    not executed in the main thread. So we have to create an autorelease pool for the thread we are in*/ 
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
//Lock the image buffer 
    if (CVPixelBufferLockBaseAddress(imageBuffer, 0) == kCVReturnSuccess) 
    { 

    // calculate FPS and display it using main thread 
    [self performSelectorOnMainThread:@selector(updateFps:) withObject: (id) nil waitUntilDone:NO]; 


    UInt8 *base = (UInt8 *)CVPixelBufferGetBaseAddress(imageBuffer); //image buffer start address 

    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 

    int size = (height*width); 
    UInt8* pRGBtmp = m_pRGBimage; 

     /* 
     Here is the problem; m_pRGBimage is RGB image I want to process. 
     In the 'for' loop I convert the image from BGRA to RGB. As a resault, the FPS drops to 20. 
     */ 
    for (int i=0;i<size;i++) 
    { 
    pRGBtmp[0] = base[2]; 
    pRGBtmp[1] = base[1]; 
    pRGBtmp[2] = base[0]; 
    base = base+4; 
    pRGBtmp = pRGBtmp+3;  
    } 


    // Display received action 
    [self performSelectorOnMainThread:@selector(displayAction:) withObject: (id) nil waitUntilDone:NO]; 
    //[self displayAction:&eyePlayOutput]; 
    //saveFrame(imageBuffer); 

    //unlock the image buffer 
    CVPixelBufferUnlockBaseAddress(imageBuffer,0); 

} 


[pool drain]; 
} 

Como complemento a las respuestas, necesito para procesar la imagen en tiempo real, que se está visualizando.

he notado que cuando uso AVCaptureSessionPresetHigh, la cosa más sencilla que hago, como:

for (int i=0;i<size;i++) 
    x = base[0]; 

hace que la velocidad de fotogramas para caer a 4-5 FPS. Supongo que es porque una imagen de ese tamaño no está en la memoria caché.

Básicamente necesito una imagen de 96x48. ¿Hay alguna manera simple de reducir la escala de la imagen de salida de la cámara, una forma que utiliza la aceleración del hardware, para poder trabajar con la pequeña?

Respuesta

8

Cualquier cosa que itera sobre cada píxel de una imagen será bastante lento en todos menos en los dispositivos IOS más rápidos. Por ejemplo, comparé la iteración sobre cada píxel en un cuadro de video de 640 x 480 (307.200 píxeles) con una prueba de color simple por píxel y descubrí que solo funciona a 4 FPS en un iPhone 4.

Estás mirando el procesamiento de 27.648 píxeles en su caso, que debe correr lo suficientemente rápido como para alcanzar 30 FPS en un iPhone 4, pero que es un procesador mucho más rápido que el que estaba en el iPhone y el iPhone 3G original. El iPhone 3G probablemente aún tendrá problemas con esta carga de procesamiento. Tampoco dice qué tan rápido estuvo el procesador en sus dispositivos Symbian.

Le sugiero que vuelva a trabajar su algoritmo de procesamiento para evitar la conversión del espacio de color. No debería haber ninguna necesidad de reordenar los componentes de color para procesarlos.

Además, puede procesar selectivamente solo unos pocos píxeles al muestrear a ciertos intervalos dentro de las filas y columnas de la imagen.

Finalmente, si se dirige a los dispositivos iOS más nuevos compatibles con OpenGL ES 2.0 (iPhone 3G S y más reciente), puede utilizar un sombreador de fragmentos GLSL para procesar el cuadro de video completamente en la GPU. Describo el proceso here, junto con el código de muestra para el seguimiento de objetos en color en tiempo real. La GPU puede manejar este tipo de procesamiento de 14 a 28 veces más rápido que la CPU, en mis puntos de referencia.

1

exención de responsabilidad: La respuesta es una suposición :)

Estás haciendo un buen montón de trabajo, mientras que el buffer está bloqueado; ¿Esto está sosteniendo el hilo que está capturando la imagen de la cámara?

Usted puede copiar los datos de la memoria intermedia mientras trabaja en él para que pueda desbloquear lo antes posible algo es decir, como

if (CVPixelBufferLockBaseAddress(imageBuffer, 0) == kCVReturnSuccess) { 
    // Get the base address and size of the buffer 
    UInt8 *buffer_base = (UInt8 *)CVPixelBufferGetBaseAddress(imageBuffer); //image buffer start address 
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 

    // Copy it's contents out 
    Uint8 *base = malloc(width * height * 4); 
    memcpy(base, buffer_base, size); 

    // Unlock the buffer 
    CVPixelBufferUnlockBaseAddress(imageBuffer,0); 

    // base now points to a copy of the buffers' data - do what you want to it . . . 
    ... 

    // remember to free base once you're done ;) 
    free(base); 

Si se trata de la cerradura que está retrasando la captura, esto debería ayudar.

NB Puede acelerar esto si sabe que todos los buffers serán del mismo tamaño, puede llamar malloc una vez para obtener la memoria y luego solo volver a usarla cada vez y solo liberarla cuando haya terminado de procesar todos los buffers .


O si ese no es el problema que podría intentar bajar la prioridad de este hilo

[NSThread setThreadPriority:0.25]; 
+0

Estoy de acuerdo en que lo más probable es que el procesamiento lento arrastra toda la captura hacia abajo, pero no estoy seguro de que simplemente liberando el bloqueo pronto haga mucho para ayudar. Para tratar con fotogramas a 30 FPS, la devolución de llamada para cada fotograma deberá completarse en menos de 1/30 de segundo. Si no lo hace, las operaciones de procesamiento simplemente atascarán el hilo en el que se están ejecutando. –

+0

No si funcionó como un patrón de productor-> consumidor, las devoluciones de llamada simplemente se pondrían en cola, todo depende de lo que esté haciendo con la imagen modificada. Si solo lo está guardando, oiga, déjelo en una memoria intermedia en algún lugar. Si se muestra, entonces tiene un problema :) – deanWombourne

+0

He probado el memcpy en un búfer dedicado, pero no sirvió de nada, de hecho fue más lento :( – akaru

0

Copie el contenido del marco de la cámara en un búfer dedicado y opere desde allí. Esto resulta en una mejora de velocidad masiva en mi experiencia. Mi mejor opción es que la región de memoria donde se encuentra el marco de la cámara tiene protecciones especiales que hacen que los accesos de lectura/escritura sean lentos.

Verifique la dirección de memoria de los datos del marco de la cámara. En mi dispositivo, el buffer de la cámara está en 0x63ac000. Eso no significa nada para mí, excepto que los otros objetos del montón están en direcciones más cercanas al 0x1300000. La sugerencia de bloqueo no resolvió mi desaceleración, pero sí lo hizo memcpy.

+0

No he visto esta mejora de aceleración. caso, la memcpy ralentizó un poco las cosas, debido a la sobrecarga de la copia en sí. ¿Alguna sugerencia? – akaru

Cuestiones relacionadas