Как применить Vignette CIFilter к прямой трансляции с камеры в iOS?

Пытаясь применить простой фильтр виньетки к необработанному каналу камеры iPhone6 ​​с помощью Metal и Core Image, я заметил большую задержку между кадрами, обрабатываемыми и визуализируемыми в MTKView

Я придерживался следующего подхода (MetalViewController.swift):

  1. Получите необработанный вывод камеры с помощью AVCaptureVideoDataOutputSampleBufferDelegate
  2. Преобразовать CMSampleBuffer> CVPixelBuffer> CGImage
  3. Создайте MTLTexture с этим CGImage.

Пункт № 2 и 3 находятся внутри метода с именем: fillMTLTextureToStoreTheImageData

  1. Примените CIFilter к CIImage, полученному из MTLTexture в MTKViewDelegate
    func draw(in view: MTKView) {

        if let currentDrawable = view.currentDrawable {
            let commandBuffer = self.commandQueue.makeCommandBuffer()

            if let myTexture = self.sourceTexture{

                let inputImage = CIImage(mtlTexture: myTexture, options: nil)

                self.vignetteEffect.setValue(inputImage, forKey: kCIInputImageKey)

                self.coreImageContext.render(self.vignetteEffect.outputImage!, to: currentDrawable.texture, commandBuffer: commandBuffer, bounds: inputImage!.extent, colorSpace: self.colorSpace)

                commandBuffer?.present(currentDrawable)

                commandBuffer?.commit()
            }
        }
    }

Производительность совсем не та, что Apple упомянула в этом документе: https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/CoreImaging/ci_tasks/ci_tasks.html#//apple_ref/doc/uid/TP30001185-CH3-TPXREF101

Я что-то упускаю?


person nr5    schedule 22.12.2018    source источник
comment
Я ничего не знаю о части камеры, но вот фильтр виньетки на основе быстрого металла: github.com/mattneub/Programming-iOS-Book-Examples/blob/master/   -  person matt    schedule 22.12.2018
comment
@matt Думаю, я уже добился этого без использования металла. Применение CIFiilter к образу происходит очень быстро только с помощью самого основного образа. Когда мы пытаемся обработать каждый необработанный кадр видео, ситуация выходит из-под контроля. Чтобы исправить это, я использовал металл, но он не работал так, как предполагалось.   -  person nr5    schedule 23.12.2018
comment
Что ж, может, здесь металл - отвлекающий маневр. У Apple есть образец кода, показывающий, как применить эффект CIFilter к видео, хотя я бы сомневался, сможет ли он не отставать от живого видео.   -  person matt    schedule 23.12.2018
comment
Если вы видите ссылку в моем вопросе, Apple четко говорит, что для рендеринга живых кадров требуется металл или opengl. Я проделал те же шаги. Но я думаю, что Apple предоставила очень простую реализацию, игнорирующую производительность и накладные расходы.   -  person nr5    schedule 23.12.2018
comment
Да, это могло быть правдой. Я могу найти только пример кода FunHouse и видеоролик WWDC 2013 session 509 по этой теме.   -  person matt    schedule 23.12.2018
comment
Я почти уверен, что ваша медлительность вызвана созданием CGImage из CVPixelBuffer, а затем текстуры металла из этого, а не прямым переходом от CVPixelBuffer к MTLTexture. Для этого вы можете использовать CVMetalTextureCache.   -  person Ken Thomases    schedule 23.12.2018
comment
Я тоже подумал о том же и последовал этому: navoshta.com/metal-camera -part-2-metal-texture но не повезло. Скоро буду фиксировать свой код с кодом MTLTexture, а пока не могли бы вы проверить эту ссылку, чтобы узнать, иду ли я в правильном направлении?   -  person nr5    schedule 23.12.2018
comment
@ nr5, если теперь есть способ без проблем с производительностью и накладных расходов при использовании CIImage. Я думаю, это потому, что CIContext использует CPU для преобразования CIImage во что-то. Я тестировал почти все способы   -  person Aznix    schedule 23.05.2020


Ответы (1)


Ваш шаг 2 слишком медленный, чтобы поддерживать рендеринг в реальном времени ... и похоже, что вам не хватает пары шагов. Для вашей цели вы обычно:

Настраивать:

  1. создать пул из CVPixelBuffer - используя CVPixelBufferPoolCreate
  2. создать бассейн металлических текстур с помощью CVMetalTextureCacheCreate

Для каждого кадра:

  1. преобразовать CMSampleBuffer> CVPixelBuffer> CIImage
  2. Пропустите этот CIImage через конвейер фильтров
  3. визуализировать выходное изображение в CVPixelBuffer из пула, созданного на шаге 1
  4. используйте CVMetalTextureCacheCreateTextureFromImage для создания металлической текстуры с помощью отфильтрованного CVPixelBuffer

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

Хорошая новость в том, что все это продемонстрировано в примере кода AVCamPhotoFilter от Apple https://developer.apple.com/library/archive/samplecode/AVCamPhotoFilter/Introduction/Intro.html#//apple_ref/doc/.uid/TP40017556. В частности, см. Класс RosyCIRenderer и его суперкласс FilterRenderer.

person Sébastien A    schedule 24.12.2018
comment
Спасибо за направление. Один вопрос, как вы определили, когда вы говорите, что все эти шаги будут гарантировать, что данные вашего изображения останутся на графическом процессоре, в отличие от перехода от графического процессора к процессору и обратно к графическому процессору для отображения? Насколько мне известно, MTLDevice представляет операции / вычисления графического процессора, поэтому я подумал, что отправка моего CGImage в MTLTexture и получение MLTexture в делегате draw поможет повысить производительность. - person nr5; 24.12.2018
comment
Боюсь, что для рендеринга выходного изображения в CVPixelBuffer вы должны использовать ciContext.render(ciImage, to: pixelBuffer), и этот код запускается в ЦП - person Aznix; 23.05.2020