2017-07-04 3 views
2

J'ai une CGImage qui est construite à partir d'un tampon CVPixel (ARGB). Je veux convertir cette CGImage en une MTLTexture. J'utilise:CGImage à MPSTexture ou MPSImage

let texture: MTLTexture = try m_textureLoader.newTexture(with: cgImage, options: [MTKTextureLoaderOptionSRGB : NSNumber(value: true)]) 

Plus tard, je veux utiliser la texture dans un MPSImage ayant 3 canaux:

let sid = MPSImageDescriptor(channelFormat: MPSImageFeatureChannelFormat.float16, width: 40, height: 40, featureChannels: 3) 
preImage = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: sid) 
lanczos.encode(commandBuffer: commandBuffer, sourceTexture: texture!, destinationTexture: preImage.texture) 
scale.encode (commandBuffer: commandBuffer, sourceImage: preImage, destinationImage: srcImage) 

Maintenant, mes questions: Comment textureLoader.newTexture (...) la carte les quatre ARVB canaux aux 3 canaux spécifiés dans le MPSImageDescriptor? Comment puis-je m'assurer que les composants RVB sont utilisés et non par ex. ARG? Existe-t-il un moyen de spécifier ce mappage de canal?

Merci, Chris

Répondre

4

Pourquoi ne pas construire le MTLTexture du CVPixelBuffer directement? Est beaucoup plus rapide!

Est-ce que cette fois au début de votre programme:

// declare this somewhere, so we can re-use it 
var textureCache: CVMetalTextureCache? 

// create the texture cache object 
guard CVMetalTextureCacheCreate(kCFAllocatorDefault, nil, device, nil, &textureCache) == kCVReturnSuccess else { 
    print("Error: could not create a texture cache") 
    return false 
} 

Est-ce que cette fois que vous aurez votre CVPixelBuffer:

let width = CVPixelBufferGetWidth(pixelBuffer) 
let height = CVPixelBufferGetHeight(pixelBuffer) 

var texture: CVMetalTexture? 
CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, textureCache, 
     pixelBuffer, nil, .bgra8Unorm, width, height, 0, &texture) 

if let texture = texture { 
    metalTexture = CVMetalTextureGetTexture(texture) 
} 

Maintenant metalTexture contient un objet MTLTexture avec le contenu du CVPixelBuffer.

+0

Merci beaucoup. Ça a l'air beaucoup plus facile. Cependant, je n'ai besoin que d'une partie recadrée du tampon de pixels qui va dans la texture. Je connais les coordonnées du ROI. Votre solution peut-elle être étendue pour faire cela? Si c'est le cas, comment ? Merci – Chris

+0

Vous pouvez créer un 'MTLTexture' supplémentaire dont la taille est égale à la taille de la ROI, puis utiliser un 'MTLBlitCommandEncoder' pour copier simplement cette région à partir de la texture que vous avez créée à partir du tampon de pixels. Cela utilisera temporairement plus de mémoire, mais après, vous pouvez rejeter ou réutiliser la première texture. Il existe d'autres façons de le faire avec Core Image ou Accelerate, mais au meilleur de ma connaissance, elles nécessiteront toutes des allocations et des copies supplémentaires. – warrenm

+1

Une alternative qui n'implique pas de faire des copies consiste à convertir le tampon de pixels complet en texture, puis à spécifier un clipRect et un décalage au noyau MPS que vous appelez (ou si vous utilisez l'échelle de Lanczos, définissez une transformation)). Cela fera fonctionner le noyau MPS sur une plus petite partie de l'image. (Toutefois, si votre région de recadrage est très petite par rapport à l'image source, faire une copie comme @warrenm suggéré pourrait être plus efficace.) –