gpt4 book ai didi

ios - 通过 Apple-Metal MPSImageLaplacian 生成 Laplacian 图像

转载 作者:行者123 更新时间:2023-12-01 15:57:40 24 4
gpt4 key购买 nike

我正在尝试使用 Metal 拉普拉斯算子从 rgb CGImage 生成拉普拉斯算子图像。

目前使用的代码:

if let croppedImage = self.cropImage2(image: UIImage(ciImage: image), rect: rect)?.cgImage {

let commandBuffer = self.commandQueue.makeCommandBuffer()!

let laplacian = MPSImageLaplacian(device: self.device)

let textureLoader = MTKTextureLoader(device: self.device)

let options: [MTKTextureLoader.Option : Any]? = nil

let srcTex = try! textureLoader.newTexture(cgImage: croppedImage, options: options)

let desc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: srcTex.pixelFormat, width: srcTex.width, height: srcTex.height, mipmapped: false)

let lapTex = self.device.makeTexture(descriptor: desc)

laplacian.encode(commandBuffer: commandBuffer, sourceTexture: srcTex, destinationTexture: lapTex!)

let output = CIImage(mtlTexture: lapTex!, options: [:])?.cgImage

print("output: \(output?.width)")


print("")
}

我怀疑问题出在 makeTexture 中:

  let lapTex = self.device.makeTexture(descriptor: desc)
  • 尽管 desc 和 srcTex 包含包括宽度和高度在内的有效数据,但调试器中 lapTex 的宽度和高度无效。

看起来顺序或初始化有误,但找不到什么。

有没有人知道哪里出了问题?

谢谢

最佳答案

这里有一些问题。

首先,正如我在评论中提到的,命令缓冲区没有被提交,因此内核工作永远不会被执行。

其次,您需要等待工作完成,然后再尝试回读结果。 (在 macOS 上,您还需要使用 blit 命令编码器来确保纹理的内容被复制回 CPU 可访问的内存。)

第三,使用适当的使用标志创建目标纹理很重要。 .shaderRead 的默认值在这种情况下是不够的,因为 MPS 内核写入纹理。因此,您应该显式设置纹理描述符的 usage 属性([.shaderRead, .shaderWrite].shaderWrite,具体取决于你如何继续使用纹理)。

第四,源纹理的像素格式可能不是可写格式,因此除非您绝对确定它是可写格式,否则请考虑将目标像素格式设置为已知可写格式(如 .rgba8unorm) 而不是假设目标应该与源匹配。这也有助于以后创建 CGImage

最后,不能保证 CIImagecgImage 属性在不是从 CGImage 创建时为非 nil .调用该属性不会(不一定)创建新的支持 CGImage。因此,您需要以某种方式显式创建一个 CGImage

这样做的一种方法是创建一个 Metal 设备支持的 CIContext 并使用它的 createCGImage(_:from:) 方法。虽然这可能有效,但如果目的只是从 MTLTexture 创建一个 CGImage(比方说,为了显示目的),这似乎是多余的。

相反,请考虑使用 getBytes(_:bytesPerRow:from:mipmapLevel:) 方法从纹理中获取字节并将它们加载到 CG 位图上下文中。然后从上下文创建一个 CGImage 就很简单了。

这是一个计算图像的拉普拉斯算子并返回结果图像的函数:

func laplacian(_ image: CGImage) -> CGImage? {
let commandBuffer = self.commandQueue.makeCommandBuffer()!

let laplacian = MPSImageLaplacian(device: self.device)

let textureLoader = MTKTextureLoader(device: self.device)
let options: [MTKTextureLoader.Option : Any]? = nil
let srcTex = try! textureLoader.newTexture(cgImage: image, options: options)

let desc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: srcTex.pixelFormat,
width: srcTex.width,
height: srcTex.height,
mipmapped: false)
desc.pixelFormat = .rgba8Unorm
desc.usage = [.shaderRead, .shaderWrite]

let lapTex = self.device.makeTexture(descriptor: desc)!

laplacian.encode(commandBuffer: commandBuffer, sourceTexture: srcTex, destinationTexture: lapTex)

#if os(macOS)
let blitCommandEncoder = commandBuffer.makeBlitCommandEncoder()!
blitCommandEncoder.synchronize(resource: lapTex)
blitCommandEncoder.endEncoding()
#endif

commandBuffer.commit()
commandBuffer.waitUntilCompleted()

// Note: You may want to use a different color space depending
// on what you're doing with the image
let colorSpace = CGColorSpaceCreateDeviceRGB()
// Note: We skip the last component (A) since the Laplacian of the alpha
// channel of an opaque image is 0 everywhere, and that interacts oddly
// when we treat the result as an RGBA image.
let bitmapInfo = CGImageAlphaInfo.noneSkipLast.rawValue
let bytesPerRow = lapTex.width * 4
let bitmapContext = CGContext(data: nil,
width: lapTex.width,
height: lapTex.height,
bitsPerComponent: 8,
bytesPerRow: bytesPerRow,
space: colorSpace,
bitmapInfo: bitmapInfo)!
lapTex.getBytes(bitmapContext.data!,
bytesPerRow: bytesPerRow,
from: MTLRegionMake2D(0, 0, lapTex.width, lapTex.height),
mipmapLevel: 0)
return bitmapContext.makeImage()
}

关于ios - 通过 Apple-Metal MPSImageLaplacian 生成 Laplacian 图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57166280/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com