gpt4 book ai didi

ios - 缩放图像 : how can the accelerate be the slowest method?

转载 作者:塔克拉玛干 更新时间:2023-11-01 21:20:30 24 4
gpt4 key购买 nike

我正在测试几种重新缩放 UIImage 的方法。

我已经测试了发布的所有这些方法 here并测量了他们调整图像大小所花费的时间。

1) UIGraphicsBeginImageContextWithOptions & UIImage -drawInRect:

let image = UIImage(contentsOfFile: self.URL.path!)

let size = CGSizeApplyAffineTransform(image.size, CGAffineTransformMakeScale(0.5, 0.5))
let hasAlpha = false
let scale: CGFloat = 0.0 // Automatically use scale factor of main screen

UIGraphicsBeginImageContextWithOptions(size, !hasAlpha, scale)
image.drawInRect(CGRect(origin: CGPointZero, size: size))

let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

2) CGBitmapContextCreate & CGContextDrawImage

let cgImage = UIImage(contentsOfFile: self.URL.path!).CGImage

let width = CGImageGetWidth(cgImage) / 2
let height = CGImageGetHeight(cgImage) / 2
let bitsPerComponent = CGImageGetBitsPerComponent(cgImage)
let bytesPerRow = CGImageGetBytesPerRow(cgImage)
let colorSpace = CGImageGetColorSpace(cgImage)
let bitmapInfo = CGImageGetBitmapInfo(cgImage)

let context = CGBitmapContextCreate(nil, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo.rawValue)

CGContextSetInterpolationQuality(context, kCGInterpolationHigh)

CGContextDrawImage(context, CGRect(origin: CGPointZero, size: CGSize(width: CGFloat(width), height: CGFloat(height))), cgImage)

let scaledImage = CGBitmapContextCreateImage(context).flatMap { UIImage(CGImage: $0) }

3) CGImageSourceCreateThumbnailAtIndex

import ImageIO

if let imageSource = CGImageSourceCreateWithURL(self.URL, nil) {
let options: [NSString: NSObject] = [
kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height) / 2.0,
kCGImageSourceCreateThumbnailFromImageAlways: true
]

let scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options).flatMap { UIImage(CGImage: $0) }
}

4) Lanczos 使用核心图像重采样

let image = CIImage(contentsOfURL: self.URL)

let filter = CIFilter(name: "CILanczosScaleTransform")!
filter.setValue(image, forKey: "inputImage")
filter.setValue(0.5, forKey: "inputScale")
filter.setValue(1.0, forKey: "inputAspectRatio")
let outputImage = filter.valueForKey("outputImage") as! CIImage

let context = CIContext(options: [kCIContextUseSoftwareRenderer: false])
let scaledImage = UIImage(CGImage: self.context.createCGImage(outputImage, fromRect: outputImage.extent()))

5) 加速中的 vImage

let cgImage = UIImage(contentsOfFile: self.URL.path!).CGImage

// create a source buffer
var format = vImage_CGImageFormat(bitsPerComponent: 8, bitsPerPixel: 32, colorSpace: nil,
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.First.rawValue),
version: 0, decode: nil, renderingIntent: CGColorRenderingIntent.RenderingIntentDefault)
var sourceBuffer = vImage_Buffer()
defer {
sourceBuffer.data.dealloc(Int(sourceBuffer.height) * Int(sourceBuffer.height) * 4)
}

var error = vImageBuffer_InitWithCGImage(&sourceBuffer, &format, nil, cgImage, numericCast(kvImageNoFlags))
guard error == kvImageNoError else { return nil }

// create a destination buffer
let scale = UIScreen.mainScreen().scale
let destWidth = Int(image.size.width * 0.5 * scale)
let destHeight = Int(image.size.height * 0.5 * scale)
let bytesPerPixel = CGImageGetBitsPerPixel(image.CGImage) / 8
let destBytesPerRow = destWidth * bytesPerPixel
let destData = UnsafeMutablePointer<UInt8>.alloc(destHeight * destBytesPerRow)
defer {
destData.dealloc(destHeight * destBytesPerRow)
}
var destBuffer = vImage_Buffer(data: destData, height: vImagePixelCount(destHeight), width: vImagePixelCount(destWidth), rowBytes: destBytesPerRow)

// scale the image
error = vImageScale_ARGB8888(&sourceBuffer, &destBuffer, nil, numericCast(kvImageHighQualityResampling))
guard error == kvImageNoError else { return nil }

// create a CGImage from vImage_Buffer
let destCGImage = vImageCreateCGImageFromBuffer(&destBuffer, &format, nil, nil, numericCast(kvImageNoFlags), &error)?.takeRetainedValue()
guard error == kvImageNoError else { return nil }

// create a UIImage
let scaledImage = destCGImage.flatMap { UIImage(CGImage: $0, scale: 0.0, orientation: image.imageOrientation) }

在测试了几个小时并测量了每种方法将图像重新缩放到 100x100 所花费的时间后,我的结论与 NSHipster 完全不同。首先,vImage in accelerate 比第一种方法慢 200 倍,在我看来这是其他方法的可怜表弟。核心图像方法也很慢。但我很好奇方法 #1 如何粉碎方法 3、4 和 5,其中一些理论上在 GPU 上处理内容。

例如,方法 #3 需要 2 秒才能将 1024x1024 图像调整为 100x100。另一方面,#1 用了 0.01 秒!

我错过了什么吗?

一定是哪里出了问题,否则 Apple 不会花时间编写加速器和 CIImage 的东西。

注意:我测量的是从图像已经加载到一个变量到缩放版本保存到另一个变量的时间。我没有考虑从文件中读取所需的时间。

最佳答案

由于多种原因,加速可能是最慢的方法:

  1. 您显示的代码可能会花费大量时间来提取数据来自 CGImage 并制作新图像。例如,你没有使用任何允许 CGImage 使用您的 vImage 结果的功能直接而不是复制。可能还需要颜色空间转换作为其中一些提取/创建 CGImage 操作的一部分。从这里很难说。
  2. 其他一些方法可能没有做任何事情,推迟了工作到后来绝对被迫去做。如果那是在您的结束时间之后,则不会对工作进行衡量。
  3. 其他一些方法的优点是能够直接使用图像的内容而无需复制首先。
  4. 不同的重采样方法(例如双线性与 Lanczos)具有不同的成本
  5. GPU 在某些方面实际上可以更快,重采样就是其中之一它专门针对执行的任务进行了优化。另一方面,随机数据访问(例如发生在重采样中)对向量单元来说不是一件好事。
  6. 计时方法会影响结果。加速是多线程的。如果你使用挂钟时间,你会得到一个答案。如果你使用getrusage 或采样器,你会得到另一个。

如果您真的认为 Accelerate 在这里离题太远,请提交错误。不过,在执行此操作之前,我当然会使用 Instruments Time Profile 检查您是否将大部分时间花在了基准循环中的 vImageScale 中。

关于ios - 缩放图像 : how can the accelerate be the slowest method?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38036759/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com