2010-11-23 40 views
8

J'essaye de faire un peu de traitement d'image sur iPhone. J'utilise http://developer.apple.com/library/ios/#qa/qa2010/qa1702.html pour capturer les cadres de la caméra. Mon problème est que lorsque j'essaie d'accéder au tampon capturé, le FPS de la caméra tombe de 30 à environ 20. Est-ce que quelqu'un sait comment je peux le réparer?Faible FPS lors de l'accès au tampon d'image de sortie vidéo de l'iPhone

J'utilise la qualité de capture la plus faible que j'ai pu trouver (AVCaptureSessionPresetLow = 192x144) au format kCVPixelFormatType_32BGRA. Si quelqu'un connaît une qualité inférieure que je pourrais utiliser, je suis prêt à l'essayer.

Lorsque je fais le même accès à l'image sur d'autres plateformes, comme Symbian, cela fonctionne correctement.

Voici mon code:

#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]; 
} 

Comme suite à la réponse, je dois traiter l'image en temps réel, il est affiché.

je remarquai que lorsque j'utilise AVCaptureSessionPresetHigh, la chose la plus simple que je fais, comme:

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

provoque le framerate tomber à 4-5 FPS. Je suppose que c'est parce qu'une image de cette taille n'est pas mise en cache.

Fondamentalement, j'ai besoin d'image 96x48. Y at-il un moyen simple de réduire l'image de sortie de la caméra, un moyen qui utilise l'accélération matérielle, afin que je puisse travailler avec le petit?

Répondre

8

Tout ce qui itère sur chaque pixel d'une image sera assez lent sur tous, mais les plus rapides les appareils iOS. Par exemple, j'ai comparé l'itération sur chaque pixel dans un cadre vidéo de 640 x 480 (307 200 pixels) avec un simple test de couleur par pixel et constaté que cela ne tourne qu'à environ 4 FPS sur un iPhone 4.

en regardant traiter 27 648 pixels dans votre cas, ce qui devrait fonctionner assez vite pour atteindre 30 FPS sur un iPhone 4, mais c'est un processeur beaucoup plus rapide que ce qui était dans l'iPhone et l'iPhone 3G d'origine. L'iPhone 3G aura probablement encore du mal avec cette charge de traitement. Vous ne dites pas non plus à quelle vitesse le processeur était dans vos appareils Symbian.

Je suggérerais de retravailler votre algorithme de traitement pour éviter la conversion de l'espace de couleurs. Il ne devrait pas être nécessaire de réorganiser les composants de couleur pour les traiter. En outre, vous pouvez traiter sélectivement seulement quelques pixels en échantillonnant à certains intervalles dans les lignes et les colonnes de l'image. Enfin, si vous ciblez les nouveaux appareils iOS prenant en charge OpenGL ES 2.0 (iPhone 3G S et versions ultérieures), vous pouvez envisager d'utiliser un fragmenteur de fragment GLSL pour traiter entièrement la trame vidéo sur le GPU. Je décris le processus here, avec un exemple de code pour le suivi d'objet basé sur la couleur en temps réel. Le GPU peut gérer ce type de traitement de 14 à 28 fois plus vite que le CPU, dans mes benchmarks.

1

Avertissement: cette réponse est GUESS :)

Vous faites beaucoup de travail alors que le tampon est verrouillé; est-ce que cela tient le fil qui capture l'image de la caméra?

Vous pouvez copier les données de la mémoire tampon pendant que vous travaillez là-dessus et vous pouvez le déverrouiller dès que possible à savoir quelque chose comme

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 c'est le verrou qui est maintenant la capture alors cela devrait aider. NB Vous pouvez accélérer ceci si vous savez que tous les tampons seront de la même taille que vous pouvez simplement appeler malloc une fois pour obtenir la mémoire et ensuite la réutiliser à chaque fois et la libérer seulement quand vous avez fini de traiter tous les tampons .


Ou si ce n'est pas le problème que vous pourriez essayer de réduire la priorité de ce fil

[NSThread setThreadPriority:0.25]; 
+0

Je suis d'accord qu'il est très probable que le ralentissement du traitement entraîne le ralentissement de l'ensemble de la capture, mais je ne suis pas sûr que le simple fait de lâcher le verrou tôt fera beaucoup pour aider. Pour traiter les trames à 30 FPS, le rappel pour chaque trame devra se terminer en moins de 1/30ème de seconde. Si ce n'est pas le cas, les opérations de traitement vont simplement bloquer le fil sur lequel ils tournent. –

+0

Pas si cela fonctionnait en tant que producteur -> modèle de consommateur - les rappels seraient juste mis en file d'attente - tout dépend de ce qu'il fait avec l'image modifiée. Si c'est juste en train de le sauvegarder alors bon, laissez-le sauvegarder dans un tampon quelque part. Si c'est affiché alors il a un problème :) – deanWombourne

+0

J'ai essayé le memcpy sur un tampon dédié, mais cela n'a pas aidé du tout, en fait c'était plus lent :( – akaru

0

Copiez le contenu du cadre de la caméra dans un tampon dédié et actionnez-le à partir de là. Cela se traduit par une amélioration massive de la vitesse dans mon expérience. Ma meilleure estimation est que la zone de mémoire où se trouve le cadre de la caméra possède des protections spéciales qui ralentissent les accès en lecture/écriture.

Vérifiez l'adresse mémoire des données de la caméra. Sur mon appareil, le tampon de la caméra est au 0x63ac000. Cela ne signifie rien pour moi, sauf que les autres objets tas sont dans des adresses plus proches de 0x1300000. La suggestion de verrouillage n'a pas résolu mon ralentissement, mais le memcpy l'a fait.

+0

Je n'ai pas vu cette amélioration de l'accélération. Dans le cas contraire, le mémcpy a légèrement ralenti les choses, en raison des frais généraux de la copie elle-même. – akaru