我有大約 50 個 3D LUT(存盤為 png 影像,每個大小為 900KB)并使用 CIColorCube 過濾器生成過濾后的影像。我使用 UICollectionView 為每個 LUT 顯示過濾的縮略圖(100x100)(就像在照片應用程式中一樣)。問題是當我在用戶滾動時生成過濾的影像時,UICollectionView 滾動變得非常慢(沒有接近照片應用程式的平滑度)。我想過預先生成過濾的影像,但問題是從 LUT png 生成 cubeData 大約需要 150 毫秒,所以對于 50 個縮略圖,準備過濾的縮略圖需要大約 7-8 秒,這很長。這也正是滾動性能的罪魁禍首。我想知道我能做些什么來使它像在照片應用程式或其他照片編輯應用程式中一樣流暢。這是我從 LUT png 生成立方體資料的代碼。
public static func colorCubeDataFromLUTPNGImage(_ image : UIImage, lutSize:Int) -> Data? {
let size = lutSize
let lutImage = image.cgImage!
let lutWidth = lutImage.width
let lutHeight = lutImage.height
let rowCount = lutHeight / size
let columnCount = lutWidth / size
if ((lutWidth % size != 0) || (lutHeight % size != 0) || (rowCount * columnCount != size)) {
NSLog("Invalid colorLUT")
return nil
}
let bitmap = getBytesFromImage(image: image)!
let floatSize = MemoryLayout<Float>.size
let cubeData = UnsafeMutablePointer<Float>.allocate(capacity: size * size * size * 4 * floatSize)
var z = 0
var bitmapOffset = 0
for _ in 0 ..< rowCount {
for y in 0 ..< size {
let tmp = z
for _ in 0 ..< columnCount {
for x in 0 ..< size {
let alpha = Float(bitmap[bitmapOffset]) / 255.0
let red = Float(bitmap[bitmapOffset 1]) / 255.0
let green = Float(bitmap[bitmapOffset 2]) / 255.0
let blue = Float(bitmap[bitmapOffset 3]) / 255.0
let dataOffset = (z * size * size y * size x) * 4
cubeData[dataOffset 3] = alpha
cubeData[dataOffset 2] = red
cubeData[dataOffset 1] = green
cubeData[dataOffset 0] = blue
bitmapOffset = 4
}
z = 1
}
z = tmp
}
z = columnCount
}
let colorCubeData = Data(bytesNoCopy: cubeData, count: size * size * size * 4 * floatSize, deallocator: Data.Deallocator.free)
return colorCubeData
}
fileprivate static func getBytesFromImage(image:UIImage?) -> [UInt8]?
{
var pixelValues: [UInt8]?
if let imageRef = image?.cgImage {
let width = Int(imageRef.width)
let height = Int(imageRef.height)
let bitsPerComponent = 8
let bytesPerRow = width * 4
let totalBytes = height * bytesPerRow
let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
let colorSpace = CGColorSpaceCreateDeviceRGB()
var intensities = [UInt8](repeating: 0, count: totalBytes)
let contextRef = CGContext(data: &intensities, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo)
contextRef?.draw(imageRef, in: CGRect(x: 0.0, y: 0.0, width: CGFloat(width), height: CGFloat(height)))
pixelValues = intensities
}
return pixelValues!
}
這是我的 UICollectionViewCell 設定代碼:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let lutPath = self.lutPaths[indexPath.item]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FilterCell", for: indexPath) as! FilterCell
if let lutImage = UIImage(contentsOfFile: lutPath) {
let renderer = CIFilter(name: "CIColorCube")!
let lutData = ColorCubeHelper.colorCubeDataFromLUTPNGImage(lutImage, lutSize: 64)
renderer.setValue(lutData!, forKey: "inputCubeData")
renderer.setValue(64, forKey: "inputCubeDimension")
renderer.setValue(inputCIImage, forKey: kCIInputImageKey)
let outputImage = renderer.outputImage!
let cgImage = self.ciContext.createCGImage(outputImage, from: outputImage.extent)!
cell.configure(image: UIImage(cgImage: cgImage))
} else {
NSLog("LUT not found at \(indexPath.item)")
}
return cell
}
uj5u.com熱心網友回復:
我們發現您可以將 LUT 影像直接渲染到基于浮點的背景關系中,以獲得所需的格式CIColorCube:
// render LUT into a 32-bit float context, since that's the data format needed by CIColorCube
let pixelData = UnsafeMutablePointer<simd_float4>.allocate(capacity: lutImage.width * lutImage.height)
let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.floatComponents.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
guard let bitmapContext = CGContext(data: pixelData,
width: lutImage.width,
height: lutImage.height,
bitsPerComponent: MemoryLayout<simd_float4.Scalar>.size * 8,
bytesPerRow: MemoryLayout<simd_float4>.size * lutImage.width,
space: lutImage.colorSpace ?? CGColorSpace.sRGBColorSpace,
bitmapInfo: bitmapInfo)
else {
assertionFailure("Failed to create bitmap context for conversion")
return nil
}
bitmapContext.draw(lutImage, in: CGRect(x: 0, y: 0, width: lutImage.width, height: lutImage.height))
let lutData = Data(bytesNoCopy: pixelData, count: bitmapContext.bytesPerRow * bitmapContext.height, deallocator: .free)
但是,如果我沒記錯的話,我們不得不交換 LUT 影像中的紅色和藍色分量,因為 Core Image 使用 BGRA 格式(正如您在代碼中所做的那樣)。
此外,在您的集合視圖委托中,如果您盡快回傳單元格并將縮略圖的生成發布到后臺執行緒,該執行緒將在完成后設定單元格的影像,則可能會提高性能。像這樣:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let lutPath = self.lutPaths[indexPath.item]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FilterCell", for: indexPath) as! FilterCell
DispatchQueue.global(qos: .background).async {
if let lutImage = UIImage(contentsOfFile: lutPath) {
let renderer = CIFilter(name: "CIColorCube")!
let lutData = ColorCubeHelper.colorCubeDataFromLUTPNGImage(lutImage, lutSize: 64)
renderer.setValue(lutData!, forKey: "inputCubeData")
renderer.setValue(64, forKey: "inputCubeDimension")
renderer.setValue(inputCIImage, forKey: kCIInputImageKey)
let outputImage = renderer.outputImage!
let cgImage = self.ciContext.createCGImage(outputImage, from: outputImage.extent)!
DispatchQueue.main.async {
cell.configure(image: UIImage(cgImage: cgImage))
}
} else {
NSLog("LUT not found at \(indexPath.item)")
}
}
return cell
}
uj5u.com熱心網友回復:
這是我認為一種更有效的方法,可以通過正確的組件順序從 LUT 影像中獲取位元組,同時一直保持在核心影像空間內,直到影像呈現到螢屏上。
guard let image = CIImage(contentsOf: url) else {
return
}
let totalPixels = Int(image.extent.width) * Int(image.extent.height)
let pixelData = UnsafeMutablePointer<simd_float4>.allocate(capacity: totalPixels)
// [.workingColorSpace: NSNull()] below is important.
// We don't want any color conversion when rendering pixels to buffer.
let context = CIContext(options: [.workingColorSpace: NSNull()])
context.render(image,
toBitmap: pixelData,
rowBytes: Int(image.extent.width) * MemoryLayout<simd_float4>.size,
bounds: image.extent,
format: .RGBAf, // Float32 per component in that order
colorSpace: nil)
let dimension = cbrt(Double(image.extent.size.volume))
let data = Data(bytesNoCopy: pixelData, count: totalPixels * MemoryLayout<simd_float4>.size, deallocator: .free)
Core Image 使用 BGRA 格式的假設是不正確的。Core Image 使用 RGBA 顏色格式(RGBA8、RGBAf、RGBAh 等)。CIColorCube 查找表按 BGR 順序布局,但顏色本身采用 RGBAf 格式,其中每個組件由 32 位浮點數表示。
當然,要使上面的代碼作業,LUT 影像必須以某種方式布置。這是身份 LUT PNG 的示例:身份 LUT
順便說一句,請查看此應用程式:https : //apps.apple.com/us/app/filter-magic/id1594986951。從新聞界新鮮出爐。它沒有從 LUT png(還)加載查找表的功能,但具有許多其他有用的功能,并提供了一個試驗場來試驗那里的每個過濾器,
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/387244.html
上一篇:AdMob-找不到名稱為com.google.DummyAdapter的廣告網路配接器
下一篇:為什么.bss段沒有可執行屬性?
