Получите фильтр CIColorCube, работающий в Swift

Я пытаюсь заставить работать фильтр CIColorCube. Однако в документах Apple представлен только плохо объясненный справочный пример:

// Allocate memory
const unsigned int size = 64;
float *cubeData = (float *)malloc (size * size * size * sizeof (float) * 4);
float rgb[3], hsv[3], *c = cubeData;

// Populate cube with a simple gradient going from 0 to 1
for (int z = 0; z < size; z++){
    rgb[2] = ((double)z)/(size-1); // Blue value
    for (int y = 0; y < size; y++){
        rgb[1] = ((double)y)/(size-1); // Green value
        for (int x = 0; x < size; x ++){
            rgb[0] = ((double)x)/(size-1); // Red value
            // Convert RGB to HSV
            // You can find publicly available rgbToHSV functions on the Internet
            rgbToHSV(rgb, hsv);
            // Use the hue value to determine which to make transparent
            // The minimum and maximum hue angle depends on
            // the color you want to remove
            float alpha = (hsv[0] > minHueAngle && hsv[0] < maxHueAngle) ? 0.0f: 1.0f;
            // Calculate premultiplied alpha values for the cube
            c[0] = rgb[0] * alpha;
            c[1] = rgb[1] * alpha;
            c[2] = rgb[2] * alpha;
            c[3] = alpha;
            c += 4; // advance our pointer into memory for the next color value
        }
    }
}
// Create memory with the cube data
NSData *data = [NSData dataWithBytesNoCopy:cubeData
                       length:cubeDataSize
                       freeWhenDone:YES];
CIColorCube *colorCube = [CIFilter filterWithName:@"CIColorCube"];
[colorCube setValue:@(size) forKey:@"inputCubeDimension"];
// Set data for cube
[colorCube setValue:data forKey:@"inputCubeData"];

Итак, я попытался перевести это на Swift со следующим:

var filter = CIFilter(name: "CIColorCube")
    filter.setValue(ciImage, forKey: kCIInputImageKey)
    filter.setDefaults()

    var size: UInt = 64
    var floatSize = UInt(sizeof(Float))
    var cubeDataSize:size_t = size * size * size * floatSize * 4
    var colorCubeData:Array<Float> = [
    0,0,0,1,
    0,0,0,1,
    0,0,0,1,
    0,0,0,1,
    0,0,0,1,
    0,0,0,1,
    0,0,0,1,
    0,0,0,1
    ]

    var cubeData:NSData = NSData(bytesNoCopy: colorCubeData, length: cubeDataSize)

Однако я получаю сообщение об ошибке при попытке создать данные куба:

"Extra argument 'bytesNoCopy' in call"

В основном я создаю cubeData неправильно. Можете ли вы посоветовать мне, как правильно создать объект cubeData в Swift?

Спасибо!


person Aggressor    schedule 29.12.2014    source источник
comment
Для всех, кто ищет полное решение, я смог быстро заставить его работать здесь: stackoverflow.com/a/32638622/1807644< /а>   -  person William T.    schedule 17.09.2015


Ответы (2)


Похоже, вам нужен рецепт фильтра хроматического ключа описан здесь. Вот код, который работает. Вы получаете фильтр для цвета, который хотите сделать прозрачным, описываемый его углом HSV:

func RGBtoHSV(r : Float, g : Float, b : Float) -> (h : Float, s : Float, v : Float) {
    var h : CGFloat = 0
    var s : CGFloat = 0
    var v : CGFloat = 0
    let col = UIColor(red: CGFloat(r), green: CGFloat(g), blue: CGFloat(b), alpha: 1.0)
    col.getHue(&h, saturation: &s, brightness: &v, alpha: nil)
    return (Float(h), Float(s), Float(v))
}

func colorCubeFilterForChromaKey(hueAngle: Float) -> CIFilter {

    let hueRange: Float = 60 // degrees size pie shape that we want to replace
    let minHueAngle: Float = (hueAngle - hueRange/2.0) / 360
    let maxHueAngle: Float = (hueAngle + hueRange/2.0) / 360

    let size = 64
    var cubeData = [Float](repeating: 0, count: size * size * size * 4)
    var rgb: [Float] = [0, 0, 0]
    var hsv: (h : Float, s : Float, v : Float)
    var offset = 0

    for z in 0 ..< size {
        rgb[2] = Float(z) / Float(size) // blue value
        for y in 0 ..< size {
            rgb[1] = Float(y) / Float(size) // green value
            for x in 0 ..< size {

                rgb[0] = Float(x) / Float(size) // red value
                hsv = RGBtoHSV(r: rgb[0], g: rgb[1], b: rgb[2])
                // the condition checking hsv.s may need to be removed for your use-case
                let alpha: Float = (hsv.h > minHueAngle && hsv.h < maxHueAngle && hsv.s > 0.5) ? 0 : 1.0 

                cubeData[offset] = rgb[0] * alpha
                cubeData[offset + 1] = rgb[1] * alpha
                cubeData[offset + 2] = rgb[2] * alpha
                cubeData[offset + 3] = alpha
                offset += 4
            }
        }
    }
    let b = cubeData.withUnsafeBufferPointer { Data(buffer: $0) }
    let data = b as NSData

    let colorCube = CIFilter(name: "CIColorCube", withInputParameters: [
        "inputCubeDimension": size,
        "inputCubeData": data
    ])
    return colorCube!
}

Затем, чтобы получить вызов фильтра

let chromaKeyFilter = colorCubeFilterForChromaKey(hueAngle: 120)

Я использовал 120 для вашего стандартного зеленого экрана.

person inorganik    schedule 16.08.2017
comment
Спасибо тебе за это. Спас мой день :) - person maxmzd; 14.09.2018

Я полагаю, вы хотите использовать NSData(bytes: UnsafePointer<Void>, length: Int) вместо NSData(bytesNoCopy: UnsafeMutablePointer<Void>, length: Int). Внесите это изменение и рассчитайте длину следующим образом, и вы должны быть готовы к работе.

let colorCubeData: [Float] = [
    0, 0, 0, 1,
    1, 0, 0, 1,
    0, 1, 0, 1,
    1, 1, 0, 1,
    0, 0, 1, 1,
    1, 0, 1, 1,
    0, 1, 1, 1,
    1, 1, 1, 1
]
let cubeData = NSData(bytes: colorCubeData, length: colorCubeData.count * sizeof(Float))
person embinder    schedule 31.01.2015
comment
Что такое sizeof(Float) - person Joshua Hart; 02.04.2020
comment
Неважно, нашел обновленное: пусть cubeData = Data(bytes: colorCubeData, count: colorCubeData.count * MemoryLayout‹Float›.size) - person Joshua Hart; 02.04.2020