【问题标题】:How to apply filter to Video real-time using Swift如何使用 Swift 对视频实时应用过滤器
【发布时间】:2015-11-29 11:13:24
【问题描述】:

是否可以将过滤器应用于 AVLayer 并将其添加到 view 作为 addSublayer?我想使用 Swift 更改颜色并为来自相机的视频添加一些噪点,但我不知道如何操作。

我想,可以像这样添加 filterLayerpreviewLayer

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

这也许可以使用我的自定义过滤器创建视频,但我认为使用 AVComposition

可以更有效地做到这一点

所以我需要知道的:

  1. 将滤镜实时应用于相机视频输出的最简单方法是什么?
  2. 是否可以合并 AVCaptureVideoPreviewLayerCALayer

感谢您的每一个建议..

【问题讨论】:

  • 您没有提供太多关于您正在做什么的信息,但是可以使用GLKView 而不是AVCapturePreviewLayer 实时编辑视频源,并将过滤器应用于每个帧captureOutput(capptureOutput: didOutputToSampleBuffer: fromConnection connection:).
  • 谢谢! GLKView 对我来说看起来更好。 :) 很简单:我需要对实时视频帧应用过滤器,并可以选择将其保存到文件中。我正在做某种带滤镜的摄像机。

标签: ios swift avfoundation calayer video-capture


【解决方案1】:

还有另一种选择,使用 AVCaptureSession 创建 CIImage 实例,您可以在其中应用 CIFilters(其中有负载,从模糊到颜色校正到 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,我们可以在视频输出上设置sample buffer delegate:

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

然后将视频输出附加到捕获会话:

 captureSession.addOutput(videoOutput)

...最后,我们开始捕获会话:

captureSession.startRunning()

因为我们已经设置了委托,所以每次捕获帧都会调用 captureOutput。 captureOutput 传递一个 CMSampleBuffer 类型的样本缓冲区,只需两行代码即可将该数据转换为 CIImage 以供 Core Image 处理:

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
}

我有source code for this project available in my GitHub repo here

【讨论】:

  • 非常感谢!你的文章和回购真的帮助了我。但是当我尝试创建 dispatch_queue Cannot invoke 'setSampleBufferDelegate' with an argument list of type '(ViewController, queue: dispatch_queue_attr_t!)' 时出现错误
  • 感谢您的客气话!看看这个类:github.com/FlexMonkey/ParticleCam/blob/master/ParticleCam/…
  • 哈,我的错...我使用的是 iOS 8.4.1 所以问题解决了。再次感谢您。
  • 我可以用这种效果保存视频吗?
  • @NinjaDevelopers 你可以,但你必须将缓冲区输出写入文件,我认为你可以使用AVAssetWriterInputPixelBufferAdaptor 执行此操作,请参阅stackoverflow.com/questions/3741323/…
【解决方案2】:

如果您使用的是AVPlayerViewController,则可以设置viewlayer 的compositingFilter 属性:

  playerController.view.layer.compositingFilter = "multiplyBlendMode"

See here for the compositing filter options you can use。例如“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 项目中的 Build Phases > Copy Bundle Resources。或者在导入文件时选中“添加到目标”框。

【讨论】:

    猜你喜欢
    • 2017-03-20
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    • 2017-01-07
    • 2023-04-10
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多