Низкий FPS при доступе к буферу изображения видеовыхода iPhone

Я пытаюсь выполнить некоторую обработку изображений на iPhone. Я использую http://developer.apple.com/library/ios/#qa/qa2010/qa1702.html для захвата кадров камеры.

Моя проблема в том, что когда я пытаюсь получить доступ к захваченному буферу, FPS камеры падает с 30 до примерно 20. Кто-нибудь знает, как я могу это исправить?

Я использую самое низкое качество захвата, которое смог найти (AVCaptureSessionPresetLow = 192x144) в формате kCVPixelFormatType_32BGRA. Если кто-нибудь знает более низкое качество, которое я мог бы использовать, я готов попробовать.

Когда я делаю такой же доступ к изображению на других платформах, таких как Symbian, все работает нормально.

Вот мой код:

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

В дополнение к ответам мне нужно обработать изображение в реальном времени, оно отображается.

Я заметил, что когда я использую AVCaptureSessionPresetHigh, самое простое, что я делаю, например:

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

Частота кадров падает до 4-5 кадров в секунду. Я думаю, это потому, что изображение такого размера не кэшируется.

В основном мне нужно изображение 96x48. есть ли простой способ уменьшить масштаб выходного изображения камеры, способ, использующий аппаратное ускорение, чтобы я мог работать с маленьким?


person Asaf Pinhassi    schedule 23.11.2010    source источник


Ответы (3)


Все, что перебирает каждый пиксель изображения, будет довольно медленным на всех устройствах iOS, кроме самых быстрых. Например, я проверил итерацию каждого пикселя в видеокадре 640 x 480 (307 200 пикселей) с помощью простого попиксельного теста цвета и обнаружил, что на iPhone 4 это работает со скоростью около 4 кадров в секунду.

В вашем случае вы смотрите на обработку 27 648 пикселей, которая должна работать достаточно быстро, чтобы достигать 30 кадров в секунду на iPhone 4, но это гораздо более быстрый процессор, чем тот, который был в оригинальном iPhone и iPhone 3G. iPhone 3G, вероятно, все еще будет бороться с такой вычислительной нагрузкой. Вы также не говорите, насколько быстрым был процессор в ваших устройствах Symbian.

Я бы предложил переработать ваш алгоритм обработки, чтобы избежать преобразования цветового пространства. Не должно быть необходимости переупорядочивать компоненты цвета для их обработки.

Кроме того, вы можете выборочно обрабатывать только несколько пикселей, производя выборку через определенные промежутки времени в строках и столбцах изображения.

Наконец, если вы ориентируетесь на более новые устройства iOS с поддержкой OpenGL ES 2.0 (iPhone 3G S и новее), вы можете рассмотреть возможность использования фрагментного шейдера GLSL для обработки видеокадра полностью на графическом процессоре. Я описываю процесс здесь , а также пример кода для отслеживания объектов на основе цвета в реальном времени. В моих тестах графический процессор может обрабатывать такую ​​​​обработку в 14–28 раз быстрее, чем центральный процессор.

person Brad Larson    schedule 23.11.2010

отказ от ответственности: ЭТОТ ОТВЕТ ЯВЛЯЕТСЯ УГАДАНИЕМ :)

Вы делаете довольно много работы, пока буфер заблокирован; это держит нить, которая захватывает изображение с камеры?

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

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);

Если блокировка мешает захвату, то это должно помочь.

NB Вы можете ускорить это, если знаете, что все буферы будут одинакового размера, вы можете просто вызвать malloc один раз, чтобы получить память, а затем просто повторно использовать ее каждый раз и освобождать ее только после того, как вы закончите обработку всех буферов.


Или, если это не проблема, вы можете попробовать понизить приоритет этого потока.

[NSThread setThreadPriority:0.25];
person deanWombourne    schedule 23.11.2010
comment
Я согласен с тем, что, скорее всего, медленная обработка замедляет весь захват, но я не уверен, что простое раннее снятие блокировки сильно поможет. Чтобы обрабатывать кадры со скоростью 30 кадров в секунду, обратный вызов для каждого кадра должен выполняться менее чем за 1/30 секунды. Если этого не произойдет, операции обработки просто затормозят поток, в котором они выполняются. - person Brad Larson; 23.11.2010
comment
Нет, если бы это работало как модель производитель-потребитель — обратные вызовы просто ставились бы в очередь — все зависит от того, что он делает с измененным изображением. Если он просто сохраняет его, то эй, дайте ему резервную копию где-нибудь в буфере. Если он отображается, значит, у него проблемы :) - person deanWombourne; 24.11.2010
comment
Я пробовал memcpy на выделенном буфере, но это вообще не помогло, на самом деле это было медленнее :( - person akaru; 21.02.2011

Скопируйте содержимое кадра камеры в специальный буфер и работайте с ним оттуда. Это приводит к значительному улучшению скорости в моем опыте. Я предполагаю, что область памяти, в которой находится кадр камеры, имеет специальную защиту, которая замедляет доступ к чтению/записи.

Проверьте адрес памяти данных кадра камеры. На моем устройстве буфер камеры равен 0x63ac000. Для меня это ничего не значит, за исключением того, что другие объекты кучи находятся по адресам ближе к 0x1300000. Предложение блокировки не решило мое замедление, но memcpy помогло.

person gonzojive    schedule 08.12.2010
comment
Я не видел этого улучшения ускорения. В моем случае memcpy немного замедлил работу из-за накладных расходов на само копирование. Какие-либо предложения? - person akaru; 21.02.2011