Tworzę aplikację, w której chciałbym uchwycić obraz z przedniej kamery, bez pokazywania jakiegokolwiek ekranu przechwytywania. Chcę zrobić zdjęcie całkowicie w kodzie bez interakcji użytkownika. Jak mam to zrobić dla kamery z widokiem z przodu?iOS: Przechwyć obraz z kamery skierowanej do przodu
Odpowiedz
Prawdopodobnie trzeba użyć AVFoundation
, aby przechwycić strumień wideo/obraz bez jego wyświetlania. W przeciwieństwie do UIImagePickerController
, nie działa "out-of-the-box". Spójrz na przykład na Apple AVCam
, aby zacząć.
Jak zrobić zdjęcie za pomocą Przednia kamera AVFoundation:
Development Ostrzeżenia:
- sprawdzić ustawienia aplikacji i orientację obrazu starannie
- AVFoundation i związane z nią ramy są paskudne molochów i bardzo trudne do zrozumienia/wdrożenia. Zrobiłem mój kod jak chude jak to możliwe, ale proszę sprawdzić to doskonały poradnik dla lepszego wyjaśnienia (strona internetowa nie jest dostępna dłużej, łącza poprzez 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
Podłącz się do UIViewController z UIImageView dla migawka i będzie działać! Migawki są wykonywane programowo w odstępach 2,0 sekundy bez wprowadzania danych przez użytkownika. Skomentuj wybrane linie, aby usunąć warstwę podglądu i informacje o obrazie.
Wszelkie dodatkowe pytania/komentarze, proszę dać mi znać!
Bardzo ładne! Polecam, aby ta odpowiedź była akceptowana nad moją (zakładając, że działa). – Tim
Czy to będzie przyjazny dla Apple App Store? – mtmurdock
Nie jestem pewien, po raz pierwszy zastanowiłem się nad taką aplikacją. Sądzę, że musiałbyś zagłębić się w drobny druk i naprawdę sprawić, że użytkownik/Apple dowie się, że nie jest wykorzystywany do złowieszczych celów (jak wspomniano w innych postach tutaj). Twoja aplikacja brzmi zabawnie i nieszkodliwie, więc może będzie dobrze! –
Istnieje metoda o nazwie takePicture w dokumentach dla klasy UIImagePickerController. Jest napisane:
Użyj tej metody w połączeniu z niestandardowym widokiem nakładki, aby zainicjować programowe przechwytywanie nieruchomego obrazu. Umożliwia to wykonanie więcej niż jednego obrazu bez opuszczania interfejsu, ale wymaga ukrycia domyślnych elementów sterujących selektora obrazu.
konwertowane powyższy kod z objc do Swift 3, jeśli ktoś nadal szuka rozwiązania w 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
}
}
Również znalazłem krótszy rozwiązanie dla uzyskania obrazu z 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
}
Dzięki, to było całkiem przydatne jako punkt wyjścia. –
Nie ma problemu, cieszę się, że było użyteczne, nie wiem, czy nadal działa z Swift 4 bez pojawiania się ostrzeżeń. –
Nie tylko ostrzeżenia, niektóre rzeczy muszą zostać zmienione, ale poprawka - najczęściej to robi. –
Konwersja powyżej kodu 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
}
}
- 1. Zapobieganie odbijaniu skierowanej do przodu kamery
- 2. ios dodaj tablicę do tablicy z przodu
- 3. Niewystarczające zasoby systemowe, przechwyć wideo z kamery internetowej Java
- 4. iOS Niestandardowy UIImagePickerController Przycinanie kamery do kwadratu
- 5. Przechwyć obraz, gdy urządzenie jest zablokowane hasłem
- 6. sposób ustawiania zoomu kamery z frontem z szybkim avfoundation
- 7. Aplikacja Cordova - czy można wyświetlać obraz z kamery w pojemniku?
- 8. iOS: orientacja kamery
- 9. Sesja kamery zwraca mały obraz
- 10. Przechowuj obraz z kamery do prywatnego katalogu pamięci podręcznej aplikacji.
- 11. Ekran Przechwyć z CGDisplayStream
- 12. iOS: Kadrowanie obrazu nieruchomego pobranego z kamery UIImagePickerController z nakładką
- 13. Przechwyć RGB z Kinnect z Openni i pokaż z OpenCV
- 14. Do przodu FFT obraz i do tyłu FFT obraz, aby uzyskać ten sam wynik
- 15. IOS: jak wysłać widok obrazu z powrotem i z przodu
- 16. Jak przesłać obraz produktu z przodu w Magento
- 17. Przechwyć wyślij formularz z jQuery
- 18. Odwróć port do przodu za pomocą biblioteki libssh2 na iOS
- 19. Obraz z kamery systemu Android powinien zostać obrócony po przechwyceniu?
- 20. Obraz z kamery ma wartość zerową, jeśli kamera jest obrócona
- 21. Port Apache do przodu
- 22. Obraz tła iOS 6
- 23. Prześlij obraz do serwisu WWW w ios
- 24. Niska jakość obrazu/obrazu podczas przechwytywania z kamery
- 25. Sprężyna do przodu z dodanymi parametrami?
- 26. Przechwyć argument w Mockito
- 27. Przechwyć UIView jako UIImage
- 28. iOS: załaduj obraz z adresu URL
- 29. Jak wyświetlać RTSP z kamery IP/CCTV w iOS
- 30. Metody rozszerzeń do przodu kompatybilne
Masz na myśli po cichu przechwycić obraz bez wiedzy użytkownika anyt o tym porozmawiać? – rid
Tak, wiem, że to brzmi źle, ale jest całkowicie nieszkodliwe. Aplikacja sprawi, że będą przyciągać zabawną twarz i chcę ją uchwycić, aby mogli zobaczyć, jak wyglądają głupio. – mtmurdock
Twoja implementacja takiej funkcji może być nieszkodliwa, ale mogę myśleć o wielu innych przypadkach, w których byłaby ona inna niż (prawdopodobnie dlatego nie jest to możliwe). – inkedmn