Un marco de procesamiento de imágenes basado en metal.
MTIImageMTIImageMTIImageCVPixelBufferSwiftAppleSiliconMetalPetal es un marco de procesamiento de imágenes basado en metal diseñado para proporcionar un procesamiento en tiempo real para imágenes fijas y videos con interfaces de programación fáciles de usar.
Este capítulo cubre los conceptos clave de MetalPetal, y lo ayudará a comprender mejor su diseño, implementación, implicaciones de rendimiento y mejores prácticas.
MetalPetal está diseñado con los siguientes objetivos en mente.
API fácil de usar
Proporciona API de conveniencia y evita las dificultades comunes.
Actuación
Use CPU, GPU y memoria de manera eficiente.
Extensibilidad
Fácil de crear filtros personalizados y complementar su unidad de procesamiento de imágenes personalizada.
Taciturno
Proporciona una experiencia fluida para programadores rápidos.
Algunos de los conceptos centrales de metalpetal son muy similares a los del marco de imagen central de Apple.
Proporciona un contexto de evaluación para representar MTIImage s. También almacena muchas cachés e información de estado, por lo que es más eficiente reutilizar un contexto siempre que sea posible.
Un objeto MTIImage es una representación de una imagen a procesar o producir. Representa directamente los datos de mapa de bits de imagen, en su lugar, tiene toda la información necesaria para producir una imagen o más precisamente una MTLTexture . Consiste en dos partes, una receta de cómo producir la textura ( MTIImagePromise ) y otra información, como cómo un contexto, almacena la imagen ( cachePolicy ) y cómo la textura debe muestrearse ( samplerDescriptor ).
Un MTIFilter representa un efecto de procesamiento de imagen y cualquier parámetros que controlen ese efecto. Produce un objeto MTIImage como salida. Para usar un filtro, crea un objeto de filtro, establece sus imágenes de entrada y parámetros, y luego accede a su imagen de salida. Por lo general, una clase de filtro posee un núcleo estático ( MTIKernel ), cuando accede a su propiedad outputImage , le pide al núcleo las imágenes de entrada y los parámetros para producir una salida MTIImage .
Un MTIKernel representa una rutina de procesamiento de imágenes. MTIKernel es responsable de crear el estado de tubería de renderización o calculadora correspondiente para el filtro, así como para construir el MTIImagePromise para una MTIImage .
MetalPetal hace muchas optimizaciones para usted debajo del capó.
Automáticamente almacena funciones, estados de núcleo, estados de muestras, etc.
Utiliza características de metal como mezcla programable, objetivos de renderizado sin memoria, montones de recursos y sombreadores de rendimiento de metal para que el renderizado sea rápido y eficiente. En MacOS, MetalPetal también puede aprovechar la arquitectura TBDR de Apple Silicon.
Antes de representar, MetalPetal puede investigar el gráfico de renderizado de su imagen y descubrir el número mínimo de texturas intermedias necesarias para hacer la representación, ahorrar memoria, energía y tiempo.
También puede reorganizar el gráfico de renderizado de la imagen si se pueden concatenar múltiples "recetas" para eliminar los pases de renderizado redundantes. ( MTIContext.isRenderGraphOptimizationEnabled )
Los objetos MTIImage son inmutables, lo que significa que se pueden compartir de manera segura entre los hilos.
Sin embargo, los objetos MTIFilter son mutables y, por lo tanto, no se pueden compartir de manera segura entre los hilos.
Un MTIContext contiene muchos estados y cachés. Hay un mecanismo seguro para los hilos para los objetos MTIContext , lo que hace que sea seguro compartir un objeto MTIContext entre hilos.
Funciones de vértices y fragmentos totalmente personalizables.
Soporte MRT (múltiples objetivos de renderizado).
Generalmente mejor rendimiento. (Se necesitan datos de referencia detallados)
Matriz de color
Búsqueda de color
Utiliza una tabla de búsqueda de color para reasignar los colores en una imagen.
Opacidad
Exposición
Saturación
Brillo
Contraste
Color invertido
Vibración
Ajusta la saturación de una imagen mientras mantiene los tonos de piel agradables.
Curva de tono rgb
Modos de mezcla
Mezclar con máscara
Transformar
Cultivo
Pixelado
Compuesto multicapa
Convolución MPS
MPS GAUSSIAN Desfloque
Definición de MPS
MPS Sobel
MPS MASCA UNSHARP
MPS Box borfia
Suavizado de la piel de pase alto
Clahe (igualación de histograma adaptativo limitado por contraste)
Blur de lente (hexagonal bokeh desenfoque)
Superficie desenfoque
Distorsión de bulto
Mezcla de teclas de croma
Color de medias salas de color
Pantalla
Esquina redonda (curva circular/continua)
Todos los filtros de imagen central
MTIImage Puede crear un objeto MTIImage a partir de casi cualquier fuente de datos de imagen, que incluya:
URL s referencia de archivos de imagen a cargarCVImageBufferRef o CVPixelBufferRef )CIImage ObjectsMDLTexture let imageFromCGImage = MTIImage ( cgImage : cgImage , isOpaque : true )
let imageFromCIImage = MTIImage ( ciImage : ciImage )
let imageFromCoreVideoPixelBuffer = MTIImage ( cvPixelBuffer : pixelBuffer , alphaType : . alphaIsOne )
let imageFromContentsOfURL = MTIImage ( contentsOf : url )
// unpremultiply alpha if needed
let unpremultipliedAlphaImage = image . unpremultiplyingAlpha ( ) let inputImage = ...
let filter = MTISaturationFilter ( )
filter . saturation = 0
filter . inputImage = inputImage
let outputImage = filter . outputImageMTIImage let options = MTIContextOptions ( )
guard let device = MTLCreateSystemDefaultDevice ( ) , let context = try ? MTIContext ( device : device , options : options ) else {
return
}
let image : MTIImage = ...
do {
try context . render ( image , to : pixelBuffer )
//context.makeCIImage(from: image)
//context.makeCGImage(from: image)
} catch {
print ( error )
}MTIImage let imageView = MTIImageView ( frame : self . view . bounds )
// You can optionally assign a `MTIContext` to the image view. If no context is assigned and `automaticallyCreatesContext` is set to `true` (the default value), a `MTIContext` is created automatically when the image view renders its content.
imageView . context = ...
imageView . image = image Si desea mover el proceso de codificación del comando GPU fuera del hilo principal, puede usar un MTIThreadSafeImageView . Puede asignar una MTIImage a un MTIThreadSafeImageView en cualquier hilo.
MetalPetal tiene una API Swift segura de tipo para conectar filtros. Puede usar => operador en FilterGraph.makeImage función para conectar filtros y obtener la imagen de salida.
Aquí hay algunos ejemplos:
let image = try ? FilterGraph . makeImage { output in
inputImage => saturationFilter => exposureFilter => output
} let image = try ? FilterGraph . makeImage { output in
inputImage => saturationFilter => exposureFilter => contrastFilter => blendFilter . inputPorts . inputImage
exposureFilter => blendFilter . inputPorts . inputBackgroundImage
blendFilter => output
} Puede conectar filtros Unary ( MTIUnaryFilter ) directamente usando => .
Para un filtro con múltiples entradas, debe conectarse a uno de sus inputPorts .
=> El operador solo funciona en FilterGraph.makeImage Method.
La salida de un solo filtro se puede conectar a output .
Trabajando con AVPlayer :
let context = try MTIContext ( device : device )
let asset = AVAsset ( url : videoURL )
let composition = MTIVideoComposition ( asset : asset , context : context , queue : DispatchQueue . main , filter : { request in
return FilterGraph . makeImage { output in
request . anySourceImage! => filterA => filterB => output
} !
}
let playerItem = AVPlayerItem ( asset : asset )
playerItem . videoComposition = composition . makeAVVideoComposition ( )
player . replaceCurrentItem ( with : playerItem )
player . play ( )Exportar un video:
Se requiere Videoio para los siguientes ejemplos.
import VideoIO
var configuration = AssetExportSession . Configuration ( fileType : . mp4 , videoSettings : . h264 ( videoSize : composition . renderSize ) , audioSettings : . aac ( channels : 2 , sampleRate : 44100 , bitRate : 128 * 1000 ) )
configuration . videoComposition = composition . makeAVVideoComposition ( )
self . exporter = try ! AssetExportSession ( asset : asset , outputURL : outputURL , configuration : configuration )
exporter . export ( progress : { progress in
} , completion : { error in
} )Se requiere Videoio para este ejemplo.
import VideoIO
// Setup Image View
let imageView = MTIImageView ( frame : self . view . bounds )
...
// Setup Camera
let camera = Camera ( captureSessionPreset : . hd1920x1080 , configurator : . portraitFrontMirroredVideoOutput )
try camera . enableVideoDataOutput ( on : DispatchQueue . main , delegate : self )
camera . videoDataOutput ? . videoSettings = [ kCVPixelBufferPixelFormatTypeKey as String : kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ]
...
// AVCaptureVideoDataOutputSampleBufferDelegate
let filter = MTIColorInvertFilter ( )
func captureOutput ( _ output : AVCaptureOutput , didOutput sampleBuffer : CMSampleBuffer , from connection : AVCaptureConnection ) {
guard let pixelBuffer = CMSampleBufferGetImageBuffer ( sampleBuffer ) else {
return
}
let inputImage = MTIImage ( cvPixelBuffer : pixelBuffer , alphaType : . alphaIsOne )
filter . inputImage = inputImage
self . imageView . image = filter . outputImage
} Consulte el CameraFilterView.swift en el proyecto de ejemplo para obtener más información sobre la vista previa y la grabación de video en vivo filtrado.
Reutilice un MTIContext siempre que sea posible.
Los contextos son objetos de peso pesado, por lo que si crea uno, hágalo lo antes posible y reutilízalo cada vez que necesite representar una imagen.
Use MTIImage.cachePolicy sabiamente.
Use MTIImageCachePolicyTransient cuando no desee preservar el resultado de renderizado de una imagen, por ejemplo, cuando la imagen es solo un resultado intermedio en una cadena de filtro, por lo que la textura subyacente del resultado de renderizado se puede reutilizar. Es la opción más eficiente de memoria. Sin embargo, cuando le pide al contexto que represente una imagen previamente renderizada, puede volver a renderizar esa imagen ya que su textura subyacente se ha reutilizado.
Por defecto, la imagen de salida de un filtro tiene la política transient .
Use MTIImageCachePolicyPersistent cuando desee evitar que la textura subyacente se reutilice.
Por defecto, las imágenes creadas a partir de fuentes externas tienen la política persistent .
Comprenda que MTIFilter.outputImage es una propiedad de cómputo.
Cada vez que solicita un filtro para su imagen de salida, el filtro puede darle un nuevo objeto de imagen de salida incluso si las entradas son idénticas con la llamada anterior. Entonces, reutilice las imágenes de salida siempre que sea posible.
Por ejemplo,
// ╭→ filterB
// filterA ─┤
// ╰→ filterC
//
// filterB and filterC use filterA's output as their input.En esta situación, la siguiente solución:
let filterOutputImage = filterA . outputImage
filterB . inputImage = filterOutputImage
filterC . inputImage = filterOutputImagees mejor que:
filterB . inputImage = filterA . outputImage
filterC . inputImage = filterA . outputImage Si desea incluir el MTIShaderLib.h en su archivo .metal , debe agregar la ruta del archivo MTIShaderLib.h a la configuración del Metal Compiler - Header Search Paths ( MTL_HEADER_SEARCH_PATHS ).
Por ejemplo, si usa Cocoapods, puede establecer MTL_HEADER_SEARCH_PATHS en ${PODS_CONFIGURATION_BUILD_DIR}/MetalPetal/MetalPetal.framework/Headers o ${PODS_ROOT}/MetalPetal/Frameworks/MetalPetal/Shaders . Si usa Swift Package Manager, configure MTL_HEADER_SEARCH_PATHS en $(HEADER_SEARCH_PATHS)
MetalPetal tiene un mecanismo incorporado para codificar los argumentos de la función de sombreador para usted. Puede pasar los argumentos de la función del sombreador como name: value a MTIRenderPipelineKernel.apply(toInputImages:parameters:outputDescriptors:) , MTIRenderCommand(kernel:geometry:images:parameters:) , etc.
Por ejemplo, el diccionario de parámetros para la función de metal vibranceAdjust puede ser:
// Swift
let amount : Float = 1.0
let vibranceVector = float4 ( 1 , 1 , 1 , 1 )
let parameters = [ " amount " : amount ,
" vibranceVector " : MTIVector ( value : vibranceVector ) ,
" avoidsSaturatingSkinTones " : true ,
" grayColorTransform " : MTIVector ( value : float3 ( 0 , 0 , 0 ) ) ] // vibranceAdjust metal function
fragment float4 vibranceAdjust (...,
constant float & amount [[ buffer( 0 ) ]],
constant float4 & vibranceVector [[ buffer( 1 ) ]],
constant bool & avoidsSaturatingSkinTones [[ buffer( 2 ) ]],
constant float3 & grayColorTransform [[ buffer( 3 ) ]])
{
...
}
Los tipos de argumentos de la función del sombreador y los tipos correspondientes a usar en un diccionario de parámetros se enumeran a continuación.
| Tipo de argumento de la función de sombreador | Rápido | Objetivo-C |
|---|---|---|
| flotar | Flotar | flotar |
| intencionalmente | Int32 | intencionalmente |
| uint | Uint32 | uint |
| bool | Bool | bool |
| Simd (Float2, Float4, Float4x4, Int4, etc.) | Simd (con MetalPetal/Swift ) / mtivector | Mtivector |
| estructura | Datos / mtidatabuffer | Nsdata / mtidatabuffer |
| Otro (flotante *, estructura *, etc.) inmutable | Datos / mtidatabuffer | Nsdata / mtidatabuffer |
| Otro (flotante *, struct *, etc.) mutable | Mtidatabuffer | Mtidatabuffer |
Para construir un filtro unario personalizado, puede subclase MTIUnaryImageRenderingFilter y anular los métodos en la categoría SubclassingHooks . Ejemplos: MTIPixellateFilter , MTIVibranceFilter , MTIUnpremultiplyAlphaFilter , MTIPremultiplyAlphaFilter , etc.
// Objective-C
@interface MTIPixellateFilter : MTIUnaryImageRenderingFilter
@property ( nonatomic ) float fractionalWidthOfAPixel;
@end
@implementation MTIPixellateFilter
- ( instancetype ) init {
if (self = [ super init ]) {
_fractionalWidthOfAPixel = 0.05 ;
}
return self;
}
+ (MTIFunctionDescriptor *) fragmentFunctionDescriptor {
return [[MTIFunctionDescriptor alloc ] initWithName: @" pixellateEffect " libraryURL: [bundle URLForResource: @" default " withExtension: @" metallib " ]];
}
- ( NSDictionary <NSString *,id> *) parameters {
return @{ @" fractionalWidthOfAPixel " : @(self. fractionalWidthOfAPixel )};
}
@end //Swift
class MTIPixellateFilter : MTIUnaryImageRenderingFilter {
var fractionalWidthOfAPixel : Float = 0.05
override var parameters : [ String : Any ] {
return [ " fractionalWidthOfAPixel " : fractionalWidthOfAPixel ]
}
override class func fragmentFunctionDescriptor ( ) -> MTIFunctionDescriptor {
return MTIFunctionDescriptor ( name : " pixellateEffect " , libraryURL : MTIDefaultLibraryURLForBundle ( Bundle . main ) )
}
} Para construir filtros más complejos, todo lo que necesita hacer es crear un kernel ( MTIRenderPipelineKernel / MTIComputePipelineKernel / MTIMPSKernel ), luego aplique el núcleo a las imágenes de entrada (s). Ejemplos: MTIChromaKeyBlendFilter , MTIBlendWithMaskFilter , MTIColorLookupFilter , etc.
@interface MTIChromaKeyBlendFilter : NSObject <MTIFilter>
@property ( nonatomic , strong , nullable ) MTIImage *inputImage;
@property ( nonatomic , strong , nullable ) MTIImage *inputBackgroundImage;
@property ( nonatomic ) float thresholdSensitivity;
@property ( nonatomic ) float smoothing;
@property ( nonatomic ) MTIColor color;
@end
@implementation MTIChromaKeyBlendFilter
@synthesize outputPixelFormat = _outputPixelFormat;
+ (MTIRenderPipelineKernel *) kernel {
static MTIRenderPipelineKernel *kernel;
static dispatch_once_t onceToken;
dispatch_once (&onceToken, ^{
kernel = [[MTIRenderPipelineKernel alloc ] initWithVertexFunctionDescriptor: [[MTIFunctionDescriptor alloc ] initWithName: MTIFilterPassthroughVertexFunctionName] fragmentFunctionDescriptor: [[MTIFunctionDescriptor alloc ] initWithName: @" chromaKeyBlend " ]];
});
return kernel;
}
- ( instancetype ) init {
if (self = [ super init ]) {
_thresholdSensitivity = 0.4 ;
_smoothing = 0.1 ;
_color = MTIColorMake ( 0.0 , 1.0 , 0.0 , 1.0 );
}
return self;
}
- (MTIImage *) outputImage {
if (!self. inputImage || !self. inputBackgroundImage ) {
return nil ;
}
return [ self .class.kernel applyToInputImages: @[ self .inputImage, self .inputBackgroundImage]
parameters: @{ @" color " : [MTIVector vectorWithFloat4: (simd_float4){self. color . red , self. color . green , self. color . blue ,self. color . alpha }],
@" thresholdSensitivity " : @(self. thresholdSensitivity ),
@" smoothing " : @(self. smoothing )}
outputTextureDimensions: MTITextureDimensionsMake2DFromCGSize ( self .inputImage.size)
outputPixelFormat: self .outputPixelFormat];
}
@end Puede usar MTIRenderCommand para emitir múltiples llamadas de sorteo en un pase de renderizado.
// Create a draw call with kernelA, geometryA, and imageA.
let renderCommandA = MTIRenderCommand ( kernel : self . kernelA , geometry : self . geometryA , images : [ imageA ] , parameters : [ : ] )
// Create a draw call with kernelB, geometryB, and imageB.
let renderCommandB = MTIRenderCommand ( kernel : self . kernelB , geometry : self . geometryB , images : [ imageB ] , parameters : [ : ] )
// Create an output descriptor
let outputDescriptor = MTIRenderPassOutputDescriptor ( dimensions : MTITextureDimensions ( width : outputWidth , height : outputHeight , depth : 1 ) , pixelFormat : . bgra8Unorm , loadAction : . clear , storeAction : . store )
// Get the output images, the output image count is equal to the output descriptor count.
let images = MTIRenderCommand . images ( byPerforming : [ renderCommandA , renderCommandB ] , outputDescriptors : [ outputDescriptor ] )También puede crear múltiples descriptores de salida para emitir múltiples imágenes en un pase de renderizado (MRT, ver https://en.wikipedia.org/wiki/multiple_render_targets).
Cuando MTIVertex no puede satisfacer sus necesidades, puede implementar el Protocolo MTIGeometry para proporcionar sus datos de vértice personalizados al codificador de comando.
Use la API MTIRenderCommand para emitir llamadas de dibujo y pasar su MTIGeometry personalizada.
En escenarios raros, es posible que desee acceder a la textura subyacente directamente, usar múltiples núcleos de MPS en un pase de renderizado, hacer una representación 3D o codificar los comandos de renderizado usted mismo.
El protocolo MTIImagePromise proporciona acceso directo a la textura subyacente y al contexto de renderizado para un paso en MetalPetal.
Puede crear nuevas fuentes de entrada o unidades de procesamiento completamente personalizadas implementando el protocolo MTIImagePromise . Deberá importar un módulo adicional para hacerlo.
Objetivo-C
@import MetalPetal.Extension;
Rápido
// CocoaPods
import MetalPetal.Extension
// Swift Package Manager
import MetalPetalObjectiveC.Extension
Consulte la implementación de MTIComputePipelineKernel , MTICLAHELUTRecipe o MTIImage por ejemplo.
Si se usa un canal alfa en una imagen, hay dos representaciones comunes disponibles: alfa no comercializado (recto/no asociado) y alfa premultiplicado (asociado).
Con el alfa no comercializado, los componentes RGB representan el color del píxel, sin tener en cuenta su opacidad.
Con el alfa premultipado, los componentes RGB representan el color del píxel, ajustado por su opacidad por multiplicación.
Manjas de metalpetal tipo alfa explícitamente. Usted es responsable de proporcionar el tipo alfa correcto durante la creación de imágenes.
Hay tres tipos alfa en metalpetal.
MTIAlphaType.nonPremultiplied : el valor alfa en la imagen no se premultiplica.
MTIAlphaType.premultiplied : el valor alfa en la imagen se premultiplica.
MTIAlphaType.alphaIsOne : no hay canal alfa en la imagen o la imagen es opaca.
Por lo general, los objetos CGImage , CVPixelBuffer y CIImage tienen canales alfa premultiplicados. MTIAlphaType.alphaIsOne se recomienda encarecidamente si la imagen es opaca, por ejemplo, un CVPixelBuffer de la alimentación de la cámara o una CGImage cargada desde un archivo jpg .
Puede llamar unpremultiplyingAlpha() o premultiplyingAlpha() en una MTIImage para convertir el tipo alfa de la imagen.
Por razones de rendimiento, la validación de tipo alfa solo ocurre en la construcción de depuración.
La mayoría de los filtros en MetalPetal aceptan imágenes alfa y opacas no abundantes y imágenes de alfa no abundantes.
Los filtros con propiedad outputAlphaType aceptan entradas de todos los tipos alfa. Y puede usar outputAlphaType para especificar el tipo alfa de la imagen de salida.
por ejemplo, MTIBlendFilter , MTIMultilayerCompositingFilter , MTICoreImageUnaryFilter , MTIRGBColorSpaceConversionFilter
Los filtros que en realidad no modifican los colores tienen una regla de manejo alfa de paso, lo que significa que los tipos alfa de las imágenes de salida son los mismos con las imágenes de entrada.
por ejemplo, MTITransformFilter , MTICropFilter , MTIPixellateFilter , MTIBulgeDistortionFilter
Para obtener más información sobre los tipos alfa y la composición alfa, consulte este increíble artículo interactivo de Bartosz CiCanowski.
Los espacios de color son vitales para el procesamiento de imágenes. Los valores numéricos de los componentes rojos, verdes y azules no tienen sentido sin espacio de color.
Antes de continuar cómo MetalPetal maneja los espacios de color, es posible que desee saber qué es un espacio de color y cómo afecta la representación de los valores de color. Hay muchos artículos en la web que explican los espacios de color, para comenzar, la sugerencia son los espacios de color, por Bartosz CiCanowski.
Diferentes software y marcos tienen diferentes formas de manejar espacios de color. Por ejemplo, Photoshop tiene un espacio de color de trabajo SRGB IEC61966-2.1 predeterminado, mientras que Core Image, por defecto, utiliza un espacio de color de trabajo SRGB lineal.
Las texturas de metal no almacenan ninguna información del espacio de color con ellas. La mayor parte del manejo del espacio de color en MetalPetal ocurre durante la entrada ( MTIImage(...) ) y la salida ( MTIContext.render... ) de los datos de la imagen.
Especificar un espacio de color para una entrada significa que MetalPetal debe convertir los valores de color de la fuente al espacio de color especificado durante la creación de la textura.
Al cargar desde URL o CGImage , puede especificar en qué espacio de color desea que se encuentren los datos de textura, utilizando MTICGImageLoadingOptions . Si no especifica ninguna opción al cargar una imagen, se usa el espacio de color RGB del dispositivo ( MTICGImageLoadingOptions.default ). Un espacio de color nil deshabilita la coincidencia de color, este es el equivalente de usar el espacio de color de la imagen de entrada para crear MTICGImageLoadingOptions . Si el modelo del espacio de color especificado no es RGB, el dispositivo de color RGB se usa como alternativa.
Al cargar desde CIImage , puede especificar en qué espacio de color desea que se encuentren los datos de textura, utilizando MTICIImageRenderingOptions . Si no especifica ninguna opción al cargar una CIImage , se usa el espacio de color RGB del dispositivo ( MTICIImageRenderingOptions.default ). Un espacio de color nil deshabilita la coincidencia de color, los valores de color se cargan en el espacio de color de trabajo del CIContext .
Al especificar un espacio de color para una salida, el espacio de color sirve más como una etiqueta que se usa para comunicarse con el resto del sistema sobre cómo representar los valores de color en la salida. No se realiza una conversión de espacio de color real.
Puede especificar el espacio de color de una salida CGImage usando MTIContext.makeCGImage... o MTIContext.startTaskTo... métodos con un parámetro colorSpace .
Puede especificar el espacio de color de una CIImage de salida utilizando MTICIImageCreationOptions .
MetalPetal supone que los valores de color de salida están en el espacio de color RGB del dispositivo cuando no se especifica espacio de color de salida.
CVPixelBuffer MetalPetal utiliza CVMetalTextureCache e IOSurface para asignar directamente CVPixelBuffer s a las texturas de metal. Por lo tanto, no puede especificar un espacio de color para cargar o representar a un CVPixelBuffer . Sin embargo, puede especificar si usar una textura con un formato de píxel SRGB para el mapeo.
En metal, si el nombre del formato de píxel tiene el sufijo _sRGB , entonces la compresión y descompresión gamma SRGB se aplican durante la lectura y la escritura de valores de color en el píxel. Eso significa que una textura con el formato de píxel _sRGB supone que los valores de color que almacena se corrigen SRGB gamma, cuando los valores de color se leen en un sombreador, se realizan SRGB a conversiones lineales de RGB. Cuando los valores de color se escriben en un sombreador, se realizan conversiones lineales de RGB a SRGB.
Puede usar MTIRGBColorSpaceConversionFilter para realizar conversiones de espacio de color. Las funciones de conversión del espacio de color también están disponibles en MTIShaderLib.h .
metalpetal::sRGBToLinear (SRGB IEC61966-2.1 a SRGB lineal)metalpetal::linearToSRGB (lineal srgb a srgb IEC61966-2.1)metalpetal::linearToITUR709 (SRGB lineal a ITU-R 709)metalpetal::ITUR709ToLinear (ITU-R 709 a SRGB lineal) Puede usar MTISCNSceneRenderer para generar MTIImage S a partir de una SCNScene . Es posible que desee manejar el espacio de color RGB lineal del renderizador de ScineKit, consulte el número 76 La imagen de ScineKit es más oscura de lo normal.
Puede usar MTISKSceneRenderer para generar MTIImage S desde un SKScene .
Puede crear MTIImage S de CIImage s.
Puede representar una MTIImage a una CIImage utilizando un MTIContext .
Puede usar un CIFilter directamente con MTICoreImageKernel o la clase MTICoreImageUnaryFilter . (Solo rápido)
Ver metalpetaljs
Con MetalPetaljs, puede crear tuberías y filtros de renderizado utilizando JavaScript, lo que permite descargar sus filtros/renderistas de "la nube".
Se recomienda que use API que acepten MTICGImageLoadingOptions para cargar CGImage S e imágenes de URL , en lugar de usar API que acepten MTKTextureLoaderOption .
Cuando usa API que acepta MTKTextureLoaderOption , MetalPetal, por defecto, usa MTIDefaultTextureLoader para cargar CGImage S, imágenes de URL e imágenes con nombre. MTIDefaultTextureLoader usa MTKTextureLoader internamente y tiene algunas soluciones para las inconsistencias y errores de MTKTextureLoader a un pequeño costo de rendimiento. También puede crear su propio cargador de texturas implementando el protocolo MTITextureLoader . Luego asigne su clase de cargador de textura a MTIContextOptions.textureLoaderClass al crear un MTIContext .
Puede usar Cocoapods para instalar la última versión.
use_frameworks!
pod 'MetalPetal'
# Required if you are using Swift.
pod 'MetalPetal/Swift'
# Recommended if you'd like to run MetalPetal on Apple silicon Macs.
pod 'MetalPetal/AppleSilicon'
SwiftProporciona adiciones y modificaciones específicas de SWIFT a las API Objective-C para mejorar su mapeo en Swift. Muy recomendable si estás usando Swift.
AppleSiliconProporciona la biblioteca de sombreador predeterminada compilada en el lenguaje de sombreado de metal v2.3 que es necesario para habilitar el soporte de mezcla programable en Apple Silicon Macs.
Agregar dependencias de paquetes a su aplicación
MetalPetal puede ejecutarse en simulador con Xcode 11+ y MacOS 10.15+.
MetalPerformanceShaders.framework no está disponible en el simulador, por lo que los filtros que dependen de MetalPerformanceShaders , como MTIMPSGaussianBlurFilter , MTICLAHEFilter , no funcionan.
El simulador admite menos características o límites de implementación diferentes que una GPU de Apple real. Consulte el desarrollo de aplicaciones de metal que se ejecutan en simulador para obtener detalles.
Si hace un vistazo rápido a una MTIImage , le mostrará el gráfico de imagen que construyó para producir esa imagen.

¿Por qué Objective-C?
Gracias por considerar contribuir a MetalPetal. Lea nuestras pautas contribuyentes.
MetalPetal es licenciado por MIT. LICENCIA
Los archivos en el directorio /MetalPetalExamples tienen licencia bajo una licencia separada. Licencia.md
La documentación tiene licencia CC-By-4.0.