2017-10-20 23 views
5

Tôi đang gọi phương thức ủy nhiệm của AVFoundation để xử lý việc chụp ảnh, nhưng tôi gặp khó khăn khi chuyển đổi AVCapturePhoto mà nó tạo thành một UIImage với định hướng chính xác. Mặc dù thường trình bên dưới thành công, tôi luôn có được UIImage đúng hướng (UIImage.imageOrientation = 3). Tôi không có cách nào cung cấp định hướng khi sử dụng UIImage (dữ liệu: hình ảnh) và cố gắng sử dụng đầu tiên photo.cgImageRepresentation() ?. takeRetainedValue() cũng không giúp ích gì. Xin vui lòng giúp đỡ.Cách tạo UIImage từ AVCapturePhoto với định hướng chính xác?

Hướng hình ảnh là rất quan trọng ở đây vì hình ảnh kết quả đang được cung cấp cho luồng công việc Khung hình.

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: Reading của Apple Photo Capture Programming Guide (hết hạn cho iOS11), tôi đã quản lý để tìm một điều tôi đã làm sai:

  1. Trên mỗi cuộc gọi chụp (self.capturePhotoOutput .capturePhoto) người ta phải thiết lập kết nối với đối tượng PhotoOutput và cập nhật hướng của nó để phù hợp với hướng của thiết bị tại thời điểm chụp ảnh. Để làm điều đó, tôi đã tạo ra một phần mở rộng của UIDeviceOrientation và sử dụng nó trên hàm snapPhoto() mà tôi đã tạo để gọi thường trình capture và đợi phương thức delegate didFinishProcessingPhoto được thực hiện. Tôi đã thêm một bản chụp các mã vì các phân cách mẫu mã ở đây dường như không hiển thị chúng một cách chính xác. enter image description here enter image description here

Cập nhật 2 Liên kết với dự án đầy đủ trên GitHub: https://github.com/agu3rra/Out-Loud

+0

Thú vị, và có thể là một [lỗi nộp] (http://bugreport.apple.com). Liệu nó cũng có vẻ bỏ qua định hướng nếu bạn ghi dữ liệu đó vào một tệp và sử dụng trình khởi tạo 'UIImage' dựa trên tệp không? – rickster

+0

Sau khi tôi đã thêm cuộc gọi kết nối vào thói quen snapPhoto() (CẬP NHẬT 1), nó không còn bỏ qua định hướng nữa, nhưng nó cho tôi trở lại các giá trị định hướng không chính xác trên UIImage mà tôi tạo ra. –

+1

Giới thiệu về tiện ích mở rộng định hướng của bạn. Apple đã phát hành AVCam cập nhật. Có một phần mở rộng tương tự. 'extension UIDeviceOrientation { var videoĐăng ký: AVCaptureVideoOrientation? { tắc tự { trường hợp .portrait: trở về .portrait trường hợp .portraitUpsideDown: return .portraitUpsideDown trường hợp .landscapeLeft: trở về .landscapeRight trường hợp .landscapeRight: return .landscapeLeft mặc định: trở về con số không }} } ' –

Trả lời

1

Bên trong AVCapturePhoto Tôi khá chắc chắn rằng bạn sẽ tìm thấy một đối tượng metadata của còn gọi là CGImageProperties.
Bên trong nó, bạn sẽ tìm thấy từ điển EXIF ​​để định hướng bước tiếp theo là chỉ lấy hướng và tạo hình ảnh theo đó.
Tôi không có kinh nghiệm sử dụng AVCapturePhotoOutput nhưng tôi có một số cách sử dụng theo cách cũ.
Chú ý rằng từ điển EXIF ​​được ánh xạ khác nhau trong UIImageOrientation.
Đây là article Tôi đã viết rất nhiều thời gian trước đây, nhưng nguyên tắc chính vẫn còn hiệu lực.
Điều này question sẽ chỉ cho bạn một số triển khai, nó quá cũ, tôi khá chắc chắn rằng trong phiên bản mới nhất họ phát hành API dễ dàng hơn, nhưng nó vẫn sẽ hướng dẫn bạn đưa vấn đề.

2

cuối cùng cập nhật: Tôi chạy một số thí nghiệm với ứng dụng và đi đến kết luận sau:

  1. kCGImagePropertyOrientation dường như không ảnh hưởng đến định hướng của hình ảnh được chụp bên trong ứng dụng của bạn và nó chỉ thay đổi theo hướng thiết bị nếu bạn cập nhật kết nối PhotoOutput mỗi khi bạn chuẩn bị gọi phương thức capturePhoto.Vì vậy:

    func snapPhoto() {// chuẩn bị và bắt đầu chụp ảnh thường xuyên

    // 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. Xem những hình ảnh tạo ra trên debugger đã cho thấy tôi làm thế nào họ nhận được tạo ra, vì vậy tôi có thể phỏng đoán xoay vòng yêu cầu (UIImageOrientation) để làm cho nó được hiển thị thẳng đứng. Nói cách khác: cập nhật UIImageOrientation cho biết cách xoay hình ảnh để bạn có thể nhìn thấy hình ảnh theo đúng hướng. Vì vậy, tôi đã đến bảng sau: Which UIImageOrientation to apply according to how the device was at the time of capture

  3. tôi phải cập nhật phần mở rộng UIDeviceOrientation của tôi đến một hình thức khá unintuitive:

    mở rộng UIDeviceOrientation { func getUIImageOrientationFromDevice() -> UIImageOrientation {// trả lại CGImagePropertyOrientation dựa trên Định hướng Thiết bị // Chức năng mở rộng này đã được xác định dựa trên thử nghiệm với cách hiển thị UII. tắc tự { trường hợp UIDeviceOrientation.portrait, .faceUp: return UIImageOrientation.right trường hợp UIDeviceOrientation.portraitUpsideDown, .faceDown: return UIImageOrientation.left trường hợp UIDeviceOrientation.landscapeLeft: return UIImageOrientation.up // đây là định hướng cơ sở trường hợp UIDeviceOrientation .landscapeRight: return UIImageOrientation.down trường hợp UIDeviceOrientation.unknown: return UIImageOrientation.up }} }

  4. Đây là cách phương pháp đại biểu cuối cùng của tôi trông bây giờ. Nó hiển thị hình ảnh theo hướng mong đợi.

    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)") 
    } 
    
Các vấn đề liên quan