2012-04-17 39 views
16

Tôi đang tạo một ứng dụng mà tôi muốn chụp ảnh từ máy ảnh mặt trước mà không cần hiển thị màn hình chụp bất kỳ loại nào. Tôi muốn chụp ảnh hoàn toàn bằng mã mà không cần bất kỳ sự tương tác nào của người dùng. Làm thế nào tôi sẽ làm điều này cho máy ảnh mặt trước?iOS: Chụp ảnh từ máy ảnh mặt trước

+2

Bạn có nghĩa là âm thầm chụp ảnh mà không cho người sử dụng biết anyt hing về nó? – rid

+2

Vâng, tôi biết nó nghe có vẻ xấu nhưng hoàn toàn vô hại. Ứng dụng này sẽ khiến họ kéo mặt buồn cười và tôi muốn chụp nó để họ có thể thấy chúng trông ngớ ngẩn như thế nào. – mtmurdock

+1

Việc bạn thực hiện một tính năng như vậy có thể vô hại, nhưng tôi có thể nghĩ đến rất nhiều trường hợp khác mà nó sẽ là bất kỳ thứ gì nhưng (đó có thể là lý do tại sao nó không thể). – inkedmn

Trả lời

3

Có thể bạn cần sử dụng AVFoundation để quay luồng/hình ảnh video mà không hiển thị. Không giống như UIImagePickerController, nó không hoạt động 'out-of-the-box'. Hãy nhìn vào ví dụ AVCam của Apple để giúp bạn bắt đầu.

41

Làm thế nào để chụp ảnh bằng cách sử dụng AVFoundation ở mặt trước máy ảnh:

Phát triển Hãy cẩn thận:

  • Kiểm tra cài đặt ứng dụng và định hướng hình ảnh của bạn một cách cẩn thận
  • AVFoundation và các khuôn khổ liên quan của nó là kếch xù khó chịu và rất khó hiểu/thực hiện. Tôi đã thực hiện mã của tôi như nạc càng tốt, nhưng hãy kiểm tra hướng dẫn này tuyệt vời cho một lời giải thích tốt hơn (trang web không cung cấp bất kỳ hơn, liên kết thông qua archive.org): http://www.benjaminloulier.com/posts/ios4-and-direct-access-to-the-camera

ViewController.h

// Frameworks 
#import <CoreVideo/CoreVideo.h> 
#import <CoreMedia/CoreMedia.h> 
#import <AVFoundation/AVFoundation.h> 
#import <UIKit/UIKit.h> 

@interface CameraViewController : UIViewController <AVCaptureVideoDataOutputSampleBufferDelegate> 

// Camera 
@property (weak, nonatomic) IBOutlet UIImageView* cameraImageView; 
@property (strong, nonatomic) AVCaptureDevice* device; 
@property (strong, nonatomic) AVCaptureSession* captureSession; 
@property (strong, nonatomic) AVCaptureVideoPreviewLayer* previewLayer; 
@property (strong, nonatomic) UIImage* cameraImage; 

@end 

ViewController.m

#import "CameraViewController.h" 

@implementation CameraViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    [self setupCamera]; 
    [self setupTimer]; 
} 

- (void)setupCamera 
{  
    NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; 
    for(AVCaptureDevice *device in devices) 
    { 
     if([device position] == AVCaptureDevicePositionFront) 
      self.device = device; 
    } 

    AVCaptureDeviceInput* input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil]; 
    AVCaptureVideoDataOutput* output = [[AVCaptureVideoDataOutput alloc] init]; 
    output.alwaysDiscardsLateVideoFrames = YES; 

    dispatch_queue_t queue; 
    queue = dispatch_queue_create("cameraQueue", NULL); 
    [output setSampleBufferDelegate:self queue:queue]; 

    NSString* key = (NSString *) kCVPixelBufferPixelFormatTypeKey; 
    NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]; 
    NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key]; 
    [output setVideoSettings:videoSettings]; 

    self.captureSession = [[AVCaptureSession alloc] init]; 
    [self.captureSession addInput:input]; 
    [self.captureSession addOutput:output]; 
    [self.captureSession setSessionPreset:AVCaptureSessionPresetPhoto]; 

    self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession]; 
    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; 

    // CHECK FOR YOUR APP 
    self.previewLayer.frame = CGRectMake(0, 0, self.view.frame.size.height, self.view.frame.size.width); 
    self.previewLayer.orientation = AVCaptureVideoOrientationLandscapeRight; 
    // CHECK FOR YOUR APP 

    [self.view.layer insertSublayer:self.previewLayer atIndex:0]; // Comment-out to hide preview layer 

    [self.captureSession startRunning]; 
} 

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 
{ 
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    CVPixelBufferLockBaseAddress(imageBuffer,0); 
    uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer); 
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 
    CGImageRef newImage = CGBitmapContextCreateImage(newContext); 

    CGContextRelease(newContext); 
    CGColorSpaceRelease(colorSpace); 

    self.cameraImage = [UIImage imageWithCGImage:newImage scale:1.0f orientation:UIImageOrientationDownMirrored]; 

    CGImageRelease(newImage); 

    CVPixelBufferUnlockBaseAddress(imageBuffer,0); 
} 

