在Swift的Metalkit库中能否获取或计算图像像素的x、y索引?
结论
你当前Metal代码里通过[[thread_position_in_grid]]拿到的id变量,就是你需要的对应像素的X、Y坐标,和你原CPU遍历逻辑里的x、y完全等价,可以直接使用。
前提:网格尺寸和纹理尺寸对齐
你只需要在Swift侧配置Metal管线调用时,保证计算网格的尺寸和输入/输出纹理的宽高完全匹配即可,示例配置代码如下:
// 假设你已经把CGImage转成了Metal纹理,宽高分别为textureWidth、textureHeight let gridSize = MTLSize(width: textureWidth, height: textureHeight, depth: 1) // 线程组大小根据GPU核心配置,一般用16x16或者32x32即可 let threadGroupSize = MTLSize(width: 16, height: 16, depth: 1) // 调用compute encoder派发任务 computeEncoder.dispatchThreads(gridSize, threadsPerThreadgroup: threadGroupSize)
如果你的设备需要兼容iOS 11以下、macOS 10.13以下系统,不支持dispatchThreads接口,可以用下面的兼容写法计算对齐后的线程组数量:
let threadGroupCount = MTLSize( width: (textureWidth + threadGroupSize.width - 1) / threadGroupSize.width, height: (textureHeight + threadGroupSize.height - 1) / threadGroupSize.height, depth: 1 ) computeEncoder.dispatchThreadgroups(threadGroupCount, threadsPerThreadgroup: threadGroupSize)
这种情况下kernel内要先判断id是否超出纹理尺寸,避免越界访问,补全后的kernel代码参考:
kernel void clearPixel ( texture2d<float, access::read> inTexture [[texture(0)]], texture2d<float, access::write> outTexture [[texture(1)]], uint2 id [[thread_position_in_grid]] ) { // 先判断坐标是否在纹理范围内,避免越界 if (id.x >= inTexture.get_width() || id.y >= inTexture.get_height()) { return; } // 直接用id.x、id.y和目标坐标判断即可,和原CPU逻辑完全一致 if (id.x == 20 && id.y == 300) { // 写入透明色,RGBA格式下透明值为[0,0,0,0] outTexture.write(float4(0, 0, 0, 0), id); } else { // 其余像素直接复制原图内容 outTexture.write(inTexture.read(id), id); } }
坐标一致性说明
Metal纹理的默认原点为左上角,和你原CGImage遍历逻辑中y从0到cgImage.height的坐标体系完全对齐,不需要额外做坐标转换。
内容的提问来源于stack exchange,提问作者Paul Mayer
相关产品推荐
相关产品推荐

