将 MPSImageConvolution 内核与 Metal 计算着色器一起使用
Using MPSImageConvolution kernel with Metal compute shaders
我正在使用位于此处 https://github.com/FlexMonkey/MetalVideoCapture 的 MetalVideoCapture 示例。我在我的版本中唯一改变的是使用具有内核值的 MPSImageConvolution(而不是 MPSImageGaussianBlur):
[-2.0, -1.0, 0.0,
-1.0, 1.0, 1.0,
0.0, 1.0, 2.0]
使用上面的值未能以任何可见的方式改变输出。但是边缘增强内核例如
[0.0, -1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 0.0]
有效,请注意仅按列主要顺序;它在行优先顺序中不起作用,即使那是 MPSImageConvolution 所期望的。我真的被这个难住了。我不知道是否有明显的原因表明卷积核无法在计算管道中工作(仅在渲染管道中),但我在网上找不到任何信息。
我还修改了代码库以将内核应用于静态图像而不是实时视频源;然而,这产生了相同的结果。
我还想指出,我在示例项目的留言板上发布了相同的问题 (https://github.com/FlexMonkey/MetalVideoCapture/issues/1#issuecomment-217609500)。这个例子的作者和我一样被难住了,这让我相信这是某种错误或我的概念知识上的差距,为什么这甚至不应该工作。
我有一个解决方法,那就是避免使用就地纹理。试试这个:创建一个单独的目标纹理:
let descriptor = MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(
drawable.texture.pixelFormat,
width: drawable.texture.width,
height: drawable.texture.height,
mipmapped: false)
let destination: MTLTexture = device!.newTextureWithDescriptor(descriptor)
让 YCbCrColorConversion
着色器指向目的地:
commandEncoder.setTexture(destination, atIndex: 2) // out texture
...然后使用使用目的地的替代 encodeToCommandBuffer
:
encodeToCommandBuffer(commandBuffer, sourceTexture: destination, destinationTexture: drawable.texture)
可以删除这些东西:
// let inPlaceTexture = UnsafeMutablePointer<MTLTexture?>.alloc(1)
// inPlaceTexture.initialize(drawable.texture)
西蒙
感谢 Warren!
一般来说,除非将卷积滤波器实现为多通道滤波器,否则任何卷积滤波器都无法正常工作。由于您正在查看相邻像素,因此在一个像素中写出结果会更改其旁边像素的输入,从而导致错误。像这样的小卷积通常在 MPS 中实现为单通滤波器。您应该使用允许框架根据需要换出目标纹理的就地 MPS 编码方法。另一种节省内存的方法是使用 MPSTemporaryImages(iOS 10 及更高版本)。
MPSImageConvolution 应该正在检测使用模式故障并断言。确保在 Xcode 中打开了 Metal 调试层。如果仍然没有断言,则未能检测到问题是值得的。 http://bugreporter.apple.com
我正在使用位于此处 https://github.com/FlexMonkey/MetalVideoCapture 的 MetalVideoCapture 示例。我在我的版本中唯一改变的是使用具有内核值的 MPSImageConvolution(而不是 MPSImageGaussianBlur):
[-2.0, -1.0, 0.0,
-1.0, 1.0, 1.0,
0.0, 1.0, 2.0]
使用上面的值未能以任何可见的方式改变输出。但是边缘增强内核例如
[0.0, -1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 0.0]
有效,请注意仅按列主要顺序;它在行优先顺序中不起作用,即使那是 MPSImageConvolution 所期望的。我真的被这个难住了。我不知道是否有明显的原因表明卷积核无法在计算管道中工作(仅在渲染管道中),但我在网上找不到任何信息。
我还修改了代码库以将内核应用于静态图像而不是实时视频源;然而,这产生了相同的结果。
我还想指出,我在示例项目的留言板上发布了相同的问题 (https://github.com/FlexMonkey/MetalVideoCapture/issues/1#issuecomment-217609500)。这个例子的作者和我一样被难住了,这让我相信这是某种错误或我的概念知识上的差距,为什么这甚至不应该工作。
我有一个解决方法,那就是避免使用就地纹理。试试这个:创建一个单独的目标纹理:
let descriptor = MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(
drawable.texture.pixelFormat,
width: drawable.texture.width,
height: drawable.texture.height,
mipmapped: false)
let destination: MTLTexture = device!.newTextureWithDescriptor(descriptor)
让 YCbCrColorConversion
着色器指向目的地:
commandEncoder.setTexture(destination, atIndex: 2) // out texture
...然后使用使用目的地的替代 encodeToCommandBuffer
:
encodeToCommandBuffer(commandBuffer, sourceTexture: destination, destinationTexture: drawable.texture)
可以删除这些东西:
// let inPlaceTexture = UnsafeMutablePointer<MTLTexture?>.alloc(1)
// inPlaceTexture.initialize(drawable.texture)
西蒙
感谢 Warren!
一般来说,除非将卷积滤波器实现为多通道滤波器,否则任何卷积滤波器都无法正常工作。由于您正在查看相邻像素,因此在一个像素中写出结果会更改其旁边像素的输入,从而导致错误。像这样的小卷积通常在 MPS 中实现为单通滤波器。您应该使用允许框架根据需要换出目标纹理的就地 MPS 编码方法。另一种节省内存的方法是使用 MPSTemporaryImages(iOS 10 及更高版本)。
MPSImageConvolution 应该正在检测使用模式故障并断言。确保在 Xcode 中打开了 Metal 调试层。如果仍然没有断言,则未能检测到问题是值得的。 http://bugreporter.apple.com