Данные через Buffer Post Xcode 11.5 Обновить

Что у меня есть:

Ссылаясь на код Chroma Key от Apple, говорится, что мы можем создать куб фильтра Chroma Key с помощью

func chromaKeyFilter(fromHue: CGFloat, toHue: CGFloat) -> CIFilter?
{
    // 1
    let size = 64
    var cubeRGB = [Float]()
        
    // 2
    for z in 0 ..< size {
        let blue = CGFloat(z) / CGFloat(size-1)
        for y in 0 ..< size {
            let green = CGFloat(y) / CGFloat(size-1)
            for x in 0 ..< size {
                let red = CGFloat(x) / CGFloat(size-1)
                    
                // 3
                let hue = getHue(red: red, green: green, blue: blue)
                let alpha: CGFloat = (hue >= fromHue && hue <= toHue) ? 0: 1
                    
                // 4
                cubeRGB.append(Float(red * alpha))
                cubeRGB.append(Float(green * alpha))
                cubeRGB.append(Float(blue * alpha))
                cubeRGB.append(Float(alpha))
            }
        }
    }

    let data = Data(buffer: UnsafeBufferPointer(start: &cubeRGB, count: cubeRGB.count))

    // 5
    let colorCubeFilter = CIFilter(name: "CIColorCube", withInputParameters: ["inputCubeDimension": size, "inputCubeData": data])
    return colorCubeFilter
}

Затем я создал функцию, позволяющую вставлять любое изображение в этот фильтр и возвращать отфильтрованное изображение.

public func filteredImage(ciimage: CIImage) -> CIImage? {
    let filter = chromaKeyFilter(fromHue: 110/360, toHue: 130/360)! //green screen effect colors
    filter.setValue(ciimage, forKey: kCIInputImageKey)
    return RealtimeDepthMaskViewController.filter.outputImage
}

Затем я могу выполнить эту функцию для любого изображения и получить изображение с цветным ключом.

if let maskedImage = filteredImage(ciimage: ciimage) {
    //Do something
}
else {
    print("Not filtered image")
}

Проблемы с обновлением:

let data = Data(buffer: UnsafeBufferPointer(start: &cubeRGB, count: cubeRGB.count))

Однако, как только я обновил Xcode до версии 11.6, я получаю предупреждение Initialization of 'UnsafeBufferPointer<Float>' results in a dangling buffer pointer, а также ошибку времени выполнения Thread 1: EXC_BAD_ACCESS (code=1, address=0x13c600020) в строке кода выше.

Я попытался решить эту проблему с помощью этого ответа, чтобы исправить новое UnsafeBufferPointer предупреждение Swift. Затем предупреждение исправляется, и у меня больше нет ошибки во время выполнения.

Проблема

Теперь, хотя предупреждение не появляется и у меня не возникает ошибки во время выполнения, я все равно получаю оператор печати Not filtered image. Я предполагаю, что проблема связана с тем, как данные обрабатываются или удаляются, не совсем уверен, как правильно обрабатывать UnsafeBufferPointers вместе с Data.

Как правильно получить Data для хроматического ключа?


person impression7vx    schedule 27.07.2020    source источник


Ответы (1)


Я не был уверен, что RealtimeDepthMaskViewController было в этом контексте, поэтому вместо этого просто вернул результат фильтра. Приносим извинения, если это было задумано оставить как есть. Также добавлен оператор защиты с возможностью возврата nil, что соответствует вашему необязательному типу возврата для функции.

public func filteredImage(ciImage: CIImage) -> CIImage? {
    guard let filter = chromaKeyFilter(fromHue: 110/360, toHue: 130/360) else { return nil }
    filter.setValue(ciImage, forKey: "inputImage")
    return filter.outputImage // instead of RealtimeDepthMaskViewController.filter.outputImage
}

Для предупреждения компилятора о висящем указателе я нашел несколько подходов:

// approach #1
var data = Data()
cubeRGB.withUnsafeBufferPointer { ptr in
    data = Data(buffer: ptr)
}

// approach #2
let byteCount = MemoryLayout<Float>.size * cubeRGB.count
let data = Data(bytes: &cubeRGB, count: byteCount)

Одно предостережение: посмотрел на это с помощью Xcode 11.6, а не 11.5

person lentil    schedule 04.08.2020
comment
В итоге я придумал решение до вашего ответа и полностью забыл о посте! Тем не менее, я отдам его вам, раз уж вы ответили :) Пара вещей, которые, однако, были для меня другими; var data = Data() должен быть типа [UInt8]. data.append(contentsOf: $0) вместо data = Data(buffer: ptr) Наконец, CIFilter должен принять NSData, поэтому вам нужно сделать что-то вроде let finalData = NSData(bytes: data, length: data.count. Тем не менее, спасибо за ответ! - person impression7vx; 05.08.2020
comment
Этот ответ очень полезен @lentil. Но знаете ли вы, почему процесс блокирует основной поток? Пока не будет возвращено окончательное изображение, все действия пользовательского интерфейса в основном потоке заморожены. - person Umit Kaya; 26.04.2021
comment
Привет, @UmitKaya. Рад, что вы нашли это полезным! По вашему вопросу о ветке - исходное сообщение не указывает контекст, в котором вызывается метод, но если вы вызываете метод из основного, он будет заблокирован до возврата. Рассмотрите возможность вызова метода в виде обратного вызова или отправьте работу в очередь отправки. - person lentil; 26.04.2021
comment
Кажется, CoreML использует графический процессор в основном потоке. Это тяжелая работа, из-за которой основной поток зависает на секунду или две. Ранее они обсуждали это здесь: developer.apple.com/forums/thread/92996 В любом случае, мне удалось переместить CoreML в фоновый поток и синхронизировать с основным потоком после возврата результата. Спасибо за советы. - person Umit Kaya; 26.04.2021