【问题标题】:Why does this Swift UIImage function overflow my memory?为什么这个 Swift UIImage 函数会溢出我的内存?
【发布时间】:2018-02-09 21:24:47
【问题描述】:

我正在使用 Swift 4 为 iPhone 构建一个应用程序。我有一些测试过滤器。两者都可以通过相机的输出正常工作,但是当我从更复杂的图像中创建一组图像时,我的内存溢出到灾难性的比例并使我的应用程序崩溃。

我在下面的循环中调用这个,这会溢出我的记忆:

func rotateHue2(with ciImage: CIImage,
               rotatedByHue deltaHueRadians: CGFloat,
               orientation:UIImageOrientation?,
               screenWidth:CGFloat,
               screenHeight:CGFloat) -> UIImage {


    let sourceCore = ciImage


    let transBG = UIImage(color: .clear, size: CGSize(width: screenWidth, height: screenHeight))

    let transBGCI = CIImage(cgImage: (transBG?.cgImage)!)



    // Part 1

    let gradientPoint0Pos: [CGFloat] = [0, 0]
    let inputPoint0Vector = CIVector(values: gradientPoint0Pos, count: gradientPoint0Pos.count)

    var gradientPoint1Pos: [CGFloat]
    if(orientation == nil){

        gradientPoint1Pos = [0, screenWidth*2]

    }else{

        gradientPoint1Pos = [screenHeight*2, 0]

    }

    let inputPoint1Vector = CIVector(values: gradientPoint1Pos, count: gradientPoint1Pos.count)


    let gradientFilter = CIFilter(name: "CISmoothLinearGradient")
    gradientFilter?.setDefaults()
    gradientFilter?.setValue(inputPoint0Vector, forKey: "inputPoint0")
    gradientFilter?.setValue(inputPoint1Vector, forKey: "inputPoint1")


    gradientFilter?.setValue(CIColor.clear, forKey:"inputColor0")
    gradientFilter?.setValue(CIColor.black, forKey:"inputColor1")


    let gradient = gradientFilter?.outputImage?
        .cropped(to: sourceCore.extent)



    let hue1 = sourceCore
        .applyingFilter("CIHueAdjust", parameters: [kCIInputImageKey: sourceCore,
                                                    kCIInputAngleKey: deltaHueRadians])
        .cropped(to: sourceCore.extent)


    let alphaMaskBlend1 = CIFilter(name: "CIBlendWithAlphaMask",
                                   withInputParameters: [kCIInputImageKey: hue1,
                                                         kCIInputBackgroundImageKey: transBGCI,
                                                         kCIInputMaskImageKey:gradient!])?.outputImage?
        .cropped(to: sourceCore.extent)


    // Part 2


    let hue2 = sourceCore
        .applyingFilter("CIHueAdjust", parameters: [kCIInputImageKey: sourceCore,
                                                    kCIInputAngleKey: deltaHueRadians+1.5707])
        .cropped(to: sourceCore.extent)


    let blendedMasks = hue2
        .applyingFilter(compositeOperationFilters[compositeOperationFiltersIndex], parameters: [kCIInputImageKey: alphaMaskBlend1!,
                                                                                                kCIInputBackgroundImageKey: hue2])
        .cropped(to: sourceCore.extent)




    // Convert the filter output back into a UIImage.
    let context = CIContext(options: nil)
    let resultRef = context.createCGImage(blendedMasks, from: blendedMasks.extent)

    var result:UIImage? = nil

    if(orientation != nil){

        result = UIImage(cgImage: resultRef!, scale: 1.0, orientation: orientation!)

    }else{

        result = UIImage(cgImage: resultRef!)

    }
    return result!
}

根据手机的方向,将每张图片的大小调整为 1280 或 720 宽。当我的其他图像过滤器正常工作时,为什么这会给我一个内存警告?

只是为了好玩,这是另一个不会让它崩溃的:

func rotateHue(with ciImage: CIImage,
                rotatedByHue deltaHueRadians: CGFloat,
                orientation:UIImageOrientation?,
                screenWidth:CGFloat,
                screenHeight:CGFloat) -> UIImage {


    // Create a Core Image version of the image.
    let sourceCore = ciImage
    // Apply a CIHueAdjust filter
    let hueAdjust = CIFilter(name: "CIHueAdjust")
    hueAdjust?.setDefaults()
    hueAdjust?.setValue(sourceCore, forKey: "inputImage")
    hueAdjust?.setValue(deltaHueRadians, forKey: "inputAngle")

    let resultCore = CIFilter(name: "CIHueAdjust",
                              withInputParameters: [kCIInputImageKey: sourceCore,
                                                    kCIInputAngleKey: deltaHueRadians])?.outputImage?
        .cropped(to: sourceCore.extent)


    // Convert the filter output back into a UIImage.
    let context = CIContext(options: nil)
    let resultRef = context.createCGImage(resultCore!, from: (resultCore?.extent)!)

    var result:UIImage? = nil

    if(orientation != nil){

        result = UIImage(cgImage: resultRef!, scale: 1.0, orientation: orientation!)

    }else{

        result = UIImage(cgImage: resultRef!)

    }
    return result!
}

【问题讨论】:

    标签: swift memory crash uiimage cifilter


    【解决方案1】:

    您应该做的第一件事是将您的CIContext 移出函数并使其尽可能全局化。创建它是内存的主要用途。

    问题不大,为什么每张图片要裁剪五次?这可能不是问题,但对我来说“感觉”是错误的。 CIImage 不是图像 - 它更接近“配方”。

    更紧密地链接事物 - 让下一个过滤器的输入成为前一个过滤器的输出。完成后裁剪。最重要的是,尽可能少地创建CIContexts

    【讨论】:

    • 这确实有帮助,但我仍然看到内存飙升至 1.5 GB!为什么?!
    • 可能是链接,但我不知道如何将它们紧紧链接。可能是因为我也在改造 transBGCI 并且不知何故在循环中建立起来?
    • 高层,你到底想做什么?另外,在技术层面上,rotateHue2(with:) 在做什么?我无法在不知道这一点的情况下使用“更严格”的代码进行编辑。例如,为什么这个函数会创建一个 UIImage,transBG,然后把它变成一个 CIImage,然后再做其他的事情?至少 - 在将上下文移出函数后,将其分解为组件函数并进行计时。根据您尝试执行的操作,您可能会发现可以将内容传递给使用链式 CIFilter 的函数。
    • 最后一点。通过紧密链接,我的意思是将每个kCIInputImageKey 直接设置为前一个过滤器的outputImageCIFilter.cropped(to:) 很可能是问题所在——第一个函数中有五个,第二个函数只有一个。另外,请尝试使CIFilter 呼叫更加全球化。如果您要重复使用四个“命名”过滤器,则可以在函数外部创建它们,以免每次调用函数时都实例化它们。 (你从来没有说过这个图像数组有多大。)
    • 好建议,我会在星期一尝试。图像阵列为 31 幅图像。他们相机的输出变成了两个具有不同颜色变化的图像,每次捕获相机的输出或当用户拍照并在 for 循环中更改时,这些图像都会发生变化。我正在将透明图像作为蒙版的背景,以便一个图像可以淡入 0 alpha,该图像以不同的颜色叠加在另一个图像之上,因此它看起来有渐变。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-19
    • 1970-01-01
    • 2012-04-20
    相关资源
    最近更新 更多