2011-10-21 34 views
7

मैं अपने ऐप में एक कस्टम कैमरा लागू करने के लिए AVFoundation कक्षाओं का उपयोग कर रहा हूं। मैं अभी भी छवियों को कैप्चर कर रहा हूं, वीडियो नहीं। मेरे पास सब कुछ काम कर रहा है लेकिन कुछ चीज से फंस गया है। जब भी एक छवि को कैप्चर किया जाता है और वीडियो कनेक्शन को उचित रूप से वीडियो सेट किया जाता है तो मैं डिवाइस अभिविन्यास को ध्यान में रखता हूं। एक कोड स्निपेट:AVCaptureVideoOrientation लैंडस्केप मोड का परिणाम अभी भी छवियों के ऊपर क्यों है?

// set the videoOrientation based on the device orientation to 
    // ensure the pic is right side up for all orientations 
    AVCaptureVideoOrientation videoOrientation; 
    switch ([UIDevice currentDevice].orientation) { 
     case UIDeviceOrientationLandscapeLeft: 
      // Not clear why but the landscape orientations are reversed 
      // if I use AVCaptureVideoOrientationLandscapeLeft here the pic ends up upside down 
      videoOrientation = AVCaptureVideoOrientationLandscapeRight; 
      break; 
     case UIDeviceOrientationLandscapeRight: 
      // Not clear why but the landscape orientations are reversed 
      // if I use AVCaptureVideoOrientationLandscapeRight here the pic ends up upside down 
      videoOrientation = AVCaptureVideoOrientationLandscapeLeft; 
      break; 
     case UIDeviceOrientationPortraitUpsideDown: 
      videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown; 
      break; 
     default: 
      videoOrientation = AVCaptureVideoOrientationPortrait; 
      break; 
    } 

    videoConnection.videoOrientation = videoOrientation; 

परिदृश्य मामलों में मेरी टिप्पणियां नोट करें। मुझे ओरिएंटेशन मैपिंग को उलटना है या परिणामी छवि उल्टा है। मैं निम्नलिखित कोड के साथ छवि को कैप्चर और सेव करता हूं:

[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection 
    completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) 
    { 
     NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; 
     self.stillImage = [UIImage imageWithData:imageData]; 
     // notify observers (image gets saved to the camera roll)               
     [[NSNotificationCenter defaultCenter] postNotificationName:CaptureSessionManagerDidCaptureStillImageNotification object:self]; 
     self.stillImage = nil; 
}]; 

कोई अन्य छवि प्रसंस्करण या हेरफेर नहीं है।

मेरा ऐप उपरोक्त कोड के साथ काम करता है। मैं बस यह समझने की कोशिश कर रहा हूं कि अभिविन्यास स्थिरांक को परिदृश्य उन्मुखताओं के लिए क्यों उलट दिया जाना चाहिए। धन्यवाद!

+0

नजर आता है UIDevice उन्मुखीकरण का उपयोग न करें जब आप वास्तव में उपयोग करना चाहते हैं UIInterface अभिविन्यास। – Till

+0

आप इस मामले में 'UIInterface' अभिविन्यास का उपयोग नहीं कर सकते हैं। छवि को कैप्चर करने के समय डिवाइस अभिविन्यास हमेशा सही होता है। उस डेटा को कैप्चर करने के बाद 'stillImage' की छवि अभिविन्यास सही नहीं है। मैं UIDeviceOrientation का उपयोग करके इस मुद्दे को हल करने में सक्षम था और घूर्णन करते समय उचित UIImageOrientation में अनुवाद कर रहा था। उस समय, कोई भी यहाँ चिल्ला रहा था इसलिए मैंने कोड पोस्ट नहीं किया। यदि मेरे पास समय है तो मैं कोड जोड़ूंगा। – XJones

+0

@XJones, कृपया अपने उत्तर को सही समाधान के साथ अपडेट करें। – Hemang

उत्तर

20

हे, ऐसा लगता है कि किसी को इस पर चिमिंग की तरह महसूस नहीं हुआ। जवाब बदलता है सीधा है। stillImageOutput captureStillImageAsynchronouslyFromConnection:... विधि के माध्यम से कब्जा कर लिया छवियाँ हमेशा निम्नलिखित गुणों के साथ अंत:

  • UIImage उन्मुखीकरण = हमेशा UIImageOrientationRight डिवाइस अभिविन्यास की परवाह किए बिना
  • UIImage आकार = डब्ल्यू एक्स एच (जैसे चित्र चौड़ाई x चित्र ऊंचाई, अपने कैमरे पर निर्भर करता है संकल्प)
  • CGImage आकार = पर डिवाइस अभिविन्यास (जैसे पोर्ट्रेट या लैंडस्केप)

तो छवि को घुमाने के लिए समाधान के लिए CGImage आकार के साथ संयोजन के रूप में डिवाइस अभिविन्यास उपयोग करने के लिए है निर्भर करता है उचित affine परिवर्तन लागू करें। विभिन्न छवि प्रसंस्करण संवर्द्धन युक्त एक UIImage श्रेणी में

