首页 > 解决方案 > 使用 Metal 有效计算 UIImage/CIImage 中有多少透明像素

问题描述

CIImage我们可以计算/中存在多少透明像素的最快方法是什么UIImage

例如:

在此处输入图像描述

如果我们谈论效率,我的第一个想法是使用Metal Kernelusing any CIColorKernelor so,但我不明白如何使用它来输出“count”。

还有我想到的其他想法:

  1. 使用某种平均颜色来计算它,“越红”越填充像素?也许某种线性计算取决于图像大小(使用CIAreaAverage CIFilter
  2. 一个一个地计算像素并检查RGB值?
  3. 使用 Metal 并行功能,类似于这篇文章:Counting coloured pixels on the GPU - Theory ?
  4. 缩小图像然后计数?或者上面建议的所有其他过程是否只是按比例缩放而不是版本,并且它的倍数取决于计算后的缩小比例?

实现此计数的最快方法是什么?

标签: iosswiftmetalcore-imagemetal-performance-shaders

解决方案


要回答你的问题如何做金属,你会使用device atomic_int.

本质上,您创建一个 IntMTLBuffer并将其传递给您的内核并使用atomic_fetch_add_explicit.

创建缓冲区一次:

var bristleCounter = 0
counterBuffer = device.makeBuffer(bytes: &bristleCounter, length: MemoryLayout<Int>.size, options: [.storageModeShared])

将计数器重置为 0 并绑定计数器缓冲区:

var z = 0
counterBuffer.contents().copyMemory(from: &z, byteCount: MemoryLayout<Int>.size)
kernelEncoder.setBuffer(counterBuffer, offset: 0, index: 0)

核心:

kernel void myKernel (device atomic_int *counter [[buffer(0)]]) {}

内核中的增量计数器(并获取值):

int newCounterValue = atomic_fetch_add_explicit(counter, 1, memory_order_relaxed);

获取 CPU 端的计数器:

kernelEncoder.endEncoding()
kernelBuffer.commit()
kernelBuffer.waitUntilCompleted()
    
//Counter from kernel now in counterBuffer
let bufPointer = counterBuffer.contents().load(as: Int.self)
print("Counter: \(bufPointer)")

推荐阅读