Ein Bildverarbeitungsrahmen basierend auf Metall.
MTIImageMTIImage machenMTIImageCVPixelBufferSwiftAppleSiliconMetalpetal ist ein Bildverarbeitungsrahmen, das auf Metall basiert, das für die Echtzeitverarbeitung für Standbilder und Video mit einfach zu verwendenden Programmierschnittstellen ausgelegt ist.
Dieses Kapitel behandelt die Schlüsselkonzepte von Metalpetal und hilft Ihnen dabei, das Design, die Implementierung, die Auswirkungen auf die Leistung und die Best Practices besser zu verstehen.
Metalpetal ist mit den folgenden Zielen konzipiert.
Einfach zu bedienender API
Bietet Komfort -APIs und vermeidet gemeinsame Fallstricke.
Leistung
Verwenden Sie effizient CPU, GPU und Speicher.
Erweiterbarkeit
Einfach zu erstellen benutzerdefinierte Filter sowie das Plugin Ihrer benutzerdefinierten Bildverarbeitungseinheit.
Schwaftend
Bietet ein flüssiges Erlebnis für Swift -Programmierer.
Einige der Kernkonzepte von Metalpetal sind denen im Kernbild von Apple sehr ähnlich.
Bietet einen Bewertungskontext für die Wiedergabe MTIImage s. Es speichert auch viele Caches und staatliche Informationen, sodass es effizienter ist, nach Möglichkeit einen Kontext wiederzuverwenden.
Ein MTIImage -Objekt ist eine Darstellung eines zu verarbeitenden oder erstellten Bildes. Es repräsentiert direkt Bildbitmap -Daten, sondern enthält alle Informationen, die erforderlich sind, um ein Bild oder MTLTexture zu erstellen. Es besteht aus zwei Teilen, einem Rezept, wie die Textur ( MTIImagePromise ) und andere Informationen erzeugt werden können, z. B. wie ein Kontext das Bild ( cachePolicy ) zwischengespeichert und wie die Textur abgetastet werden sollte ( samplerDescriptor ).
Ein MTIFilter repräsentiert einen Bildverarbeitungseffekt und alle Parameter, die diesen Effekt steuern. Es erzeugt ein MTIImage -Objekt als Ausgang. Um einen Filter zu verwenden, erstellen Sie ein Filterobjekt, setzen seine Eingangsbilder und Parameter fest und greifen dann auf das Ausgabebild zu. In der Regel besitzt eine Filterklasse einen statischen Kernel ( MTIKernel ), wenn Sie auf die Eigenschaft aus der outputImage zugreifen, die Kernel mit den Eingangsbildern und -Parametern auffordert, eine Ausgabe MTIImage zu erzeugen.
Ein MTIKernel repräsentiert eine Bildverarbeitungsroutine. MTIKernel ist dafür verantwortlich, den entsprechenden Render- oder Berechnen -Pipeline -Zustand für den Filter zu erstellen und das MTIImagePromise für ein MTIImage zu erstellen.
Metalpetal macht viele Optimierungen für Sie unter der Motorhaube.
Es schneidet automatisch Funktionen, Kernelzustände, Stichprobenzustände usw.
Es verwendet Metallfunktionen wie programmierbare Mischung, maßloses Render -Ziele, Ressourcenhaufen und Metall -Performance -Shader, um das Rendern schnell und effizient zu machen. Auf macOS kann Metalpetal auch die TBDR -Architektur von Apple Silicon nutzen.
Vor dem Rendern kann Metalpetal in Ihrem Bild -Render -Diagramm untersucht und die minimale Anzahl von Zwischenstruktur ermittelt werden, die für das Rendering, das Speichern von Speicher, Energie und Zeit erforderlich sind.
Es kann auch das Bild-Render-Diagramm neu organisieren, wenn mehrere „Rezepte“ verkettet werden können, um redundante Render-Pässe zu beseitigen. ( MTIContext.isRenderGraphOptimizationEnabled )
MTIImage -Objekte sind unveränderlich, was bedeutet, dass sie sicher unter Threads geteilt werden können.
MTIFilter -Objekte sind jedoch veränderlich und können daher nicht sicher unter Threads geteilt werden.
Ein MTIContext enthält viele Zustände und Caches. Es gibt einen thread-sicheren Mechanismus für MTIContext -Objekte, sodass es sicher ist, ein MTIContext -Objekt unter Threads zu teilen.
Vollständig anpassbare Scheitelpunkt- und Fragmentfunktionen.
Unterstützung von MRT (Mehrfach -Render -Ziele).
Im Allgemeinen bessere Leistung. (Detaillierte Benchmark -Daten benötigt)
Farbmatrix
Farb -Lookup
Verwendet eine Farb -Lookup -Tabelle, um die Farben in einem Bild neu zu gestalten.
Opazität
Belichtung
Sättigung
Helligkeit
Kontrast
Farbe invertiert
Vibrance
Passen Sie die Sättigung eines Bildes an und halten Sie die Hauttöne an.
RGB -Tonkurve
Mischmodi
Maske mit Maske mischen
Verwandeln
Ernte
Pixellate
Mehrschichtiger Verbundwerkstoff
MPS -Faltung
MPS GAUSSIAN BLUR
Abgeordnete Definition
MPS SOBEL
Abgeordnete Unscharp -Maske
MPS -Box Blur
Hochpasshautglättung
Clahe (kontrastbegrenzte adaptive Histogrammausgleich)
Objektiv Blur (hexagonaler Bokeh Blur)
Oberfläche Unschärfe
Ausbuchtungsverzerrung
Chroma Key -Mischung
Farbhalftone
Punktbildschirm
Runde Ecke (kreisförmige/kontinuierliche Kurve)
Alle Kernbildfilter
MTIImage Sie können ein MTIImage -Objekt aus nahezu jeder Quelle von Bilddaten erstellen, einschließlich:
URL Referenzierungsbilddateien zu geladen werdenCVImageBufferRef oder CVPixelBufferRef )CIImage -ObjekteMDLTexture -Objekte 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 machen 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 Wenn Sie den Codierungsprozess des GPU -Befehls aus dem Haupt -Thread verschieben möchten, können Sie eine MTIThreadSafeImageView verwenden. Sie können einem MTIThreadSafeImageView in jedem Thread eine MTIImage zuweisen.
Metalpetal verfügt über eine Swift-API vom Typ Typ zum Anschließen von Filtern. Sie können => Bediener in FilterGraph.makeImage -Funktion verwenden, um Filter zu verbinden und das Ausgabebild zu erhalten.
Hier sind einige Beispiele:
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
} Sie können unäre Filter ( MTIUnaryFilter ) direkt mit => anschließen.
Für einen Filter mit mehreren Eingängen müssen Sie eine Verbindung zu einem seiner inputPorts herstellen.
=> Operator funktioniert nur in FilterGraph.makeImage -Methode.
Ein und nur die Ausgabe eines Filters kann mit output verbunden werden.
Arbeiten mit 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 ( )Ein Video exportieren:
Videoio ist für die folgenden Beispiele erforderlich.
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
} )Für dieses Beispiel ist Videoio erforderlich.
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
} Weitere Informationen zur Vorschau und Aufnahme von gefilterten Live -Videos finden Sie unter CameraFilterView.swift .
Verwenden Sie nach Möglichkeit einen MTIContext .
Kontexte sind Schwergewichtsobjekte. Wenn Sie also einen erstellen, tun Sie dies so früh wie möglich und verwenden Sie es jedes Mal wieder, wenn Sie ein Bild rendern.
Verwenden Sie MTIImage.cachePolicy mit Bedacht.
Verwenden Sie MTIImageCachePolicyTransient , wenn Sie das Rendernergebnis eines Bildes nicht bewahren möchten, beispielsweise wenn das Bild nur ein mittleres Ergebnis in einer Filterkette ist, sodass die zugrunde liegende Textur des Renderergebnisses wiederverwendet werden kann. Es ist die maßstabendigste Option. Wenn Sie jedoch den Kontext bitten, ein zuvor gerendertes Bild zu machen, kann es dieses Bild erneut übertragen, da seine zugrunde liegende Textur wiederverwendet wurde.
Standardmäßig hat das Ausgangsbild eines Filters die transient Richtlinie.
Verwenden Sie MTIImageCachePolicyPersistent wenn Sie verhindern möchten, dass die zugrunde liegende Textur wiederverwendet wird.
Standardmäßig haben Bilder aus externen Quellen die persistent Richtlinie.
Verstehen Sie, dass MTIFilter.outputImage eine Berechnungsimperie ist.
Jedes Mal, wenn Sie einen Filter nach seinem Ausgabebild fragen, kann der Filter ein neues Ausgabebildobjekt erhalten, auch wenn die Eingänge mit dem vorherigen Aufruf identisch sind. Verwenden Sie also nach Möglichkeit Ausgabebilder.
Zum Beispiel,
// ╭→ filterB
// filterA ─┤
// ╰→ filterC
//
// filterB and filterC use filterA's output as their input.In dieser Situation die folgende Lösung:
let filterOutputImage = filterA . outputImage
filterB . inputImage = filterOutputImage
filterC . inputImage = filterOutputImageist besser als:
filterB . inputImage = filterA . outputImage
filterC . inputImage = filterA . outputImage Wenn Sie den MTIShaderLib.h in Ihre .metal -Datei aufnehmen möchten, müssen Sie den Metal Compiler - Header Search Paths ( MTL_HEADER_SEARCH_PATHS ) den Weg der MTIShaderLib.h -Datei hinzufügen.
Wenn Sie beispielsweise Cocoapods verwenden, können Sie die MTL_HEADER_SEARCH_PATHS auf ${PODS_CONFIGURATION_BUILD_DIR}/MetalPetal/MetalPetal.framework/Headers oder ${PODS_ROOT}/MetalPetal/Frameworks/MetalPetal/Shaders festlegen. Wenn Sie Swift Paket Manager verwenden, setzen Sie die MTL_HEADER_SEARCH_PATHS auf $(HEADER_SEARCH_PATHS)
Metalpetal verfügt über einen integrierten Mechanismus, um Shader-Funktionsargumente für Sie zu kodieren. Sie können die Shader -Funktionsargumente als name: value -Wörterbücher an die MTIRenderPipelineKernel.apply(toInputImages:parameters:outputDescriptors:) , MTIRenderCommand(kernel:geometry:images:parameters:) :
Zum Beispiel kann das Parameter -Wörterbuch für die Metallfunktion vibranceAdjust sein:
// 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 ) ]])
{
...
}
Die Shader -Funktionsargumententypen und die entsprechenden Typen, die in einem Parameterwörterbuch verwendet werden sollen, sind unten aufgeführt.
| Shader -Funktion Argumenttyp | Schnell | Ziel-C |
|---|---|---|
| schweben | Schweben | schweben |
| int | INT32 | int |
| uint | Uint32 | uint |
| bool | Bool | bool |
| SIMD (Float2, Float4, Float4x4, int4 usw.) | SIMD (mit MetalPetal/Swift ) / MTivector | Mtivector |
| Struktur | Daten / mtidatabuffer | Nsdata / mtidatabuffer |
| Andere (float *, struktur *usw.) unveränderlich | Daten / mtidatabuffer | Nsdata / mtidatabuffer |
| andere (float *, struct *usw.) veränderlich | Mtidatabuffer | Mtidatabuffer |
Um einen benutzerdefinierten Unary -Filter zu erstellen, können Sie MTIUnaryImageRenderingFilter subklassen und die Methoden in der Kategorie SubclassingHooks überschreiben. Beispiele: MTIPixellateFilter , MTIVibranceFilter , MTIUnpremultiplyAlphaFilter , MTIPremultiplyAlphaFilter usw.
// 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 ) )
}
} Um komplexere Filter zu erstellen, müssen Sie lediglich einen Kernel ( MTIRenderPipelineKernel / MTIComputePipelineKernel / MTIMPSKernel ) erstellen und dann den Kernel auf das Eingabebild (en) anwenden. Beispiele: MTIChromaKeyBlendFilter , MTIBlendWithMaskFilter , MTIColorLookupFilter usw.
@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 Sie können MTIRenderCommand verwenden, um mehrere Ziehanrufe in einem Render -Pass auszugeben.
// 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 ] )Sie können auch mehrere Ausgangsdeskriptoren erstellen, um mehrere Bilder in einem Render -Pass auszugeben (MRT, siehe https://en.wikipedia.org/wiki/multiple_render_targets).
Wenn MTIVertex nicht Ihren Anforderungen entsprechen kann, können Sie das MTIGeometry -Protokoll implementieren, um Ihre benutzerdefinierten Vertex -Daten dem Befehlscodierer anzugeben.
Verwenden Sie die MTIRenderCommand -API, um Zeichnen von Anrufen auszugeben und Ihre benutzerdefinierte MTIGeometry zu übergeben.
In seltenen Szenarien möchten Sie möglicherweise direkt auf die zugrunde liegende Textur zugreifen, mehrere MPS -Kernel in einem Render -Pass verwenden, 3D -Rendering durchführen oder die Render -Befehle selbst codieren.
MTIImagePromise -Protokoll bietet einen direkten Zugriff auf die zugrunde liegende Textur und den Render -Kontext für einen Schritt in Metalpetal.
Sie können neue Eingangsquellen oder vollständig benutzerdefinierte Verarbeitungseinheiten erstellen, indem Sie das MTIImagePromise -Protokoll implementieren. Sie müssen dazu ein zusätzliches Modul importieren.
Ziel-C
@import MetalPetal.Extension;
Schnell
// CocoaPods
import MetalPetal.Extension
// Swift Package Manager
import MetalPetalObjectiveC.Extension
Siehe beispielsweise die Implementierung von MTIComputePipelineKernel , MTICLAHELUTRecipe oder MTIImage .
Wenn in einem Bild ein Alpha -Kanal verwendet wird, gibt es zwei gemeinsame Darstellungen, die verfügbar sind: unkomultierter (gerade/nicht assoziiertes) Alpha und Prämultiplied (Associated) Alpha.
Bei unträmtierendem Alpha repräsentieren die RGB -Komponenten die Farbe des Pixels und ignorieren ihre Deckkraft.
Mit dem Prämultiplied Alpha repräsentieren die RGB -Komponenten die Farbe des Pixels, die für ihre Deckkraft durch Multiplikation angepasst werden.
Metalpetal verarbeitet den Alpha -Typ explizit. Sie sind dafür verantwortlich, den richtigen Alpha -Typ während der Bilderstellung bereitzustellen.
Es gibt drei Alpha -Typen in Metalpetal.
MTIAlphaType.nonPremultiplied : Der Alpha -Wert im Bild wird nicht vorbeugend.
MTIAlphaType.premultiplied : Der Alpha -Wert im Bild wird vorteilt.
MTIAlphaType.alphaIsOne : Es gibt keinen Alpha -Kanal im Bild oder das Bild ist undurchsichtig.
Typischerweise haben CGImage , CVPixelBuffer und CIImage -Objekte die Präparate Alpha -Kanäle. MTIAlphaType.alphaIsOne wird dringend empfohlen, wenn das Bild undurchsichtig ist, z. B. ein CVPixelBuffer aus der Kamera -Feed oder ein CGImage das aus einer jpg -Datei geladen wird.
Sie können unpremultiplyingAlpha() oder premultiplyingAlpha() auf einem MTIImage anrufen, um den Alpha -Typ des Bildes zu konvertieren.
Aus Leistungsgründen erfolgt die Validierung des Alpha -Typs nur im Debug -Build.
Die meisten Filter in Metalpetal akzeptieren unkomultierte Alpha- und undurchsichtige Bilder und geben unkomultiplimierte Alpha -Bilder aus.
Filter mit outputAlphaType -Eigenschaft akzeptieren Eingänge aller Alpha -Typen. Und Sie können outputAlphaType verwenden, um den Alpha -Typ des Ausgangsbildes anzugeben.
MTIBlendFilter MTIMultilayerCompositingFilter MTICoreImageUnaryFilter MTIRGBColorSpaceConversionFilter
Filter, die die Farben nicht ändern, haben die Passie -Alpha -Handhabungsregel. Dies bedeutet, dass die Alpha -Typen der Ausgabebilder mit den Eingabebildern gleich sind.
z. B. MTITransformFilter , MTICropFilter , MTIPixellateFilter , MTIBulgeDistortionFilter
Weitere Informationen zu Alpha -Typen und Alpha -Kompositionen finden Sie in diesem erstaunlichen interaktiven Artikel von Bartosz Ciechanowski.
Farbräume sind für die Bildverarbeitung von entscheidender Bedeutung. Die numerischen Werte der rot-, grün- und blauen Komponenten haben ohne Farbraum keine Bedeutung.
Bevor Sie fortsetzen, wie Metalpetal Farbräume umgeht, möchten Sie vielleicht wissen, was ein Farbraum ist und wie er die Darstellung von Farbwerten beeinflusst. Es gibt viele Artikel im Web, in denen Farbräume erklärt werden, um loszulegen. Der Vorschlag ist Farbräume - von Bartosz Ciechanowski.
Verschiedene Software und Frameworks haben unterschiedliche Möglichkeiten, Farbräume zu handhaben. Beispielsweise verfügt Photoshop über einen Standard-SRGB IEC61966-2.1 Working Color Space, während das Kernbild standardmäßig einen linearen SRGB-Arbeitsbereich verwendet.
Metalltexturen speichern keine Farbrauminformationen mit ihnen. Der größte Teil des Farbraumhandlings in Metalpetal erfolgt während der Eingabe ( MTIImage(...) ) und der Ausgabe ( MTIContext.render... ) von Bilddaten.
Wenn Sie einen Farbraum für eine Eingabe angeben, bedeutet dies, dass Metalpetal die Quellfarbwerte während der Erstellung der Textur in den angegebenen Farbraum umwandeln sollte.
Beim Laden von URL oder CGImage können Sie angeben, in welchem Farbraum Sie die Texturdaten verwenden möchten, verwenden Sie unter Verwendung von MTICGImageLoadingOptions . Wenn Sie beim Laden eines Bildes keine Optionen angeben, wird der Geräte -RGB -Farbraum verwendet ( MTICGImageLoadingOptions.default ). Ein nil -Farbraum deaktiviert die Farbanpassung. Dies entspricht der Verwendung des Farbraums des Eingabebildes, um MTICGImageLoadingOptions zu erstellen. Wenn das Modell des angegebenen Farbraums kein RGB ist, wird der Gerät RGB -Farbraum als Fallback verwendet.
Wenn Sie vom CIImage geladen werden, können Sie angeben, in welchem Farbraum Sie die Texturdaten verwenden möchten, unter Verwendung von MTICIImageRenderingOptions . Wenn Sie beim Laden eines CIImage keine Optionen angeben, wird der Gerät RGB -Farbraum verwendet ( MTICIImageRenderingOptions.default ). Ein nil -Farbraum deaktiviert die Farbanpassung, Farbwerte werden im funktionierenden Farbraum des CIContext geladen.
Bei der Angabe eines Farbraums für einen Ausgang dient der Farbraum eher wie ein Tag, mit dem mit dem Rest des Systems über die Darstellung der Farbwerte in der Ausgabe kommuniziert wird. Es wird keine tatsächliche Umwandlung des Farbraums durchgeführt.
Sie können den Farbraum eines CGImage unter Verwendung von MTIContext.makeCGImage... oder MTIContext.startTaskTo... -Methoden mit einem colorSpace -Parameter angeben.
Sie können den Farbraum eines Ausgangs CIImage unter Verwendung MTICIImageCreationOptions angeben.
Metalpetal geht davon aus, dass sich die Ausgangsfarbwerte im Gerät RGB -Farbraum befinden, wenn kein Ausgangsfarbraum angegeben ist.
CVPixelBuffer Metalpetal verwendet CVMetalTextureCache und IOSurface , um CVPixelBuffer direkt auf Metalltexturen zu kartieren. Sie können also keinen Farbraum zum Laden von oder zum Rendern eines CVPixelBuffer angeben. Sie können jedoch angeben, ob eine Textur mit einem SRGB -Pixelformat für die Zuordnung verwendet werden soll.
Wenn der Name des Pixelformates das _sRGB -Suffix hat, werden während des Lesens und des Schreibens von Farbwerten im Pixel die SRGB -Gamma -Komprimierung und -Dekompression angewendet. Das bedeutet, dass eine Textur mit dem _sRGB -Pixelformat vorausgeht, dass die Farbwerte, die sie speichern, srgb gamma korrigiert werden, wenn die Farbwerte in einem Shader gelesen werden, werden SRGB -zu linearer RGB -Konvertierungen durchgeführt. Wenn die Farbwerte in einem Shader geschrieben sind, werden lineare RGB -zu -SRGB -Konvertierungen durchgeführt.
Sie können MTIRGBColorSpaceConversionFilter verwenden, um Color Space Conversions durchzuführen. Farbraum -Konvertierungsfunktionen sind auch in MTIShaderLib.h erhältlich.
metalpetal::sRGBToLinear (SRGB IEC61966-2.1 bis linear SRGB)metalpetal::linearToSRGB (lineares SRGB an SRGB IEC61966-2.1)metalpetal::linearToITUR709 (linearer SRGB zu ITU-R 709)metalpetal::ITUR709ToLinear (ITU-R 709 bis linear SRGB) Sie können MTISCNSceneRenderer verwenden, um MTIImage S von einer SCNScene zu generieren. Möglicherweise möchten Sie den linearen RGB -Farbraum des Szenenkit -Renderers verarbeiten, siehe Ausgabe Nr. 76 Das Bild von SceneKit ist dunkler als normal.
Sie können MTISKSceneRenderer verwenden, um MTIImage S von einem SKScene zu generieren.
Sie können MTIImage s aus CIImage s erstellen.
Sie können ein MTIImage mit einem MTIContext zu einem CIImage bringen.
Sie können einen CIFilter direkt mit MTICoreImageKernel oder der MTICoreImageUnaryFilter -Klasse verwenden. (Nur schnell)
Siehe Metalpetaljs
Mit Metalpetaljs können Sie mit JavaScript Render -Pipelines und Filter erstellen, um Ihre Filter/Renderer aus "der Cloud" herunterzuladen.
Es wird empfohlen, APIs zu verwenden, die MTICGImageLoadingOptions akzeptieren, um CGImage S und Bilder von URL zu laden, anstatt APIs zu verwenden, die MTKTextureLoaderOption akzeptieren.
Wenn Sie APIs verwenden, die MTKTextureLoaderOption akzeptieren, verwendet Metalpetal standardmäßig MTIDefaultTextureLoader , um CGImage S, Bilder aus URL und benannte Bilder zu laden. MTIDefaultTextureLoader verwendet MTKTextureLoader intern und verfügt über einige Problemumgehungen für die Inkonsistenzen und Fehler von MTKTextureLoader zu kleinen Leistungskosten. Sie können auch Ihren eigenen Texturloader erstellen, indem Sie das MTITextureLoader -Protokoll implementieren. Weisen Sie dann Ihre Texturloaderklasse MTIContextOptions.textureLoaderClass bei, wenn Sie einen MTIContext erstellen.
Sie können Cocoapods verwenden, um die neueste Version zu installieren.
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'
SwiftBietet schnell spezifische Ergänzungen und Änderungen an den Objektiv-C-APIs, um ihre Zuordnung in Swift zu verbessern. Sehr zu empfehlen, wenn Sie Swift verwenden.
AppleSiliconBietet die Standard -Shader -Bibliothek, die in der Metallschattierungssprache v2.3 zusammengestellt wurde, die für die Aktivierung programmierbarer Mischbetriebsunterstützung auf Apple Silicon Macs erforderlich ist.
Hinzufügen von Paketabhängigkeiten zu Ihrer App
Metalpetal kann mit Xcode 11+ und macOS 10.15+ auf Simulator ausgeführt werden.
MetalPerformanceShaders.framework ist bei Simulator nicht verfügbar. Filter, die auf MetalPerformanceShaders wie MTIMPSGaussianBlurFilter , MTICLAHEFilter , angewiesen sind, funktionieren nicht.
Simulator unterstützt weniger Funktionen oder unterschiedliche Implementierungsgrenzen als eine tatsächliche Apple -GPU. Weitere Details finden Sie in der Entwicklung von Metall -Apps, die in Simulator ausgeführt werden.
Wenn Sie einen kurzen Blick auf ein MTIImage ansehen, werden Ihnen das Bilddiagramm angezeigt, das Sie konstruiert haben, um dieses Bild zu erstellen.

Warum Objective-C?
Vielen Dank, dass Sie überlegt haben, zu Metalpetal beizutragen. Bitte lesen Sie unsere beitragenden Richtlinien.
Metalpetal ist MIT-lizenziert. LIZENZ
Die Dateien im Verzeichnis /MetalPetalExamples sind unter einer separaten Lizenz lizenziert. Lizenz.MD
Die Dokumentation ist lizenziert CC-BY-4.0.