2017-10-20 3 views
5

Ich rufe die Delegate-Methode von AVFoundation auf, um eine Fotoaufnahme zu verarbeiten, aber ich habe Schwierigkeiten, das von ihr generierte AVCapturePhoto in ein UIImage mit der richtigen Ausrichtung zu konvertieren. Obwohl die folgende Routine erfolgreich ist, bekomme ich immer eine rechtsgerichtete UIImage (UIImage.imageOrientation = 3). Ich habe keine Möglichkeit, eine Orientierung zu geben, wenn ich die UIImage (data: image) benutze und versuche, zuerst photo.cgImageRepresentation() zu benutzen.takeRetainedValue() hilft auch nicht. Bitte helfen.Wie erzeuge ich ein UIImage von AVCapturePhoto mit korrekter Ausrichtung?

Die Bildausrichtung ist hier entscheidend, da das resultierende Bild in einen Vision Framework-Workflow eingespeist wird.

func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { 
    // capture image finished 
    print("Image captured.") 
    if let imageData = photo.fileDataRepresentation() { 
     if let uiImage = UIImage(data: imageData){ 
      // do stuff to UIImage 
     } 
    } 
} 

UPDATE 1: Lesen Apples Photo Capture Programming Guide (veraltet für iOS11), ich habe es geschafft, eine Sache zu finden war ich falsch gemacht:

  1. Auf jeder Capture-Aufruf (self.capturePhotoOutput .capturePhoto) muss eine Verbindung mit dem PhotoOutput-Objekt hergestellt und die Ausrichtung aktualisiert werden, damit sie der Ausrichtung des Geräts in dem Moment entspricht, in dem das Bild aufgenommen wird. Dafür habe ich eine Erweiterung von UIDeviceOrientation erstellt und sie in der Funktion snapPhoto() verwendet, die ich erstellt habe, um die Erfassungsroutine aufzurufen und darauf zu warten, dass die didFinishProcessingPhoto-Delegate-Methode ausgeführt wird. Ich habe eine Momentaufnahme der Codes hinzugefügt, da die Codebeispiel-Trennzeichen hier nicht korrekt angezeigt werden. enter image description here enter image description here

Update 2 Link zum vollständigen Projekt auf GitHub: https://github.com/agu3rra/Out-Loud

+0

