下面的方法获取所选照片中特定点的像素颜色。当选择JPG时,下面的图像处理速度很快。当选择HEIC照片时,下面的图像处理速度很慢。可以慢大约40倍(7秒对5分钟)。
我想知道为什么会这样,我能做些什么来修复它?为了清楚起见,下面的代码工作,只是需要很长的时间来处理HEIC。
class func getPixelColorAtPoint(point:CGPoint, sourceView: UIView) -> UIColor{
let pixel = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: 4)
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
let context = CGContext(data: pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
var color: UIColor? = nil
if let context = context {
context.translateBy(x: -point.x, y: -point.y)
sourceView.layer.render(in: context)
color = UIColor(red: CGFloat(pixel[0])/255.0,
green: CGFloat(pixel[1])/255.0,
blue: CGFloat(pixel[2])/255.0,
alpha: CGFloat(pixel[3])/255.0)
pixel.deallocate(capacity: 4)
}
return color!
}发布于 2019-06-08 14:48:40
如果耗时5分钟,我假设您必须重复调用此例程,每次都呈现此sourceView。您应该将整个视图渲染到一个完整的像素缓冲区中一次,然后您就可以有效地从该缓冲区中检索多个像素的颜色。
例如:
var data: Data?
var width: Int!
var height: Int!
func pixelColor(at point: CGPoint, for sourceView: UIView) -> UIColor? {
if data == nil { fillBuffer(for: sourceView) }
return data?.withUnsafeBytes { rawBufferPointer in
let pixels = rawBufferPointer.bindMemory(to: Pixel.self)
let pixel = pixels[Int(point.y) * width + Int(point.x)]
return pixel.color
}
}
func fillBuffer(for sourceView: UIView) {
// get image snapshot
let bounds = sourceView.bounds
let format = UIGraphicsImageRendererFormat()
format.scale = 1
let image = UIGraphicsImageRenderer(bounds: bounds, format: format).image { _ in
sourceView.drawHierarchy(in: bounds, afterScreenUpdates: false)
}
guard let cgImage = image.cgImage else { return }
// prepare to get pixel buffer
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
width = Int(bounds.width)
height = Int(bounds.height)
// populate and save pixel buffer
if let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 4 * width, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) {
context.draw(cgImage, in: bounds)
data = context.data.flatMap { Data(bytes: $0, count: 4 * width * height) }
}
}显然,您可以随心所欲地将其渲染到缓冲区,但基本思想是将像素缓冲区保存到某个Data,您可以从中快速检索颜色值。
顺便说一句,我认为使用如下所示的struct来呈现稍微更直观的代码是有用的,而不是单独导航RGBA字节:
struct Pixel {
let red: UInt8
let green: UInt8
let blue: UInt8
let alpha: UInt8
}
extension Pixel {
var color: UIColor {
return UIColor(red: CGFloat(red) / 255,
green: CGFloat(green) / 255,
blue: CGFloat(blue) / 255,
alpha: CGFloat(alpha) / 255)
}
}更有趣的问题是,为什么要检索多个像素的颜色。您是否真的需要单个像素的颜色,或者您是否正在根据结果进行一些计算(例如直方图、平均颜色等)?也就是说,如果你真的只需要逐个像素地处理颜色,这是可以的,但如果你试图解决一个更广泛的问题,我们也许能够向你展示比逐个像素处理更有效的方法。其中包括并行化例程、vImage高性能图像处理等。但是,如果不知道如何处理这些重复调用来检索像素颜色,我们就不能说更多了。
https://stackoverflow.com/questions/56499993
复制相似问题