- (void)setupTimer 
{ 
    NSTimer* cameraTimer = [NSTimer scheduledTimerWithTimeInterval:2.0f target:self selector:@selector(snapshot) userInfo:nil repeats:YES]; 
} 

- (void)snapshot 
{ 
    NSLog(@"SNAPSHOT"); 
    self.cameraImageView.image = self.cameraImage; // Comment-out to hide snapshot 
} 

@end 

Connect này lên đến một UIViewController với một UIImageView cho ảnh chụp và nó sẽ làm việc! Ảnh chụp nhanh được thực hiện theo chương trình ở khoảng thời gian 2.0 giây mà không có bất kỳ đầu vào nào của người dùng. Nhận xét các dòng được chọn để xóa lớp xem trước và phản hồi ảnh chụp nhanh.

Mọi câu hỏi/nhận xét khác, vui lòng cho tôi biết!

+1

Rất đẹp! Tôi muốn đề nghị câu trả lời này được chấp nhận trên mỏ (giả sử nó hoạt động). – Tim

+0

Đây có phải là Apple App Store thân thiện không? – mtmurdock

+1

Tôi không chắc chắn, đây là lần đầu tiên tôi nghĩ về một ứng dụng như thế này. Tôi đoán bạn sẽ cần phải đào sâu vào bản in đẹp và thực sự làm cho người dùng/Apple biết rằng nó không được sử dụng cho bất kỳ mục đích nham hiểm nào (như đã đề cập trong các bài viết khác ở đây). Ứng dụng của bạn có vẻ vui nhộn và vô hại, vì vậy có thể nó sẽ ổn thôi! –

0

Có một phương thức gọi là takePicture trong tài liệu cho lớp UIImagePickerController. Nó nói:

Sử dụng phương pháp này cùng với chế độ xem lớp phủ tùy chỉnh để bắt đầu chụp ảnh có lập trình của hình ảnh tĩnh. Điều này hỗ trợ chụp nhiều ảnh mà không cần rời khỏi giao diện, nhưng yêu cầu bạn ẩn các điều khiển bộ chọn hình ảnh mặc định.

2

tôi chuyển mã trên từ ObjC để Swift 3, nếu có ai vẫn tìm kiếm một giải pháp trong 2017.

import UIKit 
import AVFoundation 

class CameraViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate { 

@IBOutlet weak var cameraImageView: UIImageView! 

var device: AVCaptureDevice? 
var captureSession: AVCaptureSession? 
var previewLayer: AVCaptureVideoPreviewLayer? 
var cameraImage: UIImage? 

override func viewDidLoad() { 
    super.viewDidLoad() 

    setupCamera() 
    setupTimer() 
} 

func setupCamera() { 
    let discoverySession = AVCaptureDeviceDiscoverySession(deviceTypes: [.builtInWideAngleCamera], 
                  mediaType: AVMediaTypeVideo, 
                  position: .front) 
    device = discoverySession?.devices[0] 

    let input: AVCaptureDeviceInput 
    do { 
     input = try AVCaptureDeviceInput(device: device) 
    } catch { 
     return 
    } 

    let output = AVCaptureVideoDataOutput() 
    output.alwaysDiscardsLateVideoFrames = true 

    let queue = DispatchQueue(label: "cameraQueue") 
    output.setSampleBufferDelegate(self, queue: queue) 
    output.videoSettings = [kCVPixelBufferPixelFormatTypeKey as AnyHashable: kCVPixelFormatType_32BGRA] 

    captureSession = AVCaptureSession() 
    captureSession?.addInput(input) 
    captureSession?.addOutput(output) 
    captureSession?.sessionPreset = AVCaptureSessionPresetPhoto 

    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) 
    previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill 

