将cvMat转换为UIImage时的内存问题

时间:2016-11-20 19:37:23

标签: objective-c swift opencv automatic-ref-counting bridge

在这里发布这个问题之前,我已经阅读了所有材料和相似的帖子,但我无法得到主要的"想法"正在发生的事情以及如何解决这个问题,在类似的问题中,每个人都在用@autoreleasepool解决这个问题,在这种情况下,我无法实现我的目标。因此,在将cvMat转换为UIImage时,我会根据大小增加内存。

以下是我在将mat转换为uiimage之前所做的步骤:

cv::Mat undistorted = cv::Mat(cvSize(maxWidth,maxHeight), CV_8UC1);
cv::Mat original = [MatStructure convertUIImageToMat:adjustedImage];

cv::warpPerspective(original, undistorted, cv::getPerspectiveTransform(src, dst), cvSize(maxWidth, maxHeight));
original.release();

adjustedImage = [MatStructure convertMatToUIImage:undistorted];
undistorted.release();

问题是可见的,当我将我的垫子转换为uiimage时,内存上升到400 mb,并且在每个周期上升。

+ (UIImage *) convertMatToUIImage: (cv::Mat) cvMat {
    NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize() * cvMat.total()];

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

        CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef) data);
        CGBitmapInfo bmInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;

        CGImageRef imageRef = CGImageCreate(cvMat.cols,                              // width
                                            cvMat.rows,                              // height
                                            8,                                       // bits per component
                                            8 * cvMat.elemSize(),                    // bits per pixel
                                            cvMat.step.p[0],                         // bytesPerRow
                                            colorSpace,                              // colorspace
                                            bmInfo,                                  // bitmap info
                                            provider,                                // CGDataProviderRef
                                            NULL,                                    // decode
                                            false,                                   // should interpolate
                                            kCGRenderingIntentDefault                // intent
                                            );

        UIImage *image = [[UIImage alloc] initWithCGImage:imageRef];
        CGImageRelease(imageRef);
        CGDataProviderRelease(provider);
        CGColorSpaceRelease(colorSpace);
        cvMat.release(); // this line is optional.

        return image;
    }

我见过许多类似的代码,但每个例子都是这样的。 我相信问题在(__bridge CFDataRef)并且ARC无法清除此数据,如果我将尝试CFRelease((__bridge CFDataRef)data)而不会发生崩溃,因为程序将搜索已分配的内存并且它将被释放所以它会崩溃。

我正在使用openCV3并尝试了他们的方法MatToUIImage但问题仍然存在,在leaks探查器上根本没有泄漏,内存中最昂贵的任务是{{1 }}

我整天都在阅读它,但实际上还找不到任何有用的解决方案。

目前我正在使用convertMatToUIImage继承swift 3.0,并使用class XXX类来裁剪某些内容,而不是返回objC。在UIImage我正在分配这个继承的类属性nil,但问题仍然存在。我认为deinit正在重复内存,就像我在创建dataWithBytes后开始16MB一样它将是NSData ..

如果你能就这个问题提出有用的线索,我将很高兴看到它们。谢谢你的帮助

1 个答案:

答案 0 :(得分:0)

在处理这个问题超过三天后,我不得不重写功能,它100%工作,我已经在五个不同的设备上测试过。

CFReleaseFree()和@autoreleasepool根本没有帮助我,我实施了这个:

data = UIImageJPEGRepresentation([[UIImage alloc] initWithCGImage:imageRef], 0.2f); // because images are 30MB and up
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:@"MyFile.jpeg"];

[data writeToFile:appFile atomically:NO];

data = nil;

在此解决方案之后一切正常。所以我抓住UIImage并转换为NSData,之后我们应该将其保存到本地目录,剩下的就是从directory读取数据。希望这个帖子有一天会帮助别人。