2017-09-28 7 views
0

Ich bin ein Bachelor-Student und ich benutze jetzt CoreML Frame, um einige Video HumanSeg App auf dem iPhone zu tun, aber wie der Titel zeigt, habe ich ein Huuuuge Problem .CVPixelBuffer Schreiben mit UIImage.draw() ist zu langsam

Ich habe eine UIImage und ich muss Größe und Pad und es in einen CVPixelBuffer ziehen, um das MobileNet-Modell zu füttern, aber ein solcher Prozess ist einfach zu langsam, kostet etwa 30 ms, was nicht akzeptabel ist.

Um genau zu sein, In meinem Code, Methode UIImage.draw (in: CGRect (X: Int, y: Int, Breite: Int, Höhe: Int)) ist zu langsam, und nahm mich 20+ ms, die ist das Hauptproblem.

Meine Codes sind unten:

func dealRawImage(image : UIImage, dstshape : [Int], pad : UIImage) -> CVPixelBuffer? 
{ 
    // decide whether to shrink in height or width 
    let height = image.size.height 
    let width = image.size.width 
    let ratio = width/height 
    let dst_width = Int(min(CGFloat(dstshape[1]) * ratio, CGFloat(dstshape[0]))) 
    let dst_height = Int(min(CGFloat(dstshape[0])/ratio, CGFloat(dstshape[1]))) 
    let origin = [Int((dstshape[0] - dst_height)/2), Int((dstshape[1] - dst_width)/2)] 

    // init a pixelBuffer to store the resized & padded image 
    var pixelBuffer: CVPixelBuffer? 
    let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, 
       kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] 
    CVPixelBufferCreate(kCFAllocatorDefault, 
         dstshape[1], 
         dstshape[0], 
         kCVPixelFormatType_32ARGB, 
         attrs as CFDictionary, 
         &pixelBuffer) 

    // get the pointer of this pixelBuffer 
    CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) 
    let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer!) 

    // init a context that contains this pixelBuffer to draw in 
    let context = CGContext(data: pixelData, 
          width: dstshape[1], 
          height: dstshape[0], 
          bitsPerComponent: 8, 
          bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!), 
          space: CGColorSpaceCreateDeviceRGB(), 
          bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue)! 

    // push context 
    UIGraphicsPushContext(context) 
    context.translateBy(x: 0, y: CGFloat(dstshape[0])) 
    context.scaleBy(x: 1, y: -1) 

    pad.draw(in:CGRect(x: 0, y: 0, width: dstshape[1], height: dstshape[0])) 
    // THIS SINGLE FUNCTION COSTS ME 20+ ms AND IS THE MAJOR ISSUE ! 
    image.draw(in: CGRect(x: origin[1], y: origin[0], width: dst_width, height: dst_height)) 

    UIGraphicsPopContext() 

    // unlock 
    CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) 

    return pixelBuffer 
} 

Und ich rufe einfach diese Funktion wie folgt aus:

let input = dealRawImage(image: raw_input_image, dstshape: [224, 224], pad: black_image) 

Wo raw_input_image die UIImage I aus dem Speicher gelesen, dstshape ist die Form, die ich möchte, um die Größe Dieses Bild zu, und Black_image ist eine völlig schwarze UIImage zum Auffüllen verwendet.

Ich habe auf dieser Website gesucht, aber kein bekanntes Problem gefunden.

Gibt es eine Möglichkeit, diesen Prozess schneller zu machen und dieses Projekt zu speichern? Ich möchte meine zweiwöchige Arbeit einfach nicht aufgeben.

+1

Ich bin nicht sicher, warum die Zeile mit 'image.draw()' ist so viel langsamer als 'pad.draw()' [möglicherweise wegen der Größenänderung] aber zwei Fragen in den Sinn kommen hier: 1) warum Sie müssen auf das Eingabebild padding? 2) Wenn Sie Geschwindigkeit brauchen, warum sind Ihre Eingabedaten in einem UIImage? –

+0

Oh, eine Sache, die ich versuchen würde, macht 'image.draw()' verwenden 0, 0 und die volle Breite und Höhe, und sehen, ob das schneller ist. –

+0

Danke. Und lassen Sie mich zuerst Ihre Fragen beantworten. 1) Ich habe das trainierte MoblieNet-Modell aus meinem Labor bekommen, und meine Senioren haben beim Training dieses Modells die schwarze Polsterung zum Bild gemacht, also muss ich das auch machen, damit dieses Netz korrekt läuft. 2) Ich bin nicht sicher, was ich verwenden kann, wenn ich Bilder von iPhone Kamera oder Album auswählen muss. Ich habe auch versucht, opencv-swift zu benutzen, aber da war etwas nicht in Ordnung und ich kam am Ende zu UIImage zurück. 3) Meinst du, dass die Verwendung anderer Bildformate einen CVPixelBuffer schneller erzeugen kann? – AXIHIXA

Antwort

1

Es ist schon eine Weile her, seit ich mich mit CVPixelBuffer s befasst habe, und ich habe noch nicht CoreML verwendet.

Wenn ich tat arbeite mit CVPixelBuffer s, fand ich, dass ich die beste Leistung durch die Schaffung eines einzigen Pixel-Puffer bei der Zielgröße und halten es herum. Ich nahm Pixel von der Kamera, übergab sie als Textur an OpenGL, manipulierte sie und ordnete die Ausgabe in den gleichen CVPixelBuffer ein. Ich konnte die gleiche Speicherstruktur für all das verwenden. Ich schlage vor, diesen Ansatz zu wählen.

+0

Ja, aber obwohl ich einen CVPixelBuffer erstelle und ihn im gesamten Projekt verwende, ist das Schreiben von Daten immer noch zu langsam. In der Tat, um einen zu erstellen, brauche ich nur 9 ms, aber um UIImage Daten zu schreiben (mit draw() Methode) brauche ich 20+ ms und das ist das Hauptproblem, denke ich. Gibt es eine Lösung? – AXIHIXA

+1

Verwenden Sie OpenGL oder Metall und zeichnen Sie Texturen mit dem Pixel-Puffer, der als Ausgabe des OpenGL-Kontexts festgelegt wurde. Es ist so lange her, dass ich an diesem Zeug gearbeitet habe, an das ich mich nicht mal mehr erinnern kann. –

+0

In meiner App kann ich Frames von der Kamera nehmen, sie Texturen zuordnen, eine "Mesh Warp" auf der Textur machen, die Ausgabe zurück zu einem Pixelpuffer mappen und mit vollen 60 fps auf den Bildschirm rendern. –