Статьи

Swifter Swift Обработка изображений с помощью GPUImage

Я большой поклонник технологии  Apple Core Image  : мое   приложение Nodality полностью основано на фильтрах Core Image. Тем не менее, для новых пользователей код для добавления простого фильтра к изображению немного наклонен, а реализация очень строковая.

В этом посте рассматривается альтернатива,  GPUImage  от  Брэда ЛарсонаGPUImage  — это фреймворк, содержащий богатый набор фильтров изображений, многие из которых отсутствуют в Core Image. Он имеет гораздо более простой и строго типизированный API и в некоторых случаях работает быстрее, чем Core Image.

Для начала давайте рассмотрим код, необходимый для применения гауссовского синего цвета к изображению ( inputImage ) с помощью Core Filter:

        let inputImage = UIImage()
        let ciContext = CIContext(options: nil)
        
        let blurFilter = CIFilter(name: "CIGaussianBlur")
        blurFilter.setValue(CIImage(image: inputImage), forKey: "inputImage")
        blurFilter.setValue(10, forKey: "inputRadius")
        
        let outputImageData = blurFilter.valueForKey("outputImage") as CIImage!
        let outputImageRef: CGImage = ciContext.createCGImage(outputImageData, fromRect: outputImageData.extent())

        let outputImage = UIImage(CGImage: outputImageRef)!

… мы не только должны явно определять контекст, но и имя фильтра и параметр являются строками, и нам нужно несколько шагов, чтобы преобразовать выходные данные фильтра в  UIImage

Вот та же функциональность с использованием  GPUImage :

        let inputImage = UIImage()
        
        let blurFilter = GPUImageGaussianBlurFilter()
        blurFilter.blurRadiusInPixels = 10
        
        let outputImage = blurFilter.imageByFilteringImage(inputImage)

Здесь и фильтр, и его параметр радиуса размытия введены правильно, и фильтр возвращает   экземпляр UIImage .
С другой стороны, есть некоторые настройки, чтобы сделать. После того, как  вы получили локальную копию  из  GPUImage , перетащите рамки проекта в проект приложения. Затем на этапах сборки цели приложения добавьте зависимость цели, ссылку на GPUImage.framework в бинарных файлах ссылок и этап копирования файлов.
Экран фаз сборки должен выглядеть следующим образом:

Затем, просто импортировав  GPUImage , вы готовы к работе.

Чтобы продемонстрировать некоторые забавные фильтры, содержащиеся в  GPUImage , я создал небольшое демонстрационное приложение, GPUImageDemo .

Приложение демонстрирует Polar Pixellate, Polka Dot, Sketch, Threshold Sketch, Toon, Smooth Toon, Emboss, Sphere Refraction и Glass Sphere — ни один из которых не доступен в Core Image.

Вся работа по фильтрации выполняется в моем   классе GPUImageDelegate, где оператор switch объявляет  переменную GPUImageOutput (класс, который включает метод  imageByFiltering ()  ) и устанавливает его для соответствующего конкретного класса в зависимости от пользовательского интерфейса.

Например, если для средства выбора задан эскиз порога, выполняется следующая инструкция case:

       case ImageFilter.ThresholdSketch:

            gpuImageFilter =  GPUImageThresholdSketchFilter()
            
            if let gpuImageFilter = gpuImageFilter as? GPUImageThresholdSketchFilter
            {
                if values.count > 1
                {
                    gpuImageFilter.edgeStrength = values[0]
                    gpuImageFilter.threshold = values[1]
                }
            }

Если вы создаете этот проект, вы можете столкнуться с ошибкой сборки в целевой документации. Я просто удалил эту цель на зараженных машинах.

GPUImage  достаточно быстр для фильтрации видео. Я взял свой недавний  эксперимент с двумя миллионами частиц  и добавил этап постобработки, который состоит из фильтра мультфильмов и фильтра тиснения. Они упакованы вместе в GPUImageFilterGroup :

        let toonFilter = GPUImageSmoothToonFilter()
        let embossFilter = GPUImageEmbossFilter()

        let filterGroup = GPUImageFilterGroup()


        toonFilter.threshold = 1
        embossFilter.intensity = 2
        filterGroup.addFilter(toonFilter)
        filterGroup.addFilter(embossFilter)
        
        toonFilter.addTarget(embossFilter)
        
        filterGroup.initialFilters = [ toonFilter ]

        filterGroup.terminalFilter = embossFilter

Поскольку  GPUImageFilterGroup расширяет  GPUImageFilterOutput , я могу взять вывод из текстуры Metal, создать его  экземпляр UIImage и передать его в составной фильтр:

        self.imageView.image = self.filterGroup.imageByFilteringImage(UIImage(CGImage: imageRef)!)

На моем iPad Air 2 конечный результат 2 000 000 частиц с последующей обработкой двумя фильтрами на изображении с разрешением 1024 x 1024 по-прежнему работает со скоростью около 20 кадров в секунду. Вот снимок экрана в реальном времени:

Исходный код моего  GPUImageDemo  доступен в  моем репозитории GitHub здесь,  а  GPUImage здесь .