    previewLayer?.frame = CGRect(x: 0.0, y: 0.0, width: view.frame.width, height: view.frame.height) 

    view.layer.insertSublayer(previewLayer!, at: 0) 

    captureSession?.startRunning() 
} 

func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) { 
    let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) 
    CVPixelBufferLockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: .allZeros)) 
    let baseAddress = UnsafeMutableRawPointer(CVPixelBufferGetBaseAddress(imageBuffer!)) 
    let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!) 
    let width = CVPixelBufferGetWidth(imageBuffer!) 
    let height = CVPixelBufferGetHeight(imageBuffer!) 

    let colorSpace = CGColorSpaceCreateDeviceRGB() 
    let newContext = CGContext(data: baseAddress, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: 
     CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue) 

    let newImage = newContext!.makeImage() 
    cameraImage = UIImage(cgImage: newImage!) 

    CVPixelBufferUnlockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: .allZeros)) 
} 

func setupTimer() { 
    _ = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(snapshot), userInfo: nil, repeats: true) 
} 

func snapshot() { 
    print("SNAPSHOT") 
    cameraImageView.image = cameraImage 
} 
} 

Ngoài ra, tôi tìm thấy một giải pháp ngắn hơn để nhận được hình ảnh từ CMSampleBuffer:

func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) { 
    let myPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) 
    let myCIimage = CIImage(cvPixelBuffer: myPixelBuffer!) 
    let videoImage = UIImage(ciImage: myCIimage) 
    cameraImage = videoImage 
} 
+2

Cảm ơn, điều này khá hữu ích như một điểm khởi đầu. –

+0

Không có vấn đề gì, tôi rất vui vì nó rất hữu ích, không thực sự biết nếu nó vẫn hoạt động với Swift 4 mà không xuất hiện cảnh báo .. –

+0

Không chỉ cảnh báo, một số thứ cần phải được thay đổi, nhưng sửa chữa hầu hết là xử lý nó. –

0

Chuyển đổi trên mã để Swift 4

import UIKit 
import AVFoundation 

class CameraViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate { 

@IBOutlet weak var cameraImageView: UIImageView! 

var device: AVCaptureDevice? 
var captureSession: AVCaptureSession? 
var previewLayer: AVCaptureVideoPreviewLayer? 
var cameraImage: UIImage? 

override func viewDidLoad() { 
    super.viewDidLoad() 

    setupCamera() 
    setupTimer() 
} 

func setupCamera() { 
    let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], 
                  mediaType: AVMediaType.video, 
                  position: .front) 
    device = discoverySession.devices[0] 

    let input: AVCaptureDeviceInput 
    do { 
     input = try AVCaptureDeviceInput(device: device!) 
    } catch { 
     return 
    } 

    let output = AVCaptureVideoDataOutput() 
    output.alwaysDiscardsLateVideoFrames = true 

    let queue = DispatchQueue(label: "cameraQueue") 
    output.setSampleBufferDelegate(self, queue: queue) 
    output.videoSettings = [kCVPixelBufferPixelFormatTypeKey as AnyHashable as! String: kCVPixelFormatType_32BGRA] 

    captureSession = AVCaptureSession() 
    captureSession?.addInput(input) 
    captureSession?.addOutput(output) 
    captureSession?.sessionPreset = AVCaptureSession.Preset.photo 

    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession!) 
    previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill 
    previewLayer?.frame = CGRect(x: 0.0, y: 0.0, width: view.frame.width, height: view.frame.height) 

    view.layer.insertSublayer(previewLayer!, at: 0) 

     captureSession?.startRunning() 
    } 

    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) { 
     let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) 
    CVPixelBufferLockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0)) 
     let baseAddress = UnsafeMutableRawPointer(CVPixelBufferGetBaseAddress(imageBuffer!)) 
     let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!) 
     let width = CVPixelBufferGetWidth(imageBuffer!) 
     let height = CVPixelBufferGetHeight(imageBuffer!) 

     let colorSpace = CGColorSpaceCreateDeviceRGB() 
     let newContext = CGContext(data: baseAddress, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: 
     CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue) 

     let newImage = newContext!.makeImage() 
     cameraImage = UIImage(cgImage: newImage!) 

     CVPixelBufferUnlockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0)) 
    } 

    func setupTimer() { 
     _ = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(snapshot), userInfo: nil, repeats: true) 
    } 

    @objc func snapshot() { 
     print("SNAPSHOT") 
     cameraImageView.image = cameraImage 
    } 
} 
Các vấn đề liên quan