不知道我问的这个问题是否正确,但我有两个组件,一个是 CIImage
和一个 UIBezierPath
. 理想情况下,我想创建一个 CGRect
囊括了我 UIBezierPath
;路径内的所有东西都将是 白色径外的一切都将是 黑色. 这样一来,我就可以呈现这个 CGRect
变成某种图像,然后我可以将其用作其他用途的遮罩。
我正在苦苦思索如何做到这一点。注重业绩. 我的测试,如下文所述,使用的杠杆是 UIGraphicsImageRenderer
这对我的需求来说太慢了(我将在相机的采样缓冲区上做这件事)。 因此,我想坚持在 CoreImage
. 这是我的尝试。
// Path
let path = UIBezierPath()
// ... define the path's shape and close it
// My source image
let image = CIImage(cgImage: UIImage(named: "test.jpg")!.cgImage!)
// Renderer
let renderer = UIGraphicsImageRenderer(size: image.extent.size)
// Render path as mask
let img = renderer.image { ctx in
ctx.cgContext.setFillColor(UIColor.black.cgColor)
ctx.cgContext.fill(CGRect(x: 0, y: 0, width: image.extent.size.width, height: image.extent.size.height))
ctx.cgContext.setFillColor(UIColor.white.cgColor)
ctx.cgContext.addPath(path.cgPath)
ctx.cgContext.drawPath(using: .fill)
}
// Put a filter on the image
let imageFiltered = image.applyingFilter("CIPhotoEffectNoir")
// Blend with mask
let maskFilter = CIFilter.blendWithMask()
maskFilter.inputImage = imageFiltered
maskFilter.backgroundImage = image
maskFilter.maskImage = CIImage(cgImage: img.cgImage!)
// Output
if let output = maskFilter.outputImage {
... use CIContext() to render back to CVPixelBuffer for preview on MTKView.
}
总的来说,我们的目标是有一个定义的图像部分(这将不符合传统的形状,如一个正方形或圆形),这将是一个CIFilter过滤,然后合成回原来的。 如果有更好的方法(比如将原始图像进行过滤,裁剪到路径上(让路径外的所有东西都是透明的),然后再进行合成,这可能会有更好的表现。
要注意的是,上面的示例代码会导致崩溃,因为它的 UIGraphicsImageRenderer
不能足够快地渲染遮罩。
到目前为止,你的方法看起来不错。我认为慢的部分是用Core Graphics生成蒙版图像。不幸的是,没有直接的方法可以直接用Core Image做同样的事情(在GPU上)。不过,你可以尝试以下方法。
(根据你之前的问题假设路径总是有一定的形状) 你可以生成一个包含路径的蒙版图像: 曾经 为您选择的某个参考尺寸。确保该路径不会 "触及 "边界,然后,当你想使用它作为遮罩时,使用变换将形状图像移动并缩放到正确的位置,让它的边缘无限延伸(覆盖整个底层图像)。
然后,当你想把它用作蒙版时,使用变换将形状图像移动和缩放到正确的位置,并让它的边缘无限延伸(以覆盖整个底层图像;这就是为什么形状不应该接触边缘)。类似这样。
let pathImage = CIImage(cgImage: img.cgImage!)
// scale path to the size of the area you want to mask
var mask = pathImage.transformed(by: CGAffineTransform(scaleX: scaleX, y: scaleY))
// move path to the place you want to cover
mask = mask.transformed(by: CGAffineTransform(translationX: offsetX, y: offsetY))
// let mask fill the rest of the area
mask = mask.clampedToExtent()
// use mask as maskImage...
你应该能够回收 pathImage
每一帧都是如此,从而避免了Core Graphics和CPU-GPU的同步。