How to use LUT png for CIColorCube filter?

元气小坏坏 提交于 2019-12-20 10:57:52

问题


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:


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!
}


来源:https://stackoverflow.com/questions/30267567/how-to-use-lut-png-for-cicolorcube-filter

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