2013-11-29 3 views
1

После того, что я не могу успешно ничего другого из YCbCr 420 из камеры (https://stackoverflow.com/questions/19673770/objective-c-avcapturevideodataoutput-videosettings-how-to-identify-which-pix)Преобразование CVImageBufferRef YUV 420 в cv :: Mat RGB и отображение его в CALayer?

Итак, моя цель состоит в том, чтобы отобразить эту CMSampleBufferRef (YCbCr 420), после того, как процесс с OpenCV, в виде цветного кадра (CGImageRef , используя цветовую модель RGB) в CALayer.

ответ

2

В файле захвата камеры я ставлю это:

#define clamp(a) (a>255?255:(a<0?0:a)); 

cv::Mat* YUV2RGB(cv::Mat *src){ 
    cv::Mat *output = new cv::Mat(src->rows, src->cols, CV_8UC4); 
    for(int i=0;i<output->rows;i++) 
     for(int j=0;j<output->cols;j++){ 
      // from Wikipedia 
      int c = src->data[i*src->cols*src->channels() + j*src->channels() + 0] - 16; 
      int d = src->data[i*src->cols*src->channels() + j*src->channels() + 1] - 128; 
      int e = src->data[i*src->cols*src->channels() + j*src->channels() + 2] - 128; 

      output->data[i*src->cols*src->channels() + j*src->channels() + 0] = clamp((298*c+409*e+128)>>8); 
      output->data[i*src->cols*src->channels() + j*src->channels() + 1] = clamp((298*c-100*d-208*e+128)>>8); 
      output->data[i*src->cols*src->channels() + j*src->channels() + 2] = clamp((298*c+516*d+128)>>8); 
     } 

    return output; 
} 

    -(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{ 


      CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
      CVPixelBufferLockBaseAddress(imageBuffer, 0); 

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

      uint8_t *baseAddress = (uint8_t*)CVPixelBufferGetBaseAddress(imageBuffer); 
      CVPlanarPixelBufferInfo_YCbCrBiPlanar *bufferInfo = (CVPlanarPixelBufferInfo_YCbCrBiPlanar *)baseAddress; 

      NSUInteger yOffset = EndianU32_BtoN(bufferInfo->componentInfoY.offset); 
      NSUInteger yPitch = EndianU32_BtoN(bufferInfo->componentInfoY.rowBytes); 

      NSUInteger cbCrOffset = EndianU32_BtoN(bufferInfo->componentInfoCbCr.offset); 
      NSUInteger cbCrPitch = EndianU32_BtoN(bufferInfo->componentInfoCbCr.rowBytes); 

      uint8_t *yBuffer = baseAddress + yOffset; 
      uint8_t *cbCrBuffer = baseAddress + cbCrOffset; 

      cv::Mat *src = new cv::Mat((int)(height), (int)(width), CV_8UC4); 

      //YUV -> cv::Mat 

      for(int i = 0; i< height; i++) 
      { 
       uint8_t *yBufferLine = &yBuffer[i * yPitch]; 
       uint8_t *cbCrBufferLine = &cbCrBuffer[(i >> 1) * cbCrPitch]; 

       for(int j = 0; j < width; j++) 
       { 
        uint8_t y = yBufferLine[j]; 
        uint8_t cb = cbCrBufferLine[j & ~1]; 
        uint8_t cr = cbCrBufferLine[j | 1]; 

        src->data[i*width*src->channels() + j*src->channels() + 0] = y; 
        src->data[i*width*src->channels() + j*src->channels() + 1] = cb; 
        src->data[i*width*src->channels() + j*src->channels() + 2] = cr; 
       } 
      } 


      cv::Mat *output = YUV2RGB(src); 

      CGColorSpaceRef grayColorSpace = CGColorSpaceCreateDeviceRGB(); 
      CGContextRef context = CGBitmapContextCreate(output->data, output->cols, output->rows, 8, output->step, grayColorSpace, kCGImageAlphaNoneSkipLast); 
      CGImageRef dstImage = CGBitmapContextCreateImage(context); 

      dispatch_sync(dispatch_get_main_queue(), ^{ 
       customPreviewLayer.contents = (__bridge id)dstImage; 
      }); 

      CGImageRelease(dstImage); 
      CGContextRelease(context); 
      CGColorSpaceRelease(grayColorSpace); 


      output->release(); 
      src->release(); 

     } 

Я получил некоторые вопросы (я действительно застрял), пытаясь добраться до этой точки, я опишу здесь. Это может быть кто-то еще проблема, а также:

  1. Это clamp функция имеет важное значение для обеспечения правильного преобразования YUV-> RGB
  2. По какой-то причине я не мог просто держать 3 канала на изображении data, это как-то вызвало проблему, когда он собирался отобразить изображение. Поэтому я изменил kCGImageAlphaNone на kCGImageAlphaNoneSkipLast в CGBitmapContextCreate. Кроме того, я использовал 4 канала в конструкторе cv::Mat.

Часть этого кода я адаптировано из kCVPixelFormatType_420YpCbCr8BiPlanarFullRange frame to UIImage conversion

 Смежные вопросы

  • Нет связанных вопросов^_^