- (UIImage *)imageRotatedUpForDeviceOrientation:(UIDeviceOrientation)deviceOrientation 

: मैं अपने ही सवाल का जवाब कर रहा हूँ के रूप में, मैं कोड में समाधान नहीं कर रहा हूँ, लेकिन मैं एक नियमित बुलाया लेखन समाप्त हो गया।

संपादित करें - कार्यान्वयन उदाहरण

मैं इस पर कार्यात्मक कोड के लिए अनुरोध के एक नंबर मिला है। मैंने एक कार्यरत ऐप से प्रासंगिक कार्यान्वयन निकाला है।

// this method is implemented in your capture session manager (wherever AVCaptureSession is used) 
// capture a still image and save the device orientation 
- (void)captureStillImage 
{ 
    UIDeviceOrientation currentDeviceOrientation = UIDevice.currentDevice.orientation; 
     [self.stillImageOutput 
     captureStillImageAsynchronouslyFromConnection:self.videoConnection 
     completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) { 
      NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; 
      if (imageData) { 
       UIImage *image = [UIImage imageWithData:imageData]; 
       NSDictionary *captureInfo = { 
        @"image" : image, 
        @"deviceOrientation" : @(currentDeviceOrientation) 
       }; 
       // TODO: send image & orientation to delegate or post notification to observers 
      } 
      else { 
       // TODO: handle image capture error 
      } 
    }]; 
} 

// this method rotates the UIImage captured by the capture session manager based on the 
// device orientation when the image was captured 
- (UIImage *)imageRotatedUpFromCaptureInfo:(NSDictionary *)captureInfo 
{ 
    UIImage *image = [captureInfo objectForKey:@"image"]; 
    UIDeviceOrientation deviceOrientation = [[captureInfo objectForKey:@"deviceOrientation"] integerValue]; 
    UIImageOrientation rotationOrientation = [self rotationNeededForImageCapturedWithDeviceOrientation:deviceOrientation]; 
    // TODO: scale the image if desired 
    CGSize newSize = image.size; 
    return [imageScaledToSize:newSize andRotatedByOrientation:rotationOrientation]; 
} 

// return a scaled and rotated an image 
- (UIImage *)imageScaledToSize:(CGSize)newSize andRotatedByOrientation:(UIImageOrientation)orientation 
{ 
    CGImageRef imageRef = self.CGImage;  
    CGRect imageRect = CGRectMake(0.0, 0.0, newSize.width, newSize.height); 
    CGRect contextRect = imageRect; 
    CGAffineTransform transform = CGAffineTransformIdentity; 

    switch (orientation) 
    { 
     case UIImageOrientationDown: { // rotate 180 deg 
      transform = CGAffineTransformTranslate(transform, imageRect.size.width, imageRect.size.height); 
      transform = CGAffineTransformRotate(transform, M_PI); 
     } break; 

     case UIImageOrientationLeft: { // rotate 90 deg left 
      contextRect = CGRectTranspose(contextRect); 
      transform = CGAffineTransformTranslate(transform, imageRect.size.height, 0.0); 
      transform = CGAffineTransformRotate(transform, M_PI/2.0); 
     } break; 

     case UIImageOrientationRight: { // rotate 90 deg right 
      contextRect = CGRectTranspose(contextRect); 
      transform = CGAffineTransformTranslate(transform, 0.0, imageRect.size.width); 
      transform = CGAffineTransformRotate(transform, 3.0 * M_PI/2.0); 
     } break; 

     case UIImageOrientationUp: // no rotation 
     default: 
      break; 
    } 

    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); 
    CGColorSpaceRef colorSpaceRef = CGImageGetColorSpace(imageRef); 

    // madify bitmapInfo to work with PNG if necessary 
    if (bitmapInfo == kCGImageAlphaNone) { 
     bitmapInfo = kCGImageAlphaNoneSkipLast; 
    } 
    else if (bitmapInfo == kCGImageAlphaLast) { 
     bitmapInfo = kCGImageAlphaPremultipliedLast; 
    } 

    // Build a context that's the same dimensions as the new size 
    CGContextRef context = CGBitmapContextCreate(NULL, 
               contextRect.size.width, 
               contextRect.size.height, 
               CGImageGetBitsPerComponent(imageRef), 
               0, 
               colorSpaceRef, 
               bitmapInfo); 


    CGContextConcatCTM(context, transform); 
    CGContextDrawImage(context, imageRect, imageRef); 

    // Get the rotated image from the context and a UIImage 
    CGImageRef rotatedImageRef = CGBitmapContextCreateImage(context); 
    UIImage *rotatedImage = [UIImage imageWithCGImage:rotatedImageRef]; 

    // Clean up 
    CGImageRelease(rotatedImageRef); 
    CGContextRelease(context); 

    return rotatedImage; 
} 

