将 cvMat 转换为 UIImage 时出现内存问题

Memory problems while converting cvMat to UIImage

在这里发布这个问题之前,我已经阅读了所有材料和上面的类似帖子,但我无法了解主要的 "idea" 发生了什么以及如何解决它,在 10 个类似问题中,大家正在用 @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 分析器上根本没有泄漏,内存中最昂贵的任务是 convertMatToUIImage.

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

目前我在 swift 3.0 上工作,它继承了 class XXX,它使用 objC class 裁剪某些东西,而不是 return 到 UIImage以及。在 deinit 中,我将继承的 class 属性 分配为零,但问题仍然存在 exsists.Also 我认为 dataWithBytes 正在复制内存,就像我有 16MB 在创建 NSData 后开始时它将是 32MB..

如果您能就此问题提出有用的线索,我将很乐意阅读所有线索。感谢帮助

在解决这个问题三天多之后,我不得不重写函数并且它 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 读取数据。希望这一主题有一天能对某人有所帮助。