2017-10-20 8 views
5

사진 캡처를 처리하기 위해 AVFoundation의 대리자 메서드를 호출하지만 정확한 방향으로 UIImage로 생성하는 AVCapturePhoto를 변환하는 데 어려움을 겪고 있습니다. 아래 루틴이 성공했지만, 나는 항상 올바른 방향의 UIImage (UIImage.imageOrientation = 3)를 얻는다. UIImage (데이터 : 이미지)를 사용하고 photo.cgImageRepresentation()을 처음 사용할 때 오리엔테이션을 제공 할 방법이 없습니다. takeRetainedValue()도 도움이되지 않습니다. 도와주세요.올바른 방향으로 AVCapturePhoto에서 UIImage를 생성하는 방법은 무엇입니까?

결과 이미지가 Vision Framework 워크 플로로 공급되는 동안 이미지 방향이 중요합니다.

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 : 읽기 애플의 Photo Capture Programming Guide (iOS11에 대한 유효 기간), 내가 잘못하고 있던 한 가지를 찾아 관리 않았다 (모든 캡처 호출에

  1. self.capturePhotoOutput .capturePhoto) PhotoOutput 객체와의 연결을 설정하고 사진을 찍을 때 장치 방향에 맞게 방향을 업데이트해야합니다. 이를 위해 UIDeviceOrientation의 확장을 생성하고 capture 루틴을 호출하고 didFinishProcessingPhoto 대리자 메소드가 실행될 때까지 기다리기 위해 만든 snapPhoto() 함수에 사용했습니다. 여기에 코드 샘플 구분 기호가 올바르게 표시되지 않는 것 때문에 코드의 스냅 샷을 추가했습니다. enter image description here enter image description here

2 링크 GitHub의에 전체 프로젝트에 업데이트 : 난 당신이 또한 CGImageProperties 전화의 metadata 개체를 찾을 것입니다 확신 해요 AVCapturePhoto 내부 https://github.com/agu3rra/Out-Loud

+0

흥미과 가능성 [버그 파일로 (http://bugreport.apple.com). 파일에 데이터를 쓰고 파일 기반'UIImage' 이니셜 라이저를 사용하면 방향을 무시하는 것처럼 보입니까? – rickster

+0

snapPhoto() 루틴 (UPDATE 1)에서 연결 호출을 추가 한 후에 더 이상 방향을 무시하지 않지만 다시 UIImage에서 잘못된 방향 값을 제공합니다. –

+1

오리엔테이션 확장에 관하여. Apple은 AVCam을 업데이트했습니다. 유사한 확장 기능이 있습니다. 'extension UIDeviceOrientation { var videoOrientation : AVCaptureVideoOrientation? { 스위치 자체는 { 경우 .portrait : 반환 .portrait 경우 .portraitUpsideDown : .portraitUpsideDown 경우 .landscapeLeft를 반환 : 반환 경우 .landscapeRight .landscapeRight : 반환 .landscapeLeft을 기본 : 리턴 } 전무} }' –

답변

1

.
안에는 EXIF ​​사전을 찾을 수 있습니다. 다음 단계는 방향을 잡고 그것에 따라 이미지를 만드는 것입니다.
AVCapturePhotoOutput을 사용해 본 경험이 없지만 이전 방법을 사용하고 있습니다.
EXIF ​​사전이 UIImageOrientation에서 다르게 매핑된다는 점에 유의하십시오.
저는 많은 시간 전에 쓴 article입니다,하지만 주된 원칙은 여전히 ​​유효합니다. 이 question은 몇 가지 구현을 가리키며 꽤 오래된 API이지만 최신 API에서는 더 쉽게 API를 출시했지만 여전히 문제를 해결하도록 안내합니다.

2

최종 업데이트 : 나는 응용 프로그램 몇 가지 실험을 실행하고 다음과 같은 결론에 온 :

  1. kCGImagePropertyOrientation 응용 프로그램과 그 안에 캡처 된 이미지의 방향에 영향을하지 않는 것

    만 capturePhoto 메서드를 호출 할 때마다 photoOutput 연결을 업데이트하면 장치 방향에 따라 다릅니다.그래서 :

    FUNC의 snapPhoto() 디버거에서 생성 된 이미지보기

  2. 가 생성되는 방법을 나에게 보여 주었다 {준비하고

    // 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. 
    

    일상적인 이미지 캡처 시작 // }는, 그래서 필요한 회전 (UIImageOrientation)이 수직으로 표시되도록 유추 할 수 있습니다. 즉, UIImageOrientation을 업데이트하면 올바른 방향으로 이미지를 볼 수 있도록 이미지를 어떻게 회전해야하는지 알려줍니다. UIImageOrientation가 { //이 CGImagePropertyOrientation 기반 Return>을 -

    확장 UIDeviceOrientation { FUNC의 getUIImageOrientationFromDevice() : Which UIImageOrientation to apply according to how the device was at the time of capture

  3. 나는 오히려 직관적 형태로 내 UIDeviceOrientation 확장을 업데이트했다 : 그래서 다음 표에 와서 on 장치 오리엔테이션 //이 확장 기능은 UIImage가 어떻게 표시되는지에 대한 실험을 기반으로 결정되었습니다. 스위치 자체 { 경우 UIDeviceOrientation.portrait, .faceUp는 : UIImageOrientation.right 경우 UIDeviceOrientation.portraitUpsideDown, .faceDown를 리턴 : 리턴 UIImageOrientation.left 경우 UIDeviceOrientation.landscapeLeft는 : UIImageOrientation.up를 리턴 //이 기본 방향이다 케이스 UIDeviceOrientation .landscapeRight : 반환 UIImageOrientation.down 경우 UIDeviceOrientation.unknown가 : UIImageOrientation.up } } }를 반환

  4. 이 내 마지막 위임 방법은 지금 모습입니다. 예상 된 방향으로 이미지를 표시합니다.

    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)") 
    }