web-dev-qa-db-ja.com

Swift)を使用してリアルタイムでビデオにフィルターを適用する方法

フィルタをAVLayerに適用し、それをview as addSublayerとして追加することは可能ですか? Swiftを使用して、カメラからのビデオに色を変更し、ノイズを追加したいのですが、方法がわかりません。

filterLayerpreviewLayerを次のように追加することは可能だと思いました。

self.view.layer.addSublayer(previewLayer)
self.view.layer.addSublayer(filterLayer)

これは私のカスタムフィルターでビデオを作成できるかもしれませんが、それをより効果的に使用することは可能だと思いますAVComposition

だから私が知る必要があること:

  1. カメラのビデオ出力にリアルタイムでフィルターを適用する最も簡単な方法は何ですか?
  2. AVCaptureVideoPreviewLayerCALayerをマージすることは可能ですか?

すべての提案をありがとう..

10
David Sýkora

別の方法として、AVCaptureSessionを使用して、CIFilterを適用できるCIImageのインスタンスを作成します(ぼかしから色補正、VFXまでの負荷があります)。

ComicBookエフェクトを使用した例を次に示します。一言で言えば、AVCaptureSessionを作成します。

let captureSession = AVCaptureSession()
captureSession.sessionPreset = AVCaptureSessionPresetPhoto

カメラを表すAVCaptureDeviceを作成します。ここでは、バックカメラを設定しています。

let backCamera = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)

次に、デバイスの具体的な実装を作成し、それをセッションにアタッチします。 Swift 2)では、AVCaptureDeviceInputをインスタンス化するとエラーがスローされる可能性があるため、次のことをキャッチする必要があります。

 do
{
    let input = try AVCaptureDeviceInput(device: backCamera)

    captureSession.addInput(input)
}
catch
{
    print("can't access camera")
    return
}

さて、ここに小さな「落とし穴」があります。実際にはAVCaptureVideoPreviewLayerを使用していませんが、サンプルデリゲートを機能させる必要があるため、次のいずれかを作成します。

// although we don't use this, it's required to get captureOutput invoked
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)

view.layer.addSublayer(previewLayer)

次に、ビデオフィードにアクセスするために使用するビデオ出力AVCaptureVideoDataOutputを作成します。

let videoOutput = AVCaptureVideoDataOutput()

自己がAVCaptureVideoDataOutputSampleBufferDelegateを実装していることを確認して、ビデオ出力にサンプルバッファーデリゲートを設定できます。

 videoOutput.setSampleBufferDelegate(self, 
    queue: dispatch_queue_create("sample buffer delegate", DISPATCH_QUEUE_SERIAL))

次に、ビデオ出力がキャプチャセッションに添付されます。

 captureSession.addOutput(videoOutput)

...そして最後に、キャプチャセッションを開始します。

captureSession.startRunning()

デリゲートを設定したため、captureOutputはフレームキャプチャごとに呼び出されます。 CaptureOutputにはCMSampleBufferタイプのサンプルバッファーが渡され、コアイメージが処理するCIImageにそのデータを変換するのに2行のコードが必要です。

let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
let cameraImage = CIImage(CVPixelBuffer: pixelBuffer!)

...そしてその画像データはコミックブックエフェクトに渡され、コミックブックエフェクトは画像ビューにデータを入力するために使用されます。

let comicEffect = CIFilter(name: "CIComicEffect")

comicEffect!.setValue(cameraImage, forKey: kCIInputImageKey)

let filteredImage = UIImage(CIImage: comicEffect!.valueForKey(kCIOutputImageKey) as! CIImage!)

dispatch_async(dispatch_get_main_queue())
{
    self.imageView.image = filteredImage
}

このプロジェクトのソースコードはGitHubリポジトリで入手できます です。

23
Simon Gladman

AVPlayerViewControllerを使用している場合は、viewlayerのc​​ompositingFilterプロパティを設定できます。

_  playerController.view.layer.compositingFilter = "multiplyBlendMode"
_

使用できる合成フィルターオプションについては、こちらを参照してください 。例えば「multiplyBlendMode」、「screenBlendMode」など。

UIViewControllerでこれを行う例:

_class ViewController : UIViewController{
  override func viewDidLoad() {
    //load a movie called my_movie.mp4 that's in your xcode project
    let path = Bundle.main.path(forResource: "my_movie", ofType:"mp4")
    let player = AVPlayer(url: URL(fileURLWithPath: path!))

    //make a movie player and set the filter
    let playerController = AVPlayerViewController()
    playerController.player = player
    playerController.view.layer.compositingFilter = "multiplyBlendMode"

    //add the player view controller to this view controller
    self.addChild(playerController)
    view.addSubview(playerController.view)
    playerController.didMove(toParent: self)

    //play the movie
    player.play()
  }
}
_

let path = Bundle.main.path(forResource: "my_movie", ofType:"mp4")の場合は、必ず.mp4ファイルを[ビルドフェーズ]> [Xcodeプロジェクトのバンドルリソースのコピー]に追加してください。または、ファイルをインポートするときに[ターゲットに追加]チェックボックスをオンにします。

0
spnkr