zoukankan      html  css  js  c++  java
  • GPUImage2的使用

    GPUImage是一个基于OpenGL ES 2.0的开源的图像处理库,作者是Brad Larson。GPUImage将OpenGL ES封装为简洁的Objective-C或Swift接口,可以用来给图像、实时相机视频、电影等添加滤镜。对于诸如处理图像或实况视频帧的大规模并行操作,GPU相对于CPU具有一些显着的性能优点。在iPhone 4上,简单的图像滤镜在GPU上的执行速度比等效的基于CPU的滤镜快100多倍,与Core Image (ios5.0的一部分)相比,GPUImage允许您编写自己的自定义滤镜,支持部署到ios4.0,并且有一个更简单的界面。然而,它目前缺乏核心图像的一些更高级的特征,比如面部检测等功能。

     我发现在创建和使用OpenGLES过程中需要编写大量的样板代码。因此,GPUImage封装了处理图像和视频时会遇到的许多常见任务,这样就不需要关心OpenGL ES 2.0的基础了。

     GPUImage有三个版本,GPUImage是基于OpenGL ES 使用OC语言写的,对于OC的项目可以集成并使用它,GPUImage2是用Swift语言写的基于OpenGL ES2.0,GPUImage3是基于苹果的图像渲染框架Metal封装的,语言也是swift,可以根据自己的需求集成不同版本的GPUImage,本篇介绍GPUImage2使用,语言为Swift。

    一、处理静态图片使用滤镜

    class StillImageViewController: UIViewController {
        lazy var imageView: UIImageView = {
            let imageView = UIImageView(frame: CGRect(x: 0, y: 0,  UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
            imageView.image = UIImage(contentsOfFile: Bundle.main.path(forResource: "hulu", ofType: "jpg")!)
            imageView.contentMode = .scaleAspectFit
            
            return imageView
        }()
        var slider: UISlider = {
            
            let slider = UISlider(frame: CGRect(x: 20, y: SCREEN_HEIGHT - 30,  SCREEN_WIDTH - 40, height: 20))
            return slider
        }()
        var filter:BasicOperation!
        var pictureInput : PictureInput!
        var filterModel:FilterModel = FilterModel(name: "BrightnessAdjustment 亮度",
                    filterType: .basicOperation,
                    range: (-1.0, 1.0, 0.0),
                    initCallback: {BrightnessAdjustment()},
                    valueChangedCallback: nil)
        let renderView = RenderView(frame:CGRect(x: 0, y: 0,  SCREEN_WIDTH, height: SCREEN_HEIGHT - 85))
        override func viewDidLoad() {
            super.viewDidLoad()
            title = "图片滤镜"
            view.backgroundColor = .white
            view.addSubview(imageView)
            view.addSubview(renderView)
            renderView.backgroundColor = .white
            renderView.isHidden = true
            view.addSubview(slider)
            slider.isHidden = true
            slider.addTarget(self, action: #selector(sliderValueChanged(slider:)), for: .valueChanged)
            pictureInput = PictureInput(image: imageView.image!)
            
            let filterButton = UIButton(frame: CGRect(x: 90, y: UIScreen.main.bounds.height - 80,  150, height: 40))
            filterButton.setTitle("选择滤镜", for: UIControl.State.normal)
            filterButton.center.x = view.center.x
            filterButton.backgroundColor = .gray
            filterButton.addTarget(self, action: #selector(ChoseFilters(btn:)), for: .touchUpInside)
            view.addSubview(filterButton)
    
        }
    
        @objc func ChoseFilters(btn:UIButton) {
            imageView.isHidden = true
            renderView.isHidden = false
            
            let fvc = FilterListTableViewController()
            fvc.filterBlock =  {  [weak self] filterModel in
                guard let `self` = self else {
                    return
                }
                self.filterModel = filterModel
                
                self.setupFilterChain(filterModel: filterModel)
                
            }
            self.navigationController?.pushViewController(fvc, animated: true)
            
        }
        func setupFilterChain(filterModel:FilterModel) {
            title = filterModel.name
            //           pictureInput = PictureInput(image: MaYuImage)
            slider.minimumValue = filterModel.range?.0 ?? 0
            slider.maximumValue = filterModel.range?.1 ?? 0
            slider.value = filterModel.range?.2 ?? 0
            let filterObject = filterModel.initCallback()
            
            pictureInput.removeAllTargets()
            self.filter?.removeAllTargets()
            
            switch filterModel.filterType! {
                
            case .imageGenerators:
               imageView.image = imageView.image
            case .basicOperation:
                if let actualFilter = filterObject as? BasicOperation {
                    self.filter = actualFilter
                    pictureInput --> filter --> renderView
                }
                
            case .operationGroup:
                if let actualFilter = filterObject as? OperationGroup {
                    pictureInput --> actualFilter --> renderView
                }
                
            case .blend:
                if let actualFilter = filterObject as? BasicOperation {
                    self.filter = actualFilter
                    let blendImgae = PictureInput(image: flowerImage)
                    blendImgae --> actualFilter
                    pictureInput --> filter --> renderView
                    blendImgae.processImage()
                    
                }
                
            case .custom:
                
                filterModel.customCallback!(pictureInput, filterObject, renderView)
                filter = filterObject as? BasicOperation
            }
            
            pictureInput.processImage()
            
            self.sliderValueChanged(slider: slider)
        }
        
        @objc func sliderValueChanged(slider: UISlider) {
            
            if let actualCallback = filterModel.valueChangedCallback {
                actualCallback(filter, slider.value)
                slider.isHidden = false
            } else {
                slider.isHidden = true
            }
            
            if filterModel.filterType! != .imageGenerators {
                pictureInput.processImage()
            }
        }
        func filteringImage() {
            
            // 创建一个BrightnessAdjustment颜色处理滤镜
            let brightnessAdjustment = BrightnessAdjustment()
            brightnessAdjustment.brightness = 0.2
            
            // 创建一个ExposureAdjustment颜色处理滤镜
            let exposureAdjustment = ExposureAdjustment()
            exposureAdjustment.exposure = 0.5
            
            // 1.使用GPUImage对UIImage的扩展方法进行滤镜处理
            var filteredImage: UIImage
            
            // 1.1单一滤镜
            filteredImage = imageView.image!.filterWithOperation(brightnessAdjustment)
            
            // 1.2多个滤镜叠加
            filteredImage = imageView.image!.filterWithPipeline { (input, output) in
                input --> brightnessAdjustment --> exposureAdjustment --> output
            }
            
            // 不建议的
            imageView.image = filteredImage
            
            // 2.使用管道处理
            
            // 创建图片输入
            let pictureInput = PictureInput(image: imageView.image!)
            // 创建图片输出
            let pictureOutput = PictureOutput()
            // 给闭包赋值
            pictureOutput.imageAvailableCallback = { image in
                // 这里的image是处理完的数据,UIImage类型
            }
            // 绑定处理链
            pictureInput --> brightnessAdjustment --> exposureAdjustment --> pictureOutput
            // 开始处理 synchronously: true 同步执行 false 异步执行,处理完毕后会调用imageAvailableCallback这个闭包
            pictureInput.processImage(synchronously: true)
        }
        
    }

    二、拍摄照片使用滤镜

    class TakePhotoViewController: UIViewController {
        
        var filterModel:FilterModel = FilterModel(name: "BrightnessAdjustment 亮度",
                                                  filterType: .basicOperation,
                                                  range: (-1.0, 1.0, 0.5),
                                                  initCallback: {BrightnessAdjustment()},
                                                  valueChangedCallback: { (filter, value) in
                                                    (filter as! BrightnessAdjustment).brightness = value
        })
        var picture:PictureInput!
        var filter:BasicOperation!
        var camera: Camera!
        var movieOutput:MovieOutput? = nil
        var movie: MovieInput!
        var renderView: RenderView!
        
        var takeButton : UIButton!
        var filterButton : UIButton!
        var reTakeButton : UIButton!
        var slider: UISlider = {
            
            let slider = UISlider(frame: CGRect(x: 20, y: SCREEN_HEIGHT - 30,  SCREEN_WIDTH - 40, height: 20))
            return slider
        }()
        func creaatRenderView() -> RenderView{
            let renderView = RenderView(frame:CGRect(x: 0, y: 0,  SCREEN_WIDTH, height: SCREEN_HEIGHT - 100))
            return renderView
        }
        lazy var imageView: UIImageView = {
            let imageView = UIImageView(frame: CGRect(x: 0, y: 0,  SCREEN_WIDTH, height: SCREEN_HEIGHT - 80))
            imageView.image = UIImage(contentsOfFile: Bundle.main.path(forResource: "hulu", ofType: "jpg")!)
            imageView.contentMode = .scaleAspectFit
            imageView.backgroundColor = .purple
            imageView.isHidden = true
            return imageView
        }()
        @objc func ChoseFilters(btn:UIButton) {
            
            let fvc = FilterListTableViewController()
            fvc.filterBlock =  {  [weak self] filterModel in
                guard let `self` = self else {
                    return
                }
                self.filterModel = filterModel
                
                self.setupFilterChain(filterModel: filterModel)
                
            }
            self.navigationController?.pushViewController(fvc, animated: true)
            
        }
        func setupFilterChain(filterModel:FilterModel) {
            title = filterModel.name
            //           pictureInput = PictureInput(image: MaYuImage)
            slider.minimumValue = filterModel.range?.0 ?? 0
            slider.maximumValue = filterModel.range?.1 ?? 0
            slider.value = filterModel.range?.2 ?? 0
            let filterObject = filterModel.initCallback()
            
            camera.removeAllTargets()
            filter.removeAllTargets()
            renderView.sources.removeAtIndex(0)
            switch filterModel.filterType! {
                
            case .imageGenerators:
                filterObject as! ImageSource --> renderView
                
            case .basicOperation:
                if let actualFilter = filterObject as? BasicOperation {
                    filter = actualFilter
                    camera --> actualFilter --> renderView
                    //                   pictureInput.processImage()
                }
                
            case .operationGroup:
                if let actualFilter = filterObject as? OperationGroup {
                    camera --> actualFilter --> renderView
                }
                
            case .blend:
                if let actualFilter = filterObject as? BasicOperation {
                    filter = actualFilter
                    let blendImgae = PictureInput(image: flowerImage)
                    blendImgae --> actualFilter
                    camera --> actualFilter --> renderView
                    blendImgae.processImage()
                    
                }
                
            case .custom:
                filterModel.customCallback!(camera, filterObject, renderView)
                filter = filterObject as? BasicOperation
                
            }
            
            
            
            self.sliderValueChanged(slider: slider)
        }
        
        @objc func sliderValueChanged(slider: UISlider) {
            
            //           print("slider value: (slider.value)")
            
            if let actualCallback = filterModel.valueChangedCallback {
                actualCallback(filter, slider.value)
                slider.isHidden = false
            } else {
                slider.isHidden = true
            }
            
            if filterModel.filterType! != .imageGenerators {
                
            }
        }
      
        //拍摄
        @objc func takePhoto() {
            takeButton.isHidden = true
            reTakeButton.isHidden = false
            
            
            // 设置保存路径
            guard let outputPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else { return }
    
            let originalPath = outputPath + "/originalImage.png"
            print("path: (originalPath)")
            let originalURL = URL(fileURLWithPath: originalPath)
    
            let filteredPath = outputPath + "/filteredImage.png"
            print("path: (filteredPath)")
    
            let filteredlURL = URL(fileURLWithPath: filteredPath)
            // 保存相机捕捉到的图片
            self.camera.saveNextFrameToURL(originalURL, format: .png)
    
            // 保存滤镜后的图片
            self.filter.saveNextFrameToURL(filteredlURL, format: .png)
    
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .milliseconds(100)) {
                self.renderView.isHidden = true
                self.imageView.isHidden = false
                self.imageView.image = UIImage(contentsOfFile: filteredPath)
            }
            
    //        // 如果需要处理回调,有下面两种写法
    //        let dataOutput = PictureOutput()
    //        dataOutput.encodedImageFormat = .png
    //        dataOutput.encodedImageAvailableCallback = {imageData in
    //            // 这里的imageData是截取到的数据,Data类型
    //        }
    //        self.camera --> dataOutput
    //
    //        let imageOutput = PictureOutput()
    //        imageOutput.encodedImageFormat = .png
    //        imageOutput.imageAvailableCallback = {image in
    //            // 这里的image是截取到的数据,UIImage类型
    //            self.imageView.image = image
    //        }
    //
    //        self.camera --> imageOutput
            
        }
        override func viewDidLoad() {
            super.viewDidLoad()
            title = "拍照滤镜"
            view.backgroundColor = .white
            
            slider.addTarget(self, action: #selector(sliderValueChanged(slider:)), for: .valueChanged)
            self.renderView = creaatRenderView()
            view.addSubview(renderView)
            view.addSubview(imageView)
            view.addSubview(slider)
            slider.isHidden = true
            
            if let fi = filterModel.initCallback() as? BasicOperation{
                filter = fi
            }else{
                filter = BrightnessAdjustment()
            
            }
            
            takeButton = UIButton(frame: CGRect(x: 20, y: UIScreen.main.bounds.height - 100, 60, height: 60))
            takeButton.setTitle("拍摄", for: UIControl.State.normal)
            takeButton.backgroundColor = .gray
            takeButton.center.x = self.view.center.x
            takeButton.layer.cornerRadius = 30
            takeButton.addTarget(self, action: #selector(takePhoto), for: UIControl.Event.touchUpInside)
            view.addSubview(takeButton)
            
            filterButton = UIButton(frame: CGRect(x: UIScreen.main.bounds.width - 100, y: UIScreen.main.bounds.height - 90,  80, height: 40))
            filterButton.setTitle("选择滤镜", for: UIControl.State.normal)
            filterButton.backgroundColor = .gray
            filterButton.addTarget(self, action: #selector(ChoseFilters), for: .touchUpInside)
            view.addSubview(filterButton)
            
            reTakeButton = UIButton(frame: CGRect(x: UIScreen.main.bounds.width - 100, y: UIScreen.main.bounds.height - 90,  80, height: 40))
            reTakeButton.setTitle("重新拍摄", for: UIControl.State.normal)
            reTakeButton.backgroundColor = .gray
            reTakeButton.center.x = self.view.center.x
            reTakeButton.addTarget(self, action: #selector(retake), for: UIControl.Event.touchUpInside)
            view.addSubview(reTakeButton)
            
            reTakeButton.isHidden = true
            
            cameraFiltering()
        }
         @objc func retake() {
            takeButton.isHidden = false
            reTakeButton.isHidden = true
            renderView.isHidden = false
            imageView.isHidden = true
        }
        
        func cameraFiltering() {
            
            // Camera的构造函数是可抛出错误的
            do {
                camera = try Camera(sessionPreset: AVCaptureSession.Preset.hd1280x720,
                                    cameraDevice: nil,
                                    location: .backFacing,
                                    captureAsYUV: true)
                
            } catch {
                print(error)
                return
            }
            // 绑定处理链
            camera --> renderView
            
            // 开始捕捉数据
            self.camera.startCapture()
            // 结束捕捉数据
            // camera.stopCapture()
            
        }
    }

    三、播放视频时添加滤镜

    class PlayMoviewViewController: UIViewController {
    
        var filter:BasicOperation = BrightnessAdjustment()
        var renderView: RenderView!
        var filterModel:FilterModel = FilterModel(name: "BrightnessAdjustment 亮度",
                    filterType: .basicOperation,
                    range: (-1.0, 1.0, 0.0),
                    initCallback: {BrightnessAdjustment()},
                    valueChangedCallback: { (filter, value) in
                        (filter as! BrightnessAdjustment).brightness = value
        })
        var movie: MovieInput! = {
            let documentsDir = try! FileManager.default.url(for:.documentDirectory, in:.userDomainMask, appropriateFor:nil, create:true)
            let fileURL = URL(string:"test.mp4", relativeTo:documentsDir)!
            let movie = try? MovieInput(url:fileURL, playAtActualSpeed:true)
            return movie
            
        }()
        var slider: UISlider = {
            
            let slider = UISlider(frame: CGRect(x: 8, y: SCREEN_HEIGHT - 30,  SCREEN_WIDTH - 18, height: 20))
            return slider
        }()
        override func viewDidLoad() {
            super.viewDidLoad()
            title = "播放视频添加滤镜"
            view.backgroundColor = .white
            addbutton()
            
            slider.addTarget(self, action: #selector(sliderValueChanged(slider:)), for: .valueChanged)
            view.addSubview(slider)
            slider.isHidden = true
        }
        @objc func buttonClick(btn:UIButton){
            if btn.tag == 101 {
                
                
            }else if btn.tag == 102{
                playMovie(btn: btn)
            }else if btn.tag == 103{
                
                let fvc = FilterListTableViewController()
                fvc.filterBlock =  {  [weak self] filterModel in
                    guard let `self` = self else {
                        return
                    }
                    self.filterModel = filterModel
                    
                    self.setupFilterChain(filterModel: filterModel)
                    
                }
                self.navigationController?.pushViewController(fvc, animated: true)
                
            }
        }
        
         func setupFilterChain(filterModel:FilterModel) {
                title = filterModel.name
                //           pictureInput = PictureInput(image: MaYuImage)
                slider.minimumValue = filterModel.range?.0 ?? 0
                slider.maximumValue = filterModel.range?.1 ?? 0
                slider.value = filterModel.range?.2 ?? 0
                let filterObject = filterModel.initCallback()
                
                movie.removeAllTargets()
                filter.removeAllTargets()
                renderView.sources.removeAtIndex(0)
                switch filterModel.filterType! {
                    
                case .imageGenerators:
                    filterObject as! ImageSource --> renderView
                    
                case .basicOperation:
                    if let actualFilter = filterObject as? BasicOperation {
                        filter = actualFilter
                        movie --> actualFilter --> renderView
                        //                   pictureInput.processImage()
                    }
                    
                case .operationGroup:
                    if let actualFilter = filterObject as? OperationGroup {
                        movie --> actualFilter --> renderView
                    }
                    
                case .blend:
                    if let actualFilter = filterObject as? BasicOperation {
                        filter = actualFilter
                        let blendImgae = PictureInput(image: flowerImage)
                        blendImgae --> actualFilter
                        movie --> actualFilter --> renderView
                        blendImgae.processImage()
                        
                    }
                    
                case .custom:
                    filterModel.customCallback!(movie, filterObject, renderView)
                    filter = (filterObject as? BasicOperation)!
                }
                
                
                
                self.sliderValueChanged(slider: slider)
            }
               
               @objc func sliderValueChanged(slider: UISlider) {
                   
        //           print("slider value: (slider.value)")
                   
                   if let actualCallback = filterModel.valueChangedCallback {
                       actualCallback(filter, slider.value)
                   } else {
                       slider.isHidden = true
                   }
                   
                   if filterModel.filterType! != .imageGenerators {
                    
                   }
               }
        func addbutton() {
            let buttonX = UIButton(frame: CGRect.zero)
            buttonX.tag = 101
            buttonX.setTitle("选视频", for: UIControl.State.normal)
            buttonX.addTarget(self, action: #selector(buttonClick(btn:)), for: UIControl.Event.touchUpInside)
            buttonX.backgroundColor = UIColor.gray
            let buttonY = UIButton(frame: CGRect.zero)
            
            buttonY.tag = 102
            buttonY.setTitle("播放", for: UIControl.State.normal)
            buttonY.addTarget(self, action: #selector(buttonClick(btn:)), for: UIControl.Event.touchUpInside)
            buttonY.backgroundColor = UIColor.gray
            
            let buttonZ = UIButton(frame: CGRect.zero)
            buttonZ.tag = 103
            buttonZ.setTitle("选滤镜", for: UIControl.State.normal)
            buttonZ.addTarget(self, action: #selector(buttonClick(btn:)), for: UIControl.Event.touchUpInside)
            buttonZ.backgroundColor = UIColor.gray
            
            view.addSubview(buttonX)
            view.addSubview(buttonY)
            view.addSubview(buttonZ)
            
            buttonX.translatesAutoresizingMaskIntoConstraints = false
            buttonY.translatesAutoresizingMaskIntoConstraints = false
            buttonZ.translatesAutoresizingMaskIntoConstraints = false
    
            buttonY.widthAnchor.constraint(equalTo: buttonX.widthAnchor).isActive = true
            buttonZ.widthAnchor.constraint(equalTo: buttonX.widthAnchor).isActive = true
    
            buttonX.leftAnchor.constraint(equalTo: view.leftAnchor,constant: 20).isActive = true
            buttonX.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -5).isActive = true
            buttonX.heightAnchor.constraint(equalToConstant: 60).isActive = true
    
            buttonY.leftAnchor.constraint(equalTo: buttonX.rightAnchor,constant: 10).isActive = true
            buttonY.topAnchor.constraint(equalTo: buttonX.topAnchor).isActive = true
            buttonY.bottomAnchor.constraint(equalTo: buttonX.bottomAnchor).isActive = true
    
            buttonZ.leftAnchor.constraint(equalTo: buttonY.rightAnchor,constant: 10).isActive = true
            buttonZ.topAnchor.constraint(equalTo: buttonX.topAnchor).isActive = true
            buttonZ.bottomAnchor.constraint(equalTo: buttonX.bottomAnchor).isActive = true
            buttonZ.rightAnchor.constraint(equalTo: view.rightAnchor,constant: -20).isActive = true
        }
    
        //播放
        @objc func playMovie(btn:UIButton){
            btn.isSelected = !btn.isSelected
            if btn.isSelected {
                
                btn.setTitle("stop", for: UIControl.State.normal)
                if (movie == nil) {
                    
                    filter = SaturationAdjustment()
                    movie --> filter --> renderView
                    movie.start()
                }else{
                    movie --> filter
                }
                
    //            movie.runBenchmark = true
    //
                
                
                
            }else{
                btn.setTitle("play", for: UIControl.State.normal)
    //            movie.cancel()
                movie.removeAllTargets()
    //            filter.removeAllTargets()
            }
        }
        
    
    }

    四、录制视频添加实时滤镜

    class VideoViewController: UIViewController {
    
        var filterModel:FilterModel = FilterModel(name: "BrightnessAdjustment 亮度",
                    filterType: .basicOperation,
                    range: (-1.0, 1.0, 0.0),
                    initCallback: {BrightnessAdjustment()},
                    valueChangedCallback: { (filter, value) in
                        (filter as! BrightnessAdjustment).brightness = value
        })
        var picture:PictureInput!
        var filter:BasicOperation!
        var camera: Camera!
        var movieOutput:MovieOutput? = nil
        var movie: MovieInput!
        var renderView: RenderView!
        var slider: UISlider = {
            
            let slider = UISlider(frame: CGRect(x: 8, y: SCREEN_HEIGHT - 30,  SCREEN_WIDTH - 18, height: 20))
            return slider
        }()
        //RenderView
        func creaatRenderView() -> RenderView{
            let renderView = RenderView(frame:CGRect(x: 0, y: 0,  SCREEN_WIDTH, height: SCREEN_HEIGHT - 50))
            let button = UIButton(frame: CGRect(x: 20, y: UIScreen.main.bounds.height - 100, 80, height: 40))
            button.setTitle("开始录制", for: UIControl.State.normal)
            button.backgroundColor = .gray
            button.addTarget(self, action: #selector(startVideo(btn:)), for: UIControl.Event.touchUpInside)
            renderView.addSubview(button)
            
            let filterButton = UIButton(frame: CGRect(x: 130, y: UIScreen.main.bounds.height - 100,  80, height: 40))
            filterButton.setTitle("选择滤镜", for: UIControl.State.normal)
            filterButton.backgroundColor = .gray
            filterButton.center.x = self.view.center.x
            filterButton.addTarget(self, action: #selector(ChoseFilters), for: .touchUpInside)
            renderView.addSubview(filterButton)
            
            let playButton = UIButton(frame: CGRect(x: UIScreen.main.bounds.width - 100, y: UIScreen.main.bounds.height - 100,  80, height: 40))
            playButton.setTitle("播放视频", for: UIControl.State.normal)
            playButton.backgroundColor = .gray
            playButton.addTarget(self, action: #selector(playMovie(btn:)), for: UIControl.Event.touchUpInside)
            renderView.addSubview(playButton)
            
            return renderView
        }
        
        @objc func ChoseFilters(btn:UIButton) {
           
            let fvc = FilterListTableViewController()
            fvc.filterBlock =  {  [weak self] filterModel in
                guard let `self` = self else {
                    return
                }
                self.filterModel = filterModel
                
                self.setupFilterChain(filterModel: filterModel)
                
            }
            self.navigationController?.pushViewController(fvc, animated: true)
            
        }
        func setupFilterChain(filterModel:FilterModel) {
            title = filterModel.name
            //           pictureInput = PictureInput(image: MaYuImage)
            slider.minimumValue = filterModel.range?.0 ?? 0
            slider.maximumValue = filterModel.range?.1 ?? 0
            slider.value = filterModel.range?.2 ?? 0
            let filterObject = filterModel.initCallback()
            
            camera.removeAllTargets()
            filter.removeAllTargets()
            renderView.sources.removeAtIndex(0)
            switch filterModel.filterType! {
                
            case .imageGenerators:
                filterObject as! ImageSource --> renderView
                
            case .basicOperation:
                if let actualFilter = filterObject as? BasicOperation {
                    filter = actualFilter
                    camera --> actualFilter --> renderView
                    //                   pictureInput.processImage()
                }
                
            case .operationGroup:
                if let actualFilter = filterObject as? OperationGroup {
                    camera --> actualFilter --> renderView
                }
                
            case .blend:
                if let actualFilter = filterObject as? BasicOperation {
                    filter = actualFilter
                    let blendImgae = PictureInput(image: flowerImage)
                    blendImgae --> actualFilter
                    camera --> actualFilter --> renderView
                    blendImgae.processImage()
                    
                }
                
            case .custom:
                filterModel.customCallback!(camera, filterObject, renderView)
                filter = filterObject as? BasicOperation
                
            }
            
            
            
            self.sliderValueChanged(slider: slider)
        }
           
           @objc func sliderValueChanged(slider: UISlider) {
               
    //           print("slider value: (slider.value)")
               
               if let actualCallback = filterModel.valueChangedCallback {
                   actualCallback(filter, slider.value)
               } else {
                   slider.isHidden = true
               }
               
               if filterModel.filterType! != .imageGenerators {
                
               }
           }
        //播放
        @objc func playMovie(btn:UIButton){
            
            let playVc = PlayMoviewViewController()
            self.navigationController?.pushViewController(playVc, animated: true)
        }
        //拍摄
        @objc func startVideo(btn:UIButton){
            btn.isSelected = !btn.isSelected
            if btn.isSelected {
                btn.setTitle("stop", for: UIControl.State.normal)
                do {
                    let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! as NSString
                    print(documentsPath)
                    let documentsDir = try FileManager.default.url(for:.documentDirectory, in:.userDomainMask, appropriateFor:nil, create:true)
                    let fileURL = URL(string:"test.mp4", relativeTo:documentsDir)!
                    
                    do {
                        try FileManager.default.removeItem(at:fileURL)
                    } catch {
                        print("error")
                    }
                    movieOutput = try MovieOutput(URL:fileURL, size:Size(480, height:640), liveVideo:true)
                    camera.audioEncodingTarget = movieOutput
                    camera.removeAllTargets()
                    camera --> filter --> movieOutput!
                    movieOutput!.startRecording()
                    
                } catch {
                    fatalError("Couldn't initialize movie, error: (error)")
                }
            }else{
                btn.setTitle("start", for: UIControl.State.normal)
                
                movieOutput?.finishRecording{
                    self.camera.audioEncodingTarget = nil
                    self.movieOutput = nil
                }
            }
        }
        override func viewDidLoad() {
            super.viewDidLoad()
            title = "拍摄视频"
            view.backgroundColor = .white
            
            slider.addTarget(self, action: #selector(sliderValueChanged(slider:)), for: .valueChanged)
            self.renderView = creaatRenderView()
            view.addSubview(renderView)
            view.addSubview(slider)
            slider.isHidden = true
            
            if let fi = filterModel.initCallback() as? BasicOperation{
                filter = fi
            }else{
                filter = BrightnessAdjustment()
            }
            cameraFiltering()
        }
        
    
        func cameraFiltering() {
            
            // Camera的构造函数是可抛出错误的
            do {
                camera = try Camera(sessionPreset: AVCaptureSession.Preset.hd1280x720,
                                    cameraDevice: nil,
                                    location: .backFacing,
                                    captureAsYUV: true)
                
            } catch {
                print(error)
                return
            }
            // 绑定处理链
            camera --> renderView
            
            // 开始捕捉数据
            self.camera.startCapture()
            // 结束捕捉数据
            // camera.stopCapture()
            
        }
    
    }

    五、自定义滤镜

     框架使用一系列协议来定义可以输出要处理的图像、接收要处理的图像或同时执行这两种操作的类型。它们分别是ImageSource、ImageConsumer和ImageProcessingOperation协议。任何类型都可以遵循这些协议,但通常使用类。许多常见的滤镜和其他图像处理操作可以被描述为BasicOperation类的子类。BasicOperation提供了从一个或多个图像输入中获取图像所需的大量内部代码,使用指定的着色程序从这些输入中绘制图像,并将该图像提供给所有目标。在基本操作上的变化,如纹理放大操作或两个阶段操作,提供额外的信息给着色程序,可能需要某些类型的操作。要构建一个简单的单自定义滤镜,甚至可能不需要创建自己的子类。当实例化一个基本操作时,你所需要做的就是提供一个片段着色器和输入的数量:

         let myFilter = BasicOperation(fragmentShaderFile:MyFilterFragmentShaderURL, numberOfInputs:1)

         一个着色器程序是由匹配的顶点着色器和片段着色器组成的,它们被编译并链接到一个程序中。默认情况下,框架根据输入到操作中的图像的数量使用一系列顶点着色器。通常,你所需要做的就是提供用于执行过滤或其他处理的自定义片段着色器。

    func customFilter() {
            
            // 获取文件路径
            let url = URL(fileURLWithPath: Bundle.main.path(forResource: "Custom", ofType: "fsh")!)
            
            var customFilter: BasicOperation
            
            do {
                // 从文件中创建自定义滤镜
                customFilter = try BasicOperation(fragmentShaderFile: url)
            } catch {
                
                print(error)
                return
            }
            
            // 进行滤镜处理
            imageView.image = imageView.image!.filterWithOperation(customFilter)
        }
        /*
        自定义片元着色器代码
         precision highp float;
         varying vec2 TextureCoordsVarying;
         uniform sampler2D Texture;
    
         void main()
         {
             vec2 sampleDivisor = vec2(1.0 / 200.0, 1.0 / 320.0);
             //highp vec4 colorDivisor = vec4(colorDepth);
             
             vec2 samplePos = TextureCoordsVarying - mod(TextureCoordsVarying, sampleDivisor);
             vec4 color = texture2D(Texture, samplePos );
             
             //gl_FragColor = texture2D(Texture, samplePos );
             vec4 colorCyan = vec4(85.0 / 255.0, 1.0, 1.0, 1.0);
             vec4 colorMagenta = vec4(1.0, 85.0 / 255.0, 1.0, 1.0);
             vec4 colorWhite = vec4(1.0, 1.0, 1.0, 1.0);
             vec4 colorBlack = vec4(0.0, 0.0, 0.0, 1.0);
             
             vec4 endColor;
             float blackDistance = distance(color, colorBlack);
             float whiteDistance = distance(color, colorWhite);
             float magentaDistance = distance(color, colorMagenta);
             float cyanDistance = distance(color, colorCyan);
             
             vec4 finalColor;
             
             float colorDistance = min(magentaDistance, cyanDistance);
             colorDistance = min(colorDistance, whiteDistance);
             colorDistance = min(colorDistance, blackDistance);
             
             if (colorDistance == blackDistance) {
                 finalColor = colorBlack;
             } else if (colorDistance == whiteDistance) {
                 finalColor = colorWhite;
             } else if (colorDistance == cyanDistance) {
                 finalColor = colorCyan;
             } else {
                 finalColor = colorMagenta;
             }
             
             gl_FragColor = finalColor;
         }
         */

    六、滤镜操作组

         如果希望将一系列操作分组到单个单元中以便传递,可以创建一个新的OperationGroup实例。OperationGroup提供了一个configureGroup属性,它带有一个闭包,该闭包指定了该组应该如何配置

    unc operationGroup() {
            
            // 创建一个BrightnessAdjustment颜色处理滤镜
            let brightnessAdjustment = BrightnessAdjustment()
            brightnessAdjustment.brightness = 0.2
            
            // 创建一个ExposureAdjustment颜色处理滤镜
            let exposureAdjustment = ExposureAdjustment()
            exposureAdjustment.exposure = 0.5
            
            // 创建一个操作组
            let operationGroup = OperationGroup()
            
            // 给闭包赋值,绑定处理链
            operationGroup.configureGroup{input, output in
                input --> brightnessAdjustment --> exposureAdjustment --> output
            }
            
            // 进行滤镜处理
            imageView.image = imageView.image!.filterWithOperation(operationGroup)
        }

    Core Image是iOS内置的图像处理框架,两者相比各有优点:

         GPUImage 优势

         最低支持 iOS 4.0,iOS 5.0 之后就支持自定义滤镜。

         在低端机型上,GPUImage 有更好的表现。(这个我没用真正的设备对比过,GPUImage 的主页上是这么说的)

         GPUImage 在视频处理上有更好的表现。

         GPUImage 的代码完成公开,实现透明。

         可以根据自己的业务需求,定制更加复杂的管线操作。可定制程度高。

         

         Core Image 优势

         官方框架,使用放心,维护方便。

         支持 CPU 渲染,可以在后台继续处理和保存图片。

         一些滤镜的性能更强劲。例如由 Metal Performance Shaders 支持的模糊滤镜等。

         支持使用 Metal 渲染图像。而 Metal 在 iOS 平台上有更好的表现。

         与 Metal,SpriteKit,SceneKit,Core Animation 等更完美的配合。

         支持图像识别功能。包括人脸识别、条形码识别、文本识别等。

         支持自动增强图像效果,会分析图像的直方图,图像属性,脸部区域,然后通过一组滤镜来改善图像效果。

         支持对原生 RAW 格式图片的处理。

         滤镜链的性能比 GPUImage 高。(没有验证过,GPUImage 的主页上是这么说的)。

         支持对大图进行处理,超过 GPU 纹理限制 (4096 * 4096)的时候,会自动拆分成几个小块处理(Automatic tiling)。GPUImage 当处理超过纹理限制的图像时候,会先做判断,压缩成最大纹理限制的图像,导致图像质量损失。

    本文所有示例代码github地址:https://github.com/duzhaoquan/UseGPUImage2

    参考资料:GPUImage集成与使用:https://www.jianshu.com/p/1bcf38960dbb

    GPUImage2:https://github.com/BradLarson/GPUImage2

  • 相关阅读:
    沈阳集训day2
    ac自动机
    2018沈阳集训day1
    洛谷P1875 佳佳的魔法药水
    洛谷P1941 飞扬的小鸟
    Noip2016day2
    1123: [POI2008]BLO
    1718: [Usaco2006 Jan] Redundant Paths 分离的路径
    P3119 [USACO15JAN]草鉴定Grass Cownoisseur
    [LeetCode] Clone Graph
  • 原文地址:https://www.cnblogs.com/duzhaoquan/p/13265563.html
Copyright © 2011-2022 走看看