2014-10-07 5 views
13

Ich schreibe eine App, die eine Echtzeit-Videoverarbeitung unter Verwendung einer AVCaptureSession mit einer AVCaptureVideoDataOutput als Ausgabe und einer AVCaptureDeviceInput mit der Videodatei (es muss nicht mehr in Echtzeit sein) als Eingabe.Wie verwende ich AVCaptureSession, um ein Video aus einer Datei zu lesen?

Ist es möglich, die Videodatei als Eingabe an die AVCaptureSession anstelle der Kamera zu verwenden? Wenn es nicht möglich ist, was ist die beste Methode, um eine Video-Datei mit Video-Capture von opencv on iOS (entweder gleichzeitig oder nacheinander) zu verarbeiten?

Antwort

1

Da Sie Zugriff auf die RAW-Videodateirahmen haben (von Ihrem AVCaptureVideoDataOutput), können Sie jeden Rahmen in ein cv::Mat Objekt konvertieren (eine opencv-Matrix, die ein Bild darstellt). Dann mach deine Bildbearbeitung an jedem einzelnen Frame.

Überprüfen Sie https://developer.apple.com/library/ios/qa/qa1702/_index.html für ein Echtzeitbeispiel mit der Kamera; Sie können Ihre UIImage in eine cv::Mat mit cvMatFromUIImage konvertieren.

0

So stellt sich heraus, es ist nicht zu schwierig zu tun. Die Grundzüge ist:

  1. eine cv::VideoCapture erstellen aus einer Datei lesen
  2. erstellen CALayer zu empfangen und jedes Bild angezeigt werden soll.
  3. Führen Sie eine Methode mit einer bestimmten Rate aus, die jeden Frame liest und verarbeitet.
  4. Sobald die Verarbeitung abgeschlossen ist, wandeln Sie jede cv::Mat in eine CGImageRef um und zeigen Sie sie auf der CALayer an.

Die eigentliche Implementierung ist wie folgt:

Schritt 1: Erstellen cv :: Videocapture

std::string filename = "/Path/To/Video/File"; 
capture = cv::VideoCapture(filename); 
if(!capture.isOpened()) NSLog(@"Could not open file.mov"); 

Schritt 2: Erstellen Sie die Ausgabe CALayer

self.previewLayer = [CALayer layer]; 
self.previewLayer.frame = CGRectMake(0, 0, width, height); 
[self.view.layer addSublayer:self.previewLayer]; 

Schritt 3: Erstellen Verarbeitungsschleife w/GCD

int kFPS = 30; 

dispatch_queue_t queue = dispatch_queue_create("timer", 0); 
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); 
dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, 0), (1/kFPS) * NSEC_PER_SEC, (0.5/kFPS) * NSEC_PER_SEC); 

dispatch_source_set_event_handler(self.timer, ^{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self processNextFrame]; 
    }); 
}); 

dispatch_resume(self.timer); 

Schritt 4: Verarbeitungsmethode

-(void)processNextFrame { 
    /* Read */ 
    cv::Mat frame; 
    capture.read(frame); 

    /* Process */ 
    ... 

    /* Convert and Output to CALayer*/ 
    cvtColor(frame, frame, CV_BGR2RGB); 
    NSData *data = [NSData dataWithBytes:frame.data 
           length:frame.elemSize()*frame.total()]; 

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGBitmapInfo bitmapInfo = (frame.elemSize() == 3) ? kCGImageAlphaNone : kCGImageAlphaNoneSkipFirst; 
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef) data); 

    CGImageRef imageRef = CGImageCreate(frame.cols, 
             frame.rows, 
             8, 
             8 * frame.elemSize(), 
             frame.step[0], 
             colorSpace, 
             bitmapInfo, 
             provider, 
             NULL, 
             false, 
             kCGRenderingIntentDefault); 

    self.previewLayer.contents = (__bridge id)imageRef; 

    CGImageRelease(imageRef); 
    CGColorSpaceRelease(colorSpace); 
} 
Verwandte Themen