如何裁剪/调整金属中的纹理阵列

问题描述:

假设我有一个N通道MPSImage或基于MTLTexture的纹理阵列。如何裁剪/调整金属中的纹理阵列

如何裁剪一个区域,复制所有N个通道,但改变“像素大小”?

我只想解决农作物的情况,因为调整大小的情况涉及到重采样,并且稍微复杂一些。让我知道你是否真的需要这个。

让我们假设您的源MPSImage是128x128像素的12个特征通道(3切片)图像,您的目标图像是64x64像素的8个特征通道图像(2个切片),并且您要复制源的最后两个片的右下64x64区域放入目的地。

没有API,我所知道的,它允许你从/一次复制到一个数组质感的多个片,所以你需要发出多个blit的命令,以覆盖所有的切片:

let sourceRegion = MTLRegionMake3D(64, 64, 0, 64, 64, 1) 
let destOrigin = MTLOrigin(x: 0, y: 0, z: 0) 
let firstSlice = 1 
let lastSlice = 2 // inclusive 

let commandBuffer = commandQueue.makeCommandBuffer() 
let blitEncoder = commandBuffer.makeBlitCommandEncoder() 

for slice in firstSlice...lastSlice { 
    blitEncoder.copy(from: sourceImage.texture, 
        sourceSlice: slice, 
        sourceLevel: 0, 
        sourceOrigin: sourceRegion.origin, 
        sourceSize: sourceRegion.size, 
        to: destImage.texture, 
        destinationSlice: slice - firstSlice, 
        destinationLevel: 0, 
        destinationOrigin: destOrigin) 
} 

blitEncoder.endEncoding() 
commandBuffer.commit() 

我不确定为什么要剪裁,但请记住MPSCNN图层可以在MPSImage的较小部分上工作。只需设置offsetclipRect属性,该图层将只在源图像的该区域上工作。

事实上,你可以使用MPSCNNNeuronLinear这种方式做你的庄稼。不知道这是否比使用blit编码器更快或更慢,但它确实更简单。

编辑:增加了一个代码示例。这是从内存类型,因此它可能有小的误差,但这是总体思路:

// Declare this somewhere: 
let linearNeuron = MPSCNNNeuronLinear(a: 1, b: 0) 

然后,当你运行你的神经网络,添加以下内容:

let yourImage: MPSImage = ... 
let commandBuffer = ... 

// This describes the size of the cropped image. 
let imgDesc = MPSImageDescriptor(...) 

// If you're going to use the cropped image in other layers 
// then it's a good idea to make it a temporary image. 
let tempImg = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: imgDesc) 

// Set the cropping offset: 
linearNeuron.offset = MPSOffset(x: ..., y: ..., z: 0) 

// The clip rect is the size of the output image. 
linearNeuron.clipRect = MTLRegionMake(0, 0, imgDesc.width, imgDesc.height) 

linearNeuron.encode(commandBuffer: commandBuffer, sourceImage: yourImage, destinationImage: tempImg) 

// Here do your other layers, taking tempImg as input. 
. . . 

commandBuffer.commit() 
+0

我upvoted这两个问题的答案,但@ warrenm似乎更适合。我也喜欢你的想法。 – s1ddok

+0

你还可以提供一个简单的代码,介绍如何用'NeuronLinear'裁剪'MPSImage'?我发现我需要将'a'设置为'1',将'b'设为'0',但不知道下一步该怎么做。 – s1ddok

+0

如果'yourImage'是3通道图像(例如RGB),'tempImg'是1通道图像:如何使用linearNeuron实现通道更改? dest-region应该包含'R'或更好的灰色表示。当我用(,, 3)和(,, 1)指定ImageDescriptors时,整个事件都会崩溃。 – Chris