CIImage像素的RGB值

4
我想访问从实时ARFrame获取的CVPixelBuffer特定区域的平均颜色值。我设法裁剪图像,使用滤镜计算平均颜色,并在转换为CGImage后从像素中获取值,但不幸的是,这影响了我的应用程序性能(FPS降至30fps以下)。我认为造成这种情况的原因是使用CGContext。是否有一种方法可以在不将CIImage转换为CGImage的情况下访问颜色? 这是我目前正在使用的代码:
func fun() {
  let croppVector = CIVector(cgRect: inputImageRect)

  guard let filter = CIFilter(
    name: "CIAreaAverage",
    parameters: [kCIInputImageKey: image, kCIInputExtentKey: croppVector]
  ),
    let outputImage = filter.outputImage,
    let cgImage = context.createCGImage(
      outputImage,
      from: CGRect(x: 0, y: 0, width: 1, height: 1)
    ),
    let dataProvider = cgImage.dataProvider,
    let data = CFDataGetBytePtr(dataProvider.data) else { return nil }

  let color = UIColor(
    red: CGFloat(data[0]) / 255,
    green: CGFloat(data[1]) / 255,
    blue: CGFloat(data[2]) / 255,
    alpha: CGFloat(data[3]) / 255
  )
}
1个回答

1

我认为在这里你能做的不多——像这样的缩减操作是昂贵的。

你可以尝试一些方法:

  • 通过将.workingColorSpace.outputColorSpace选项设置为NSNull(),设置你的CIContext不执行任何颜色管理。
  • 直接渲染到内存而不是通过CGImage。上下文有一个方法render(_ image: CIImage, toBitmap data: UnsafeMutableRawPointer, rowBytes: Int, bounds: CGRect, format: CIFormat, colorSpace: CGColorSpace?)可以用于此操作。在此处也将颜色空间传递为nil。你应该能够只将指向simd_uchar4变量的“指针”作为data传递过去。在这种情况下,rowBytes将为4,格式将为.BGRA8
  • 在计算平均值之前,你也可以尝试缩小图像(这已经是一个缩减操作)。虽然不会得到完全相同的值,但是可以得到一个公平的近似值——而且可能更快。

感谢Frank的回答。不幸的是,它并没有帮助太多(也许稍微提高了性能),但我仍然遇到帧率降至18fps的情况。我使用Metal Frame Debugger捕获了帧,并得到了一个问题:“编码器:'mainMetalEntryPoint'有未使用的纹理:'com.apple.CoreImage'问题”,涉及到我从中计算平均值的裁剪图像。您知道从CVPixelBuffer获取像素RGB值的其他方法吗?我的目标是将其值与参考RGB颜色进行比较。 - RealUglyDuck
您可以使用CVPixelBufferGetBaseAddress访问原始数据。关于性能:您是否尝试在方案设置中禁用“GPU帧捕获”和“Metal API验证”?这些会严重干扰任何性能基准测试。 - Frank Rupprecht
@FrankSchlegel 那么将输入和输出转换为sRGB,然后再转回去,这就是我们所说的颜色管理吗? - Deepak Sharma
1
@DeepakSharma 对,也被苹果称为ColorSync。 - Frank Rupprecht
好的,我会提出一个新问题并发布。 - Deepak Sharma
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接