Objective-C
iOS
OpenCV

iOSのビデオカメラ機能とUIImageのメモリ解放

More than 5 years have passed since last update.

まだ十分に検証出来てないけどUIImageでメモリが解放出来なくて苦戦した。

※コードの元ネタはOpenCVのチュートリから

http://docs.opencv.org/doc/tutorials/ios/image_manipulation/image_manipulation.html

+ (UIImage *)imageFromCVMat:(cv::Mat&)cvMat

{
NSData *nsData = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize()*cvMat.total()];
CGColorSpaceRef colorSpace;

if (cvMat.elemSize() == 1) {
colorSpace = CGColorSpaceCreateDeviceGray();
} else {
colorSpace = CGColorSpaceCreateDeviceRGB();
}

CFDataRef cfData = (__bridge CFDataRef)nsData;
nsData = nil;

CGDataProviderRef provider = CGDataProviderCreateWithCFData(cfData);

// Creating CGImage from cv::Mat
CGImageRef imageRef = CGImageCreate(cvMat.cols, //width
cvMat.rows, //height
8, //bits per component
8 * cvMat.elemSize(), //bits per pixel
cvMat.step[0], //bytesPerRow
colorSpace, //colorspace
kCGImageAlphaNone|kCGBitmapByteOrderDefault,// bitmap info
provider, //CGDataProviderRef
NULL, //decode
false, //should interpolate
kCGRenderingIntentDefault //intent
);

// Getting UIImage from CGImage
UIImage *finalImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:UIImageOrientationRight];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
CFRelease(cfData);

return finalImage;
}

こうやって作ったUIImageが次のようなケースで解放されない。

// AVCaptureVideoDataOutputSampleBufferDelegateプロトコル

- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
// OpenCVでごにょごにょ
// 内部ではsampleBuffer->cv::Mat->UIImage変換を行っている
// processingImageはcv::Mat->UIImageしたUIImage
UIImage *processingImage = [self.imageProcessingFromBuffer:sampleBuffer];

// 画像を画面に表示
dispatch_async(dispatch_get_main_queue(), ^{
self.previewImageView.image = processingImage;
});
}

原因はよくわからなかったけど、下記の方法で解決した。

メモリの実体はcv::Matが持ってるのでdelegateメソッド内でcvMatを生成して、ブロックの中でdeleteすることでメモリリークが無くなった。

多分cv::Matのコピーが理解できてないんだと思う(:D)TL

// AVCaptureVideoDataOutputSampleBufferDelegateプロトコル

- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
// OpenCVでごにょごにょ
// 内部ではsampleBuffer->cv::Mat変換を行っている
// processingImageはcv::Mat形式
cv::Mat processingImage = new cv::Mat();
processingImage = [self imageProcessingFromBuffer:sampleBuffer];

// 画像を画面に表示
dispatch_async(dispatch_get_main_queue(), ^{
// 内部でcv::Mat -> UIImage変換
self.previewImageView.image = [self imageFromCVMat:processingImage];
     // 渡したらdeleteする
delete processingImage;
});
}

とりあえずこんなところで。