web-dev-qa-db-ja.com

CVImageBufferRefをUIImageに変換する方法

カメラからビデオをキャプチャしようとしています。トリガーするcaptureOutput:didOutputSampleBuffer:コールバックを取得しました。これにより、サンプルバッファが提供され、それをCVImageBufferRefに変換します。次に、その画像をUIImageに変換して、アプリで表示できるようにします。

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    /*Lock the image buffer*/
    CVPixelBufferLockBaseAddress(imageBuffer,0); 
    /*Get information about the image*/
    uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer); 
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 

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

    /*Create a CGImageRef from the CVImageBufferRef*/
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 
    CGImageRef newImage = CGBitmapContextCreateImage(newContext); 

    /*We release some components*/
    CGContextRelease(newContext); 
     CGColorSpaceRelease(colorSpace);

     /*We display the result on the custom layer*/
    /*self.customLayer.contents = (id) newImage;*/

    /*We display the result on the image view (We need to change the orientation of the image so that the video is displayed correctly)*/
    UIImage *image= [UIImage imageWithCGImage:newImage scale:1.0 orientation:UIImageOrientationRight];
    self.capturedView.image = image;

    /*We relase the CGImageRef*/
    CGImageRelease(newImage);
}

CGBitmapContextCreateを呼び出すまで、コードは正常に機能しているようです。常にNULLポインタを返します。その結果、残りの関数は機能しません。私がそれを渡したように見えても、関数はnullを返します。理由がわかりません。

23
iHorse

BaseAddressを渡す方法は、画像データが次の形式であることを前提としています。

ACCC

(ここで、Cは色成分、R || G || B)。

ネイティブ形式でビデオフレームをキャプチャするようにAVCaptureSessionを設定した場合、おそらく、平面YUV420形式でビデオデータを取得します。 (参照: リンクテキスト )ここで実行しようとしていることを実行するには、ビデオフレームをkCVPixelFormatType_32RGBAでキャプチャするように指定するのがおそらく最も簡単な方法です。 Appleビデオフレームを非平面形式でキャプチャする場合は、kCVPixelFormatType_32BGRAでキャプチャすることをお勧めします。理由は説明されていませんが、パフォーマンスの考慮事項によるものと合理的に推測できます。

警告:私はこれを行っていません。このようにCVPixelBufferRefのコンテンツにアクセスすることが、イメージを構築するための合理的な方法であると仮定しています。これが実際に機能することを保証することはできませんが、ビデオフレームを(おそらく)キャプチャしているピクセル形式のために、現在の方法が確実に機能しないことを/できます/と言います。

20
Chris Zelenak

単にCVImageBufferRefをUIImageに変換する必要がある場合は、本来よりもはるかに難しいようです。基本的に、CIImage、次にCGImage、次にUIImageに変換する必要があります。理由をお話しできればと思います。知るか。

-(void) screenshotOfVideoStream:(CVImageBufferRef)imageBuffer
{
    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:imageBuffer];
    CIContext *temporaryContext = [CIContext contextWithOptions:nil];
    CGImageRef videoImage = [temporaryContext
                             createCGImage:ciImage
                             fromRect:CGRectMake(0, 0,
                             CVPixelBufferGetWidth(imageBuffer),
                             CVPixelBufferGetHeight(imageBuffer))];

    UIImage *image = [[UIImage alloc] initWithCGImage:videoImage];
    [self doSomethingWithOurUIImage:image];
    CGImageRelease(videoImage);
}

この特定のメソッドは、VTDecompressionSessionコールバックを使用してH.264ビデオを変換してCVImageBufferRefを取得するときに機能しました(ただし、どのCVImageBufferRefでも機能するはずです)。 iOS 8.1、XCode6.2を使用していました。

14
Olivia Stork

あなたは直接電話することができます:

self.yourImageView.image=[[UIImage alloc] initWithCIImage:[CIImage imageWithCVPixelBuffer:imageBuffer]];
5

Benjamin Loulierは、複数のアプローチでの速度を考慮して、CVImageBufferRefの出力について非常に優れた投稿を書きました。

Githubで実際の例を見つけることもできます;)

昔はどうですか? ;)どうぞ: http://web.archive.org/web/20140426162537/http://www.benjaminloulier.com/posts/ios4-and-direct-access-to-the-camera

2
maaalex