将 UIBezierPath 变成掩码?



不确定我是否正确地问了这个问题,但我有两个组成部分; 一个CIImage和一个UIBezierPath。 理想情况下,我想创建一个封装我的UIBezierPathCGRect;路径内的所有内容都将是白色的,路径外的所有内容都将是黑色的。 这样,我就可以将此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无法足够快地呈现掩码。

到目前为止,你的方法看起来不错。我认为缓慢的部分是使用核心图形生成遮罩图像。不幸的是,没有直接的方法可以直接对核心映像(在 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,从而避免核心图形和 CPU-GPU 同步。

最新更新