iOS Metal how to compute standard deviation in kernel function?

Viewed 133

I have a kernel Metal function, it receives an X,Y grid position of an element. I would like to apply statistical filtering to some elements, and need to know the standard deviation of the value from it's neighbors.

I can implement the function myself inside the kernel function, but am curious if there's a better/more efficient way.

Does iOS Metal provide ready-made math functions that I can use to compute standard deviation of a small number (10 or so) members?

1 Answers

I think you should look into the Metal Performance Shaders framework. There are dozens of image processing filters that may be of use, especially if you are doing a standard filter (e.g. Gaussian blur). For this particular problem, the MPSImageStatisticsMeanAndVariance image filter would probably be your best bet. After encoding the filter work and writing into some output texture (or MPSImage; see the docs linked below for more info), you would then access the variance and simply use the sqrt function on the variance value read in from each thread in MSL (each reading from the output texture). It might look something like

import MetalPerformanceShaders

let device = MTLCreateSystemDefaultDevice()!
let commandQueue = device.makeCommandQueue()!

let sourceTextureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .rgba8Unorm,
                                                                       width: 100, height: 100,
                                                                       mipmapped: false)
let sourceTexture = device.makeTexture(descriptor: sourceTextureDescriptor)!

let destinationTextureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .rgba8Unorm,
                                                                            width: 100, height: 100,
                                                                            mipmapped: false)
let destinationTexture = device.makeTexture(descriptor: destinationTextureDescriptor)!


// Do encoding work
let commandBuffer = commandQueue.makeCommandBuffer()!

// Create the `MPSImageStatisticsMeanAndVariance` filter
let filter = MPSImageStatisticsMeanAndVariance(device: device)

filter.encode(commandBuffer: commandBuffer, sourceTexture: sourceTexture, destinationTexture: destinationTexture)

// Do more work with the destination texture
let customEncoder = commandBuffer.makeComputeCommandEncoder()!
customEncoder.setComputePipelineState(...)
customEncoder.setTexture(destinationTexture, index: 0)
...

More documentation for the MPSImageStatisticsMeanAndVariance and MPS image filters can be found on the Apple developer website here and here respectively. This may not be precisely what you are looking for, but there may be other resources in MPS of use

Related