2016-04-28 8 views
0

Ich schrieb den folgenden Code ein Sepia-Filter auf ein Bild anwenden:Objective C verbessern CIImage Filtergeschwindigkeit

- (void)applySepiaFilter { 
    // Set previous image 
    NSData *buffer = [NSKeyedArchiver archivedDataWithRootObject: self.mainImage.image]; 
    [_images push:[NSKeyedUnarchiver unarchiveObjectWithData: buffer]]; 


    UIImage* u = self.mainImage.image; 
    CIImage *image = [[CIImage alloc] initWithCGImage:u.CGImage]; 
    CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone" 
            keysAndValues: kCIInputImageKey, image, 
         @"inputIntensity", @0.8, nil]; 
    CIImage *outputImage = [filter outputImage]; 
    self.mainImage.image = [self imageFromCIImage:outputImage]; 
} 

- (UIImage *)imageFromCIImage:(CIImage *)ciImage { 
    CIContext *ciContext = [CIContext contextWithOptions:nil]; 
    CGImageRef cgImage = [ciContext createCGImage:ciImage fromRect:[ciImage extent]]; 
    UIImage *image = [UIImage imageWithCGImage:cgImage]; 
    CGImageRelease(cgImage); 
    return image; 
} 

Wenn ich diesen Code ausführen es für 1-2 Sekunden zu hinken scheint. Ich habe gehört, dass das Kernbild schneller ist als Core-Grafiken, aber ich bin nicht beeindruckt von der Renderzeit. Ich habe mich gefragt, ob dies in CoreGraphics oder sogar OpenCV (das an anderer Stelle im Projekt verwendet wird) schneller ist? Wenn nicht, kann ich diesen Code optimieren, um schneller zu laufen?

+0

Haben Sie Instrumente benutzt, um herauszufinden, was hier eigentlich langsam ist? – zneak

+0

@zneak Welche Instrumente wären das? –

+0

Aus meinem Kopf, etwas wie "Time Profiler". – zneak

Antwort

3

Ich kann fast garantieren, dass es in Core Graphics langsamer sein wird als mit Core Image, abhängig von der Größe des Bildes. Wenn das Bild klein ist, kann Core-Grafik in Ordnung sein, aber wenn Sie viel verarbeiten, wird es viel langsamer als das Rendern mit der GPU sein.

Core Image ist sehr schnell, aber Sie müssen sehr bewusst sein, was vor sich geht. Der größte Teil der Leistung, die mit Core Image erzielt wird, ist auf das Einrichten des Kontexts und das Kopieren von Bildern von/nach Core Image zurückzuführen. Neben dem Kopieren von Bytes kann Core Image auch zwischen Bildformaten konvertieren.

Ihr Code macht folgendes jedes Mal: ​​

  • ein CIContext erstellen. (langsam)
  • Übernahme von Bytes aus einem CGImage und Erstellung eines CIImage.
  • Kopieren von Bilddaten auf GPU (langsam).
  • Verarbeitung Sepia-Filter (schnell).
  • Ergebnisbild zurück zu CGImage kopieren. (langsam)

Dies ist kein Rezept für Spitzenleistung. Bytes von CGImage werden normalerweise im CPU-Speicher gespeichert, aber Core Image möchte die GPU für die Verarbeitung verwenden.

eine hervorragende Referenz für Leistungsüberlegungen sind in Getting the Best Performance Dokumentation für Core Image zur Verfügung gestellt:

  • kein Objekt CIContext erstellen Sie jedes Mal, wenn Sie machen. Kontexte speichern viele Statusinformationen; es ist effizienter, sie wiederzuverwenden.
  • Werten Sie aus, ob Ihre App ein Farbmanagement benötigt. Benutze es nur, wenn du es brauchst. Siehe Benötigt Ihre App Farbmanagement ?.
  • Vermeiden Sie Kernanimationsanimationen, während Sie CImage-Objekte mit einem GPU-Kontext rendern. Wenn Sie beide gleichzeitig verwenden müssen, können Sie beide für die Verwendung der CPU einrichten.

  • Stellen Sie sicher, dass die Bilder die CPU- und GPU-Grenzwerte nicht überschreiten. (iOS)

  • Verwenden Sie nach Möglichkeit kleinere Bilder. Leistung skaliert mit der Anzahl der Ausgangspixel. Sie können das Core Image-Rendering in eine kleinere Ansicht, Textur oder Framebuffer rendern. Lassen Sie die Kern-Animation auf die Anzeigegröße hochskalieren.

  • Verwenden Sie Core-Grafiken oder Bild-E/A-Funktionen zum Zuschneiden oder Neuberechnen, z. B. die Funktionen CGImageCreateWithImageInRect oder CGImageSourceCreateThumbnailAtIndex.

  • Die UIImageView-Klasse funktioniert am besten mit statischen Bildern. Wenn Ihre App die beste Leistung erzielen soll, verwenden Sie untergeordnete APIs.

  • Vermeiden Sie unnötige Texturübertragungen zwischen der CPU und der GPU. Rendern Sie auf ein Rechteck, das die gleiche Größe wie das Quellbild hat, bevor Sie einen Inhaltsskalierungsfaktor anwenden.

  • Verwenden Sie einfachere Filter, die ähnliche Ergebnisse wie algorithmische Filter liefern können. Zum Beispiel kann CIColorCube ähnliche Ausgabe wie CISepiaTone produzieren, und dies effizienter.

  • Nutzen Sie die Unterstützung für YUV-Image in iOS 6.0 und höher.

Wenn Sie Echtzeit-Rechenleistung verlangen, sollten Sie eine OpenGL verwenden Ansicht, dass Coreimage kann seine Ausgabe an, machen und lesen Sie Ihr Bild direkt in die GPU-Bytes anstatt es von einem CGImage des Ziehens . Die Verwendung einer GLKView und überschreiben drawRect: ist eine ziemlich einfache Lösung, um eine Ansicht zu erhalten, auf die Core Image direkt rendern kann. Das Bewahren von Daten auf der GPU ist der beste Weg, Spitzenleistung aus Core Image herauszuholen.

Versuchen Sie, so viel wie möglich wiederzuverwenden. Halten Sie eine für nachfolgende Renderings herum (wie das Dokument sagt). Wenn Sie eine OpenGL-Ansicht verwenden, sind dies auch Dinge, die Sie so oft wie möglich wiederverwenden möchten.

Sie können möglicherweise auch bessere Leistung erzielen, indem Sie Software-Rendering verwenden. Software-Rendering würde eine Kopie von/zu GPU vermeiden. [CIContext contextWithOptions:@{kCIContextUseSoftwareRenderer: @(YES)}] Dies hat jedoch Leistungseinschränkungen im tatsächlichen Rendern, da das Rendern der CPU normalerweise langsamer ist als das Rendering einer GPU.

So können Sie Ihren Schwierigkeitsgrad wählen, um maximale Leistung zu erhalten. Die beste Leistung kann eine größere Herausforderung sein, aber einige Optimierungen können zu einer "akzeptablen" Leistung für Ihren Anwendungsfall führen.