// return the UIImageOrientation needed for an image captured with a specific deviceOrientation 
- (UIImageOrientation)rotationNeededForImageCapturedWithDeviceOrientation:(UIDeviceOrientation)deviceOrientation 
{ 
    UIImageOrientation rotationOrientation; 
    switch (deviceOrientation) { 
     case UIDeviceOrientationPortraitUpsideDown: { 
      rotationOrientation = UIImageOrientationLeft; 
     } break; 

     case UIDeviceOrientationLandscapeRight: { 
      rotationOrientation = UIImageOrientationDown; 
     } break; 

     case UIDeviceOrientationLandscapeLeft: { 
      rotationOrientation = UIImageOrientationUp; 
     } break; 

     case UIDeviceOrientationPortrait: 
     default: { 
      rotationOrientation = UIImageOrientationRight; 
     } break; 
    } 
    return rotationOrientation; 
} 
+7

अच्छा जवाब लेकिन कार्यान्वयन की कुछ पंक्तियां मुझे कुछ टाइपिंग बचाएंगी! 8 -) – kalperin

+3

@XJones मैं कोड की निम्न पंक्ति को समझ नहीं पाया, क्या आप कृपया मेरे लिए यह समझा सकते हैं? contextRect = CGRectTranspose (contextRect); –

+1

सीजीआरईटीटी डब्ल्यूटीएफ – jjxtra

6

के लिए तुम क्यों AVCaptureVideoOrientationLandscape सही जरूरत है जब डिवाइस का अभिविन्यास UIDeviceOrientationLandscape वाम है के रूप में, कि, क्योंकि किसी कारण से, UIDeviceOrientationLandscape वाम == UIInterfaceOrientationLandscape सही, और AVCaptureVideoOrientations अनुसरण कर रहे हैं है UIInterfaceOrientation सम्मेलन।

इसके अलावा, UIDeviceOrientation UIDeviceOrientationFaceUp, UIDeviceOrientationFaceDown, और UIDeviceOrientation अज्ञात जैसे अन्य विकल्पों को शामिल करता है। यदि आप डिवाइस के अभिविन्यास से मेल खाने के लिए अपना इंटरफ़ेस घुमा रहे हैं, तो आप इसके बजाय UIDeviceOrientation [UIApplication sharedAplication] प्राप्त कर सकते हैं .statusBarOrientation इसके बजाए।

+3

क्या यह हो सकता है कि लैंडस्केप बाएं/दाएं फ्रंट बनाम बैक कैमरे का उपयोग करने के कारण हो? – VaporwareWolf

+0

नहीं, मान दोनों फ्रंट और बैक कैमरों के बराबर हैं। –

0

असल में, आपके कार्यान्वयन में कोई गलती नहीं है और आप पूरे स्विच केस को खत्म कर सकते हैं।

स्विच मामले क्यों समाप्त किया जा सकता:

डिवाइस और वीडियो झुकाव की corressponding मूल्यों संख्यानुसार बराबर, यानी जब तक डिवाइस अभिविन्यास अज्ञात नहीं है के रूप में, का सामना या नीचे का सामना कर रहे हैं, आप कर सकते हैं समानता UIDeviceOrientation और AVCaptureVideoOrientation

भ्रामक नामकरण के बारे में:

डिवाइस उन्मुखीकरण LandscapeLeft => को आपके फोन का पी बाईं ओर है।

तो, बस कल्पना करें कि वीडियो का प्रारंभिक बिंदु कहां है ..... यह सही है, शीर्ष दाएं कोने => लैंडस्केप दाएं।

इसी तरह अन्य परिदृश्य अभिविन्यास में, वीडियो अभिविन्यास फोन के शीर्ष से दूर है। इस चित्र के मामले में भ्रमित नहीं है और उल्टा

सबूत

जब आप एक अभी भी छवि पर कब्जा उन्मुखीकरण EXIF ​​मूल्य की जाँच करें। परिदृश्य छोड़ दिया के लिए, EXIF ​​उन्मुखीकरण 3 (180 डिग्री उलट) परिदृश्य सही के लिए है, EXIF ​​उन्मुखीकरण 1 (कोई रोटेशन)

जब आप प्रदर्शित कर रहे हैं, अपने exif उन्मुखीकरण इसी UIImageOrientation में बदल जाती है, इसलिए वहाँ होना चाहिए कोई उलटा मत बनो।

फ्रंट कैमरा के मामले में, मैंने देखा है कि EXIF ​​मान, बस वीडियो अभिविन्यास मानों का पालन करें (दर्पण प्रभाव का ख्याल नहीं रखा जाता है)। EXIF के केवल 1, 3, 6, 8 मानों का उपयोग किया जाता है।

इसके अलावा, दर्पण नीचे तो करने के लिए डिवाइस के ऊपर से रेखा के साथ हमेशा होता है, परिदृश्य उल्टा लग जाएगा, जबकि चित्र और उल्टा चित्र सिर्फ

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^