Interessante und möglicherweise ein [Fehler in Datei] (http://bugreport.apple.com). Scheint es auch, die Ausrichtung zu ignorieren, wenn Sie diese Daten in eine Datei schreiben und einen dateibasierten 'UIImage'-Initialisierer verwenden? – rickster

+0

Nachdem ich den Verbindungsaufruf für die snapPhoto() - Routine (UPDATE 1) hinzugefügt habe, ignoriert er nicht mehr die Ausrichtung, sondern gibt mir falsche Orientierungswerte für das von mir erstellte UII zurück. –

+1

Über Ihre Ausrichtungserweiterung. Apple hat AVCam aktualisiert veröffentlicht. Es gibt eine ähnliche Erweiterung. 'Erweiterung UIDeviceOrientation { var videoOrientation: AVCaptureVideoOrientation? { Schalter selbst { Fall .portrait: return .portrait Fall .portraitUpsideDown: .portraitUpsideDown Fall .landscapeLeft zurück: Rückkehr .landscapeRight Fall .landscapeRight: return .landscapeLeft default: return null } } } ' –

Antwort

1

Im Inneren des AVCapturePhoto Ich bin ziemlich sicher, erhalten Sie eine metadata Aufgabe der auch CGImageProperties genannt finden.
Darin finden Sie das EXIF-Wörterbuch zur Orientierung. Der nächste Schritt besteht darin, die Orientierung zu nehmen und ein entsprechendes Bild zu erstellen.
Ich habe keine Erfahrungen in der Verwendung von AVCapturePhotoOutput, aber ich habe einige mit der alten Art und Weise.
Beachten Sie, dass das EXIF-Wörterbuch in UIImageOrientation anders zugeordnet ist.
Hier ist ein article Ich habe vor langer Zeit geschrieben, aber das Hauptprinzip ist immer noch gültig.
Diese question wird Sie auf einige Implementierungen verweisen, es ist ziemlich alt, ich bin mir ziemlich sicher, dass in der neuesten Version leichter API veröffentlicht, aber es wird Sie immer noch in das Problem führen.

2

Schluss Update: lief ich einige Experimente mit der App und kam zu folgenden Ergebnissen:

  1. kCGImagePropertyOrientation scheint nicht die Ausrichtung des aufgenommenen Bildes in Ihrer Anwendung und es zu beeinflussen nur variiert mit der Geräteausrichtung, wenn Sie Ihre photoOutput-Verbindung jedes Mal aktualisieren, wenn Sie die capturePhoto-Methode aufrufen.Also:

    func snapPhoto() {// vorbereiten und einleiten Bildaufnahme Routine

    // if I leave the next 4 lines commented, the intented orientation of the image on display will be 6 (right top) - kCGImagePropertyOrientation 
    let deviceOrientation = UIDevice.current.orientation // retrieve current orientation from the device 
    guard let photoOutputConnection = capturePhotoOutput.connection(with: AVMediaType.video) else {fatalError("Unable to establish input>output connection")}// setup a connection that manages input > output 
    guard let videoOrientation = deviceOrientation.getAVCaptureVideoOrientationFromDevice() else {return} 
    photoOutputConnection.videoOrientation = videoOrientation // update photo's output connection to match device's orientation 
    
    let photoSettings = AVCapturePhotoSettings() 
    photoSettings.isAutoStillImageStabilizationEnabled = true 
    photoSettings.isHighResolutionPhotoEnabled = true 
    photoSettings.flashMode = .auto 
    self.capturePhotoOutput.capturePhoto(with: photoSettings, delegate: self) // trigger image capture. It appears to work only if the capture session is running. 
    

    }

  2. Anzeigen der erzeugten Bilder auf dem Debugger mir gezeigt hat, wie sie erzeugt werden, so dass ich könnte die erforderliche Rotation (UIImageOrientation) ableiten, um sie aufrecht zu zeigen. Mit anderen Worten: Durch die Aktualisierung von UIImageOrientation erfahren Sie, wie das Bild gedreht werden sollte, damit Sie es in der richtigen Ausrichtung sehen können. So kam ich auf die folgende Tabelle: Which UIImageOrientation to apply according to how the device was at the time of capture

  3. Ich musste meine UIDeviceOrientation Erweiterung auf eine eher unintuitive Form aktualisieren:

    Erweiterung UIDeviceOrientation { func getUIImageOrientationFromDevice() -> UIImageOrientation { // return CGImagePropertyOrientation basiert on Device Orientation // Diese erweiterte Funktion wurde basierend auf Experimenten mit der Anzeige eines UIImage bestimmt. Schalter selbst { Fall UIDeviceOrientation.portrait, .faceUp: UIImageOrientation.right Fall UIDeviceOrientation.portraitUpsideDown, .faceDown zurück: return UIImageOrientation.left Fall UIDeviceOrientation.landscapeLeft: UIImageOrientation.up zurück // dies ist die Grundorientierung Fall UIDeviceOrientation .landscapeRight: return UIImageOrientation.down Fall UIDeviceOrientation.unknown: return UIImageOrientation.up } } }

  4. Dies ist, wie meine letzte Delegatmethode jetzt aussieht. Es zeigt das Bild in der erwarteten Ausrichtung an.

    func photoOutput(_ output: AVCapturePhotoOutput, 
               didFinishProcessingPhoto photo: AVCapturePhoto, 
               error: Error?) 
    { 
        // capture image finished 
        print("Image captured.") 
    
        let photoMetadata = photo.metadata 
        // Returns corresponting NSCFNumber. It seems to specify the origin of the image 
        //    print("Metadata orientation: ",photoMetadata["Orientation"]) 
    
        // Returns corresponting NSCFNumber. It seems to specify the origin of the image 
        print("Metadata orientation with key: ",photoMetadata[String(kCGImagePropertyOrientation)] as Any) 
    
        guard let imageData = photo.fileDataRepresentation() else { 
         print("Error while generating image from photo capture data."); 
         self.lastPhoto = nil; self.controller.goToProcessing(); 
         return 
    
        } 
    
        guard let uiImage = UIImage(data: imageData) else { 
         print("Unable to generate UIImage from image data."); 
         self.lastPhoto = nil; self.controller.goToProcessing(); 
         return 
    
        } 
    
        // generate a corresponding CGImage 
        guard let cgImage = uiImage.cgImage else { 
         print("Error generating CGImage");self.lastPhoto=nil;return 
    
        } 
    
        guard let deviceOrientationOnCapture = self.deviceOrientationOnCapture else { 
         print("Error retrieving orientation on capture");self.lastPhoto=nil; 
         return 
    
        } 
    
        self.lastPhoto = UIImage(cgImage: cgImage, scale: 1.0, orientation: deviceOrientationOnCapture.getUIImageOrientationFromDevice()) 
    
        print(self.lastPhoto) 
        print("UIImage generated. Orientation:(self.lastPhoto.imageOrientation.rawValue)") 
        self.controller.goToProcessing() 
    } 
    
    
    func photoOutput(_ output: AVCapturePhotoOutput, 
            willBeginCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings) 
            { 
        print("Just about to take a photo.") 
        // get device orientation on capture 
        self.deviceOrientationOnCapture = UIDevice.current.orientation 
        print("Device orientation: \(self.deviceOrientationOnCapture.rawValue)") 
    } 
    
Verwandte Themen