How to use LUT png for CIColorCube filter?

匿名 (未验证) 提交于 2019-12-03 02:50:02

问题:

I would like to use a lookup table png (example) as color cube data for the CIColorCube filter in Swift. All I tried (and found) so far are examples with a computed color cube as in this example.

How can I read a png as lookup data?

回答1:

I now used this and this project to adapt their Objective-C implementation for Swift:

func colorCubeFilterFromLUT(imageName : NSString) -> CIFilter? {      let kDimension : UInt = 64      let lutImage    = UIImage(named: imageName)!.CGImage     let lutWidth    = CGImageGetWidth(lutImage!)     let lutHeight   = CGImageGetHeight(lutImage!)     let rowCount    = lutHeight / kDimension     let columnCount = lutWidth / kDimension      if ((lutWidth % kDimension != 0) || (lutHeight % kDimension != 0) || (rowCount * columnCount != kDimension)) {          NSLog("Invalid colorLUT %@", imageName);         return nil     }      let bitmap  = self.createRGBABitmapFromImage(lutImage)     let size    = Int(kDimension) * Int(kDimension) * Int(kDimension) * sizeof(Float) * 4     let data    = UnsafeMutablePointer<Float>(malloc(UInt(size)))      var bitmapOffset : Int = 0     var z : UInt = 0       for (var row: UInt = 0; row < rowCount; row++)     {         for (var y: UInt = 0; y < kDimension; y++)         {             var tmp = z             for (var col: UInt = 0; col < columnCount; col++)             {                 for (var x: UInt = 0; x < kDimension; x++) {                      let alpha   = Float(bitmap[Int(bitmapOffset)]) / 255.0                     let red     = Float(bitmap[Int(bitmapOffset+1)]) / 255.0                     let green   = Float(bitmap[Int(bitmapOffset+2)]) / 255.0                     let blue    = Float(bitmap[Int(bitmapOffset+3)]) / 255.0                      var dataOffset = Int(z * kDimension * kDimension + y * kDimension + x) * 4                      data[dataOffset] = red                     data[dataOffset + 1] = green                     data[dataOffset + 2] = blue                     data[dataOffset + 3] = alpha                     bitmapOffset += 4                 }                 z++             }             z = tmp         }         z += columnCount     }      let colorCubeData = NSData(bytesNoCopy: data, length: size, freeWhenDone: true)      // create CIColorCube Filter     var filter = CIFilter(name: "CIColorCube")     filter.setValue(colorCubeData, forKey: "inputCubeData")     filter.setValue(kDimension, forKey: "inputCubeDimension")      return filter }   func createRGBABitmapFromImage(inImage: CGImage) -> UnsafeMutablePointer<Float> {      //Get image width, height     let pixelsWide = CGImageGetWidth(inImage)      let pixelsHigh = CGImageGetHeight(inImage)       // Declare the number of bytes per row. Each pixel in the bitmap in this     // example is represented by 4 bytes; 8 bits each of red, green, blue, and     // alpha.     let bitmapBytesPerRow = Int(pixelsWide) * 4      let bitmapByteCount = bitmapBytesPerRow * Int(pixelsHigh)      // Use the generic RGB color space.     let colorSpace = CGColorSpaceCreateDeviceRGB()      // Allocate memory for image data. This is the destination in memory     // where any drawing to the bitmap context will be rendered.     let bitmapData = malloc(CUnsignedLong(bitmapByteCount)) // bitmap     let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue)       // Create the bitmap context. We want pre-multiplied RGBA, 8-bits     // per component. Regardless of what the source image format is     // (CMYK, Grayscale, and so on) it will be converted over to the format     // specified here by CGBitmapContextCreate.     let context = CGBitmapContextCreate(bitmapData, pixelsWide, pixelsHigh, 8, UInt(bitmapBytesPerRow), colorSpace, bitmapInfo)       let rect = CGRect(x:0, y:0, width:Int(pixelsWide), height:Int(pixelsHigh))              // Draw the image to the bitmap context. Once we draw, the memory     // allocated for the context for rendering will then contain the     // raw image data in the specified color space.     CGContextDrawImage(context, rect, inImage)      // Now we can get a pointer to the image data associated with the bitmap     // context.     // var data = CGBitmapContextGetData(context)     // var dataType = UnsafeMutablePointer<Float>(data)     // return dataType       var convertedBitmap = malloc(UInt(bitmapByteCount * sizeof(Float)))     vDSP_vfltu8(UnsafePointer<UInt8>(bitmapData), 1, UnsafeMutablePointer<Float>(convertedBitmap), 1, vDSP_Length(bitmapByteCount))      free(bitmapData)     return UnsafeMutablePointer<Float>(convertedBitmap) } 

Also see this answer.



回答2:

While it's not the exact same type of LUT image you have linked, CocoaLUT, my 1D and 3D LUT framework for Cocoa, can read and write 3 different types of LUT images.

When I first started making CocoaLUT and wrote the Image-Based LUT readers/writers, I didn't know how to do low level bitmap image work in Cocoa. I just used NSBitmapImageRep, which means you're out of luck if you need to do this in iOS until I decide to go back and revamp it to work with Core Graphics knowing what I know now.

In the case that you are writing this for a Mac app, you should just be able to do (in Swift):

let imageLUT = LUT3D(fromURL:NSURL.fileURLWithPath("/path/to/image.tiff"), error: nil) let cubeFilter = imageLUT.coreImageFilterWithCurrentColorSpace() 

If you need to first generate a blank or "identity" LUT Image to perform grading on, you should do (in Swift):

let identity33 = LUT3D(identityOfSize: 33, inputLowerBound: 0, inputUpperBound: 1); let success = identity33.writeToURL(NSURL.fileURLWithPath("/path/to/output.tiff"), atomically: true, formatterID: "unwrappedCube", options: nil, conformLUT: true) 

Please note that you need to do this with TIFF files throughout! Again, generalizing the code for Core Graphics will fix all this, if I finally get around to it.



回答3:

Thought I would update this for Swift 3.0 also this works for JPG's and PNG's 3D Color LUTs

fileprivate func colorCubeFilterFromLUT(imageName : String) -> CIFilter? {      let size = 64      let lutImage    = UIImage(named: imageName)!.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 %@", imageName);         return nil     }      let bitmap  = getBytesFromImage(image: UIImage(named: imageName))!     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 = NSData(bytesNoCopy: cubeData, length: size * size * size * 4 * floatSize, freeWhenDone: true)      // create CIColorCube Filter     let filter = CIFilter(name: "CIColorCube")     filter?.setValue(colorCubeData, forKey: "inputCubeData")     filter?.setValue(size, forKey: "inputCubeDimension")      return filter }   fileprivate 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! } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!