- This topic has 2개 답변, 2명 참여, and was last updated 4 years, 6 months 전에 by .
-
-
-
CIContext 를 사용해야 합니다. 코어 이미지 모든 프로세싱이 일어나는 부분으로 CIFilter를 사용시에 반드시 필요합니다.
-
첫 번째 인자에는 AVCaptureOutput 하위 클래스가 들어옵니다. 여기서는 아마 AVCaptureVideoDataOutput 가 들어올 거라고 생각됩니다. 그리고 AVCaptureOutput 은 최상위 추상 클래스입니다. 간단히 말하자면 AVCaptureSession의 addOutput에 인자가 될 수 있는 클래스들의 부모 클래스(AVCaptureVideoDataOutput, AVCapturePhotoOutput 등)입니다.
-
두 번째 인자는 CMSampleBuffer 클래스의 인스턴스 입니다. 여기서 CM은 apple의 CoreMedia framework를 말합니다. CMSampleBuffer는 변경할 수 없는 CMSampleBufferRef 객체에 대한 참조입니다. CMSampleBuffer 는 압축되어 있거나 압축되어 있지 않은 특정 미디어 타입(audio, video 등)의 samples 를 가지고 있습니다.
-
세 번째 인자로는 AVCaptureConnection 클래스 타입이 변수로 들어옵니다. AVCaptureSession에 있는 특정한 input 과 output 사이의 연결이라고 합니다. 다만
addInput(_:)
과addOutput(_:)
을 사용했다면 자동으로 모든 input 과 output에 연결이 생성된다고 합니다. -
두 번째인자 sampleBuffer 로부터
CMSampleBufferGetImageBuffer(_:)
를 이용해서 CVImageBuffer를 받아옵니다. -
CIFilter 를 이용해서 이미 구현된 필터를 불러옵니다. 이미 구현된 filter 들은
Core Image Filter Reference 에서 확인할 수 있습니다.
-
이제는 CIFilter를 통과할 CIImage가 필요합니다. CIImage 클래스는 Core Image filter 들을 거칠 또는 생산된 image를 말합니다. 상당히 많은 init이 존재하는 데
init(cvImageBuffer:) 를 이용합니다. -
CIComicEffect filter를 통과한 이미지를 얻기 위해서 CIContext의
createCGImage(_:from:)
함수를 이용해서 CGImage를 생성합니다. 첫 번째 인자는 filter를 통과할 CIImage 객체이고, 두 번째 인자는 CGImage가 그려질 영역으로 CGRect 객체 입니다.func captureOutput(_:didOutput:from:)
부분의 코드입니다.
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { guard let videoPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer), let _ = CMSampleBufferGetFormatDescription(sampleBuffer) else {return} let comicEffect = CIFilter(name: "CIPhotoEffectMono") let cameraImage = CIImage(cvImageBuffer: videoPixelBuffer) // setValue 부분은 잘 이해가 되지 않습니다. comicEffect!.setValue(cameraImage, forKey: kCIInputImageKey) let cgImage = self.context.createCGImage(comicEffect!.outputImage!, from: cameraImage.extent)! DispatchQueue.main.async { let filteredImage = UIImage(cgImage: cgImage) self.imageView.image = filteredImage } }
-
func captureOutput(_:didOutput:from)
에서 commicEffect!.setValue 부분의 의미가 무엇인지 궁금합니다. -
또
func captureOutput(_:didOutput:from)
에서 DispatchQueue 코드의 의미는 UI 변경에 관한 코드라서 main thread 에서 실행해서 해야하는 걸로 생각하고 있는 데 맞게 생각하는 건지 궁금합니다.
func captureOutput(:didOutput:from:) 구현 부분 설명
참조 링크
이해 되지 않는 부분
전체 코드입니다.
import UIKit import AVFoundation // CIFilter(CIComicFilter) 실시간 적용하기 class ViewController: UIViewController{ @IBOutlet weak var imageView: UIImageView! var captureSession: AVCaptureSession? var backCamera: AVCaptureDevice? var frontCamera: AVCaptureDevice? var captureInput: AVCaptureInput? var photoOutput: AVCapturePhotoOutput? var photoSetting: AVCapturePhotoSettings? var videoOutput: AVCaptureVideoDataOutput? var orientation: AVCaptureVideoOrientation = .portrait let context = CIContext() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) self.setAuthorization() self.setSession() self.setDevice() self.setInputOutput() self.imageView.transform = self.imageView.transform.rotated(by: .pi / 2) } func setAuthorization() { let status = AVCaptureDevice.authorizationStatus(for: .video) switch status { case .authorized: print("Get Authorization Success") case .denied: AVCaptureDevice.requestAccess(for: .video) { access in if access { DispatchQueue.main.async { self.setInputOutput() } } } default: print("Get Authorization failed") } } func setSession(){ self.captureSession = AVCaptureSession() self.captureSession?.sessionPreset = .photo } func setDevice(){ self.backCamera = AVCaptureDevice.default(for: .video) // or using default(_:for:position:) // self.backCamera = AVCaptureDevice.default(.builtInDualWideCamera, for: .video, position: .back) } func setInputOutput(){ guard let captureDevice = self.backCamera else {return} do{ // Set photoInput self.captureInput = try AVCaptureDeviceInput(device: captureDevice) // Set photoOutput self.photoOutput = AVCapturePhotoOutput() self.photoOutput?.isHighResolutionCaptureEnabled = true // Set videoDataOutput self.videoOutput = AVCaptureVideoDataOutput() self.videoOutput?.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String : Int(kCVPixelFormatType_32BGRA)] self.videoOutput?.setSampleBufferDelegate(self, queue: DispatchQueue.main) guard let photoinput = self.captureInput else {return} guard let photoOutput = self.photoOutput else {return} guard let videoOutput = self.videoOutput else {return} self.captureSession?.addInput(photoinput) self.captureSession?.addOutput(photoOutput) self.captureSession?.addOutput(videoOutput) self.captureSession?.startRunning() }catch{ print(error.localizedDescription) } } } extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate { func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { guard let videoPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer), let _ = CMSampleBufferGetFormatDescription(sampleBuffer) else {return} let comicEffect = CIFilter(name: "CIComicEffect") let cameraImage = CIImage(cvImageBuffer: videoPixelBuffer) comicEffect!.setValue(cameraImage, forKey: kCIInputImageKey) let cgImage = self.context.createCGImage(comicEffect!.outputImage!, from: cameraImage.extent)! DispatchQueue.main.async { let filteredImage = UIImage(cgImage: cgImage) self.imageView.image = filteredImage } } } -