★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公衆號:山青詠芝(shanqingyongzhi)
➤博客園地址:山青詠芝(https://www.cnblogs.com/strengthen/)
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:http://www.javashuo.com/article/p-dneegqra-mc.html
➤若是連接不是山青詠芝的博客園地址,則多是爬取做者的文章。
➤原文已修改更新!強烈建議點擊原文地址閱讀!支持做者!支持原創!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★html
目錄:[Swift]通天遁地Swiftgit
本文將演示如何給相機添加實時的濾鏡效果。github
首先打開項目的配置文件【Info.plist】,在空白區域點擊鼠標右鍵,彈出右鍵菜單。swift
選擇【Add Row】添加行命令,添加一行配置選項。api
在【Key】鍵輸入框輸入相機的訪問標識:【Application Category】緩存
在【Value】值輸入框輸入當應用程序訪問相機設備時的提示語:微信
【Requires access to the camera】session
在左側的項目導航區,打開視圖控制器的代碼文件【ViewController.swift】框架
如今開始編寫代碼,在應用程序中使用相機設備,並給相機添加實時濾鏡。ide
須要使用真機進行調試。
1 import UIKit 2 //引入須要使用到的類庫,用來添加濾鏡效果。 3 import CoreImage 4 //引入須要使用到的類庫,用來對視頻的採樣進行處理 5 import AVFoundation 6 7 //給當前的類添加協議,使用該協議,能夠得到相機設備中的實時輸出的數據流。 8 class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate{ 9 10 //添加一個濾鏡,它將在代理協議中的方法中被使用, 11 //從而對視頻流實時添加濾鏡效果。 12 var filter: CIFilter! 13 //該屬性用來存儲在協議方法中得到的圖像。 14 //當用戶點擊截圖按鈕時,從而得到當前視頻流中的截圖。 15 var cgImage: CGImage! 16 //該屬性用來展現應用濾鏡後的視頻流截圖 17 var videoLayer: CALayer! 18 //當用戶點擊截圖按鈕時,展現視頻流的截圖 19 var imageView : UIImageView! 20 //使用該屬性得到相機設備的數據流 21 var avCaptureSession: AVCaptureSession! 22 //該屬性能夠將應用濾鏡後的圖像,轉換成CGImage格式的圖像, 23 //並提交給視頻層進行展現。 24 var context: CIContext = { 25 //返回一個指定接口的上下文對象 26 return CIContext(eaglContext: EAGLContext(api: EAGLRenderingAPI.openGLES2)!, options: nil) 27 }() 28 29 //在視圖加載完成的方法中,對部分屬性進行初始化操做。 30 override func viewDidLoad() { 31 super.viewDidLoad() 32 33 //初始化濾鏡對象,該濾鏡可使用圖像顯示覆古、暖色調的藝術風格。 34 filter = CIFilter(name: "CIPhotoEffectTransfer") 35 //調用生成界面的方法,對程序的界面進行初始化操做。 36 buildUI() 37 //對用於捕捉視頻流的對象進行初始化操做 38 buildSession() 39 } 40 41 //添加一個方法,用來建立應用程序的界面 42 func buildUI() 43 { 44 //對視圖層進行初始化操做 45 videoLayer = CALayer() 46 //設置視圖層的錨點點位置在原點 47 videoLayer.anchorPoint = CGPoint.zero 48 //保持視圖層的尺寸和騙你幹嗎的尺寸相同 49 videoLayer.bounds = view.bounds 50 //將視圖層添加到根視圖的層中 51 self.view.layer.insertSublayer(videoLayer, at: 0) 52 53 //建立一個圖像視圖對象,該圖像視圖將用來展現從視頻流中, 54 //得到應用濾鏡後的截圖,它的尺寸也跟屏幕尺寸相同。 55 imageView = UIImageView(frame: view.bounds) 56 //將圖像視圖添加到根視圖中。 57 self.view.addSubview(imageView) 58 59 //添加一個按鈕,當用戶點擊該按鈕時,得到視頻流中的應用濾鏡後的截圖。 60 let button = UIButton(frame: CGRect(x: 0, y: 420, width: 320, height: 60)) 61 //設置按鈕在正常狀態下的標題文字 62 button.setTitle("Capture", for: .normal) 63 //同時設置按鈕的背景顏色爲黑色。 64 button.backgroundColor = UIColor.black 65 //給按鈕控件綁定點擊事件 66 button.addTarget(self, action: #selector(ViewController.captureScreen), for: .touchUpInside) 67 //將按鈕添加到根視圖 68 self.view.addSubview(button) 69 } 70 71 //添加一個方法,用來響應按鈕的點擊事件 72 func buildSession() 73 { 74 //對得到數據流的對象進行初始化操做 75 avCaptureSession = AVCaptureSession() 76 //經過調用對象的開始配置方法,開始對各類參數進行配置。 77 avCaptureSession.beginConfiguration() 78 //設置得到質量較高的視頻流和音頻流。 79 avCaptureSession.sessionPreset = AVCaptureSession.Preset.high 80 81 //得到當前的相機設備 82 let captureDevice = AVCaptureDevice.default(for: .video) 83 //初始化一個視頻捕捉設備輸入對象 84 let deviceInput = try! AVCaptureDeviceInput(device: captureDevice!) 85 //當相機設備處於可用狀態時, 86 if avCaptureSession.canAddInput(deviceInput) 87 { 88 //設置視頻流的輸入設備爲相機設備 89 avCaptureSession.addInput(deviceInput) 90 } 91 92 //得到視頻捕捉數據輸出對象, 93 //該對象用於從視頻流中,獲取未經壓縮的幀 94 let dataOutput = AVCaptureVideoDataOutput() 95 //設置視頻幀的格式爲32位的RGBA格式 96 dataOutput.videoSettings = ([kCVPixelBufferPixelFormatTypeKey as AnyHashable : Int(kCVPixelFormatType_32BGRA)] as! [String : Any]) 97 //設置自動丟棄因爲視頻延遲等因素,而形成延遲等的視頻幀。 98 dataOutput.alwaysDiscardsLateVideoFrames = true 99 100 //將數據輸出對象,添加到視頻捕捉對象的數據輸出端口 101 if avCaptureSession.canAddOutput(dataOutput) 102 { 103 avCaptureSession.addOutput(dataOutput) 104 } 105 106 //建立一個串行的任務隊列 107 let queue = DispatchQueue(label: "VideoQueue", attributes: .concurrent) 108 //設置數據輸出對象的採樣換成代理,位當前的視圖控制器對象, 109 //並使用穿好的任務隊列 110 dataOutput.setSampleBufferDelegate(self, queue: queue) 111 112 //經過調用視頻捕捉對象的提交配置方法,結束對各類參數的配置。 113 avCaptureSession.commitConfiguration() 114 //調用開始運行方法,開始使用相機設備捕捉視頻。 115 avCaptureSession.startRunning() 116 } 117 118 //實現協議中的代理方法,以實時檢測視頻流, 119 //並給視頻流實時添加濾鏡。 120 func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) 121 { 122 //添加一個自動釋放池 123 autoreleasepool 124 { 125 //將採樣的流數據,轉換成圖像緩存對象 126 let imgBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! 127 //將圖像緩存對象進行格式的轉換, 128 //以便給圖像添加濾鏡。 129 var ciImage = CIImage(cvPixelBuffer: imgBuffer) 130 131 //將數據流轉換格式後,就能夠應用框架中的衆多濾鏡。 132 //首先設置濾鏡的輸入圖像,爲流數據轉換格式後的對象。 133 self.filter.setValue(ciImage, forKey: kCIInputImageKey) 134 //得到應用濾鏡後所輸出的圖像。 135 ciImage = self.filter.outputImage! 136 137 //得到當前設備的朝向 138 let orientation = UIDevice.current.orientation 139 //由於兩種座標系統的原點不一樣,因此須要對視頻流中的應用濾鏡後的截圖,進行旋轉操做。 140 if orientation == UIDeviceOrientation.portrait 141 { 142 ciImage = ciImage.transformed(by: CGAffineTransform(rotationAngle: CGFloat(Double.pi / -2.0))) 143 } 144 //處理設備在豎立狀態,主鍵在上的狀況。 145 else if orientation == UIDeviceOrientation.portraitUpsideDown 146 { 147 ciImage = ciImage.transformed(by: CGAffineTransform(rotationAngle: CGFloat(Double.pi / 2.0))) 148 } 149 //處理設備在橫向狀態,主鍵在右的狀況。 150 else if (orientation == UIDeviceOrientation.landscapeRight) 151 { 152 ciImage = ciImage.transformed(by: CGAffineTransform(rotationAngle: CGFloat(Double.pi))) 153 } 154 //將調整方向後的圖像,賦予應用的屬性,供按鈕控件的點擊事件使用。 155 self.cgImage = self.context.createCGImage(ciImage, from: ciImage.extent) 156 157 //返回主線程,在主線程中刷新界面上的內容, 158 DispatchQueue.main.sync(execute: 159 { 160 //將視頻層的內容屬性,設置爲應用濾鏡後的圖像。 161 self.videoLayer.contents = self.cgImage 162 }) 163 } 164 } 165 166 //添加一個方法,用來響應按鈕的點擊事件 167 @objc func captureScreen(_ sender: UIButton) 168 { 169 //當按鈕被點擊時,首先停止視頻流的傳遞。 170 avCaptureSession.stopRunning() 171 //將用來顯示時流的圖層,從父層中移除。 172 videoLayer.removeFromSuperlayer() 173 //隱藏當前的按鈕控件 174 sender.isHidden = true 175 176 //設置圖像視圖的內容模式,圖片按必定比例縮放, 177 //直到在長度或者寬度達到圖像視圖的邊界爲止。 178 imageView.contentMode = .scaleAspectFit 179 //將應用濾鏡後的截圖,賦予當前根視圖中的圖像視圖, 180 //在屏幕上顯示來自視頻流的截圖。 181 imageView.image = UIImage(cgImage: self.cgImage) 182 } 183 184 override func didReceiveMemoryWarning() { 185 super.didReceiveMemoryWarning() 186 // Dispose of any resources that can be recreated. 187 } 188 }