如何解决Swift:使用 CIColorCube 将 LUT查找表应用于图像缓慢性能
我正在使用 CIColorCube 将 LUT(来自 .png - Example LUT Image)应用于图像。它运作良好。我面临的唯一问题是当我创建按钮缩略图时,应用会停止几秒钟。
按钮看起来像这样 -> Buttons Example Image
这是我的代码:
@IBOutlet weak var filteRSScrollView: UIScrollView!
var filters = ["-","Filter1","Filter2","Filter3","Filter4"]
override func viewDidLoad() {
createFilters()
}
func createFilters() {
var x: CGFloat = 10
let y: CGFloat = 0
let width: CGFloat = 60
let height: CGFloat = 83
let gap: CGFloat = 2
for i in 0..<filters.count {
let filterButton = UIButton(type: .custom)
filterButton.frame = CGRect(x: x,y: y,width: width,height: height)
filterButton.imageView?.contentMode = .scaleAspectFill
filterButton.setTitleColor(#colorLiteral(red: 1,green: 1,blue: 1,alpha: 0),for: .normal)
let text = UILabel()
text.frame = CGRect(x: 0,y: height - 21,width: filterButton.frame.width,height: 21)
text.textAlignment = .center
text.backgroundColor = #colorLiteral(red: 0.9372549057,green: 0.3490196168,blue: 0.1921568662,alpha: 1)
text.textColor = .white
text.font = .systemFont(ofSize: 8.5,weight: .medium)
filterButton.addSubview(text)
filteRSScrollView.insertSubview(filterButton,at: 1)
x += width + gap
if i == 0 {
filterButton.setimage(originalImage,for: .normal)
text.text = "-"
text.backgroundColor = #colorLiteral(red: 0.1215686275,green: 0.1215686275,blue: 0.1215686275,alpha: 1)
}
else {
// THIS LINE MAKES THE APP STOP FOR A FEW SECONDS
let filteredImage = filterFromLUT(inputimage: originalCIImage,lut: "\(filters[i])")?.outputimage
filterButton.setimage(UIImage(ciImage: filteredImage!),for: .normal)
text.text = "\(filters[i])"
}
}
filteRSScrollView.contentSize = CGSize(width: x,height: height)
}
func filterFromLUT(inputimage: CIImage,lut: String) -> CIFilter? {
let dimension = 64
let lutimage = UIImage(named: lut)!.cgImage
let width = lutimage!.width
let height = lutimage!.height
let rowNum = width / dimension
let columnNum = height / dimension
let bitmap = createBitmap(image: lutimage!)
let dataSize = dimension * dimension * dimension * MemoryLayout<Float>.size * 4
var array = Array<Float>(repeating: 0,count: dataSize)
var bitmapOffest: Int = 0
var z: Int = 0
for _ in stride(from: 0,to: rowNum,by: 1) {
for y in stride(from: 0,to: dimension,by: 1) {
let tmp = z
for _ in stride(from: 0,to: columnNum,by: 1) {
for x in stride(from: 0,by: 1) {
let dataOffset = (z * dimension * dimension + y * dimension + x) * 4
let position = bitmap!
.advanced(by: bitmapOffest)
array[dataOffset + 0] = Float(position
.advanced(by: 0)
.pointee) / 255
array[dataOffset + 1] = Float(position
.advanced(by: 1)
.pointee) / 255
array[dataOffset + 2] = Float(position
.advanced(by: 2)
.pointee) / 255
array[dataOffset + 3] = Float(position
.advanced(by: 3)
.pointee) / 255
bitmapOffest += 4
}
z += 1
}
z = tmp
}
z += columnNum
}
free(bitmap)
let data = Data.init(bytes: array,count: dataSize)
// Create CIColorCube filter
let filter = CIFilter.colorCube()
filter.inputimage = inputimage
filter.cubedata = data
filter.cubedimension = Float(dimension)
return filter
}
func createBitmap(image: CGImage) -> UnsafeMutablePointer<UInt8>? {
let width = image.width
let height = image.height
let bitsPerComponent = 8
let bytesPerRow = width * 4
let bitmapSize = bytesPerRow * height
guard let data = malloc(bitmapSize) else {
return nil
}
let context = CGContext(
data: data,height: height,bitsPerComponent: bitsPerComponent,bytesPerRow: bytesPerRow,space: CGColorSpaceCreateDeviceRGB(),bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue,releaseCallback: nil,releaseInfo: nil)
context!.draw(image,in: CGRect(x: 0,y: 0,height: height))
return data.bindMemory(to: UInt8.self,capacity: bitmapSize)
}
我认为可能是 createBitmap() 函数中的 CGContext 导致了这种情况。有大佬知道怎么解决吗?
解决方法
您可以采取一些措施来提高性能:
- 目前,您正在处理原始输入图像(我认为它非常大)只是为了在 60 x 83 按钮中显示结果。在将图像放入过滤器之前,请考虑先缩小图像。
- 您可以通过使图像处理代码异步来避免阻塞 UI。只需创建适当大小的按钮并
DispatchQueue.global().async { ... }
进行图像处理。 - 不要使用
.setImage(UIImage(ciImage: filteredImage)
。根据我的经验,以这种方式从UIImage
创建CIImage
非常不可预测。而是使用CIContext
将过滤后的图像呈现为CGImage
,然后将其转换为UIImage
。还要尝试重复使用单个CIContext
,而不是为每个图像重新创建它。 - 可以使用 vDSP 加速将 LUT 图像转换为浮点数据数组的代码(见下文)。
使用 vDSP 创建 LUT 数据:
let lutImage = UIImage(named: lut)!.cgImage
let dimension = lutImage.height
// get data from image
let lutImageData = lutImage.dataProvider?.data
let lutImageDataPtr = CFDataGetBytePtr(lutImageData)!
// convert to float and divide by 255
let numElements = dimension * dimension * dimension * 4
let inDataFloat = UnsafeMutablePointer<Float>.allocate(capacity: numElements)
vDSP_vfltu8(lutImageDataPtr,1,inDataFloat,vDSP_Length(numElements))
var div: Float = 255.0
vDSP_vsdiv(inDataFloat,&div,vDSP_Length(numElements))
// convert buffer pointer to data
let lutData = NSData(bytesNoCopy: inDataFloat,length: numElements * MemoryLayout<Float>.size,freeWhenDone: true)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。