1

一旦我无法从相机成功获得任何与 YCbCr 420 不同的东西(https://stackoverflow.com/questions/19673770/objective-c-avcapturevideodataoutput-videosettings-how-to-identify-which-pix

所以,我的目标是在使用 opencv 处理之后,在 CALayer 中将这个 CMSampleBufferRef(YCbCr 420)显示为彩色帧(CGImageRef,使用 RGB 颜色模型)。

4

1 回答 1

3

在相机捕获文件中,我放了这个:

#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改为kCGImageAlphaNoneSkipLastCGBitmapContextCreate. 另外,我在构造函数中使用了 4 个通道cv::Mat

我改编自kCVPixelFormatType_420YpCbCr8BiPlanarFullRange 帧到 UIImage 转换的部分代码

于 2013-11-29T06:36:06.913 回答