Frage

Ich habe ein Stück Code, dass Sätze auf eine Aufnahmesitzung von der Kamera, den Rahmen mit OpenCV zu verarbeiten und dann stellen Sie die Bildeigenschaft eines UIImageView mit einem generierten UIImage aus dem Rahmen. Wenn die App gestartet wird, das Bild der Bildansicht ist gleich Null und keine Frames anzeigen, bis ich eine andere Ansicht-Controller auf den Stapel schieben und es dann aus Pop. Dann bleibt das Bild unverändert, bis ich es wieder tun. NSLog Aussagen zeigen, dass der Rückruf bei etwa der korrekten Frame-Rate genannt wird. Irgendwelche Ideen, warum es wird nicht angezeigt? Ich reduzierte die Fps den ganzen Weg bis zu 2 Bildern pro Sekunde. Ist es nicht schnell genug verarbeiten?

Hier ist der Code:

- (void)setupCaptureSession {
    NSError *error = nil;

    // Create the session
    AVCaptureSession *session = [[AVCaptureSession alloc] init];

    // Configure the session to produce lower resolution video frames, if your 
    // processing algorithm can cope. We'll specify medium quality for the
    // chosen device.
    session.sessionPreset = AVCaptureSessionPresetLow;

    // Find a suitable AVCaptureDevice
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    // Create a device input with the device and add it to the session.
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device 
                                                                        error:&error];
    if (!input) {
        // Handling the error appropriately.
    }
    [session addInput:input];

    // Create a VideoDataOutput and add it to the session
    AVCaptureVideoDataOutput *output = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
    output.alwaysDiscardsLateVideoFrames = YES;
    [session addOutput:output];

    // Configure your output.
    dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);
    [output setSampleBufferDelegate:self queue:queue];
    dispatch_release(queue);

    // Specify the pixel format
    output.videoSettings = 
    [NSDictionary dictionaryWithObject:
     [NSNumber numberWithInt:kCVPixelFormatType_32BGRA] 
                                forKey:(id)kCVPixelBufferPixelFormatTypeKey];


    // If you wish to cap the frame rate to a known value, such as 15 fps, set 
    // minFrameDuration.
    output.minFrameDuration = CMTimeMake(1, 1);

    // Start the session running to start the flow of data
    [session startRunning];

    // Assign session to an ivar.
    [self setSession:session];
}

// Create a UIImage from sample buffer data
- (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer {
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    // Lock the base address of the pixel buffer
    CVPixelBufferLockBaseAddress(imageBuffer,0);

    // Get the number of bytes per row for the pixel buffer
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    // Get the pixel buffer width and height
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 

    // Create a device-dependent RGB color space
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    if (!colorSpace) 
     {
        NSLog(@"CGColorSpaceCreateDeviceRGB failure");
        return nil;
     }

    // Get the base address of the pixel buffer
    void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
    // Get the data size for contiguous planes of the pixel buffer.
    size_t bufferSize = CVPixelBufferGetDataSize(imageBuffer); 

    // Create a Quartz direct-access data provider that uses data we supply
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, baseAddress, bufferSize, 
                                                              NULL);
    // Create a bitmap image from data supplied by our data provider
    CGImageRef cgImage = 
    CGImageCreate(width,
                  height,
                  8,
                  32,
                  bytesPerRow,
                  colorSpace,
                  kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little,
                  provider,
                  NULL,
                  true,
                  kCGRenderingIntentDefault);
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpace);

    // Create and return an image object representing the specified Quartz image
    UIImage *image = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);

    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);

    return image;
}


// Delegate routine that is called when a sample buffer was written
- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
       fromConnection:(AVCaptureConnection *)connection {
    // Create a UIImage from the sample buffer data
    UIImage *image = [self imageFromSampleBuffer:sampleBuffer];
    [self.delegate cameraCaptureGotFrame:image];
}
War es hilfreich?

Lösung

Dies zu Threading-Versuche in Verbindung stehen könnte:

[self.delegate performSelectorOnMainThread:@selector(cameraCaptureGotFrame:) withObject:image waitUntilDone:NO];

Andere Tipps

Das sieht wie ein Threading-Problem. Sie können nicht Ihre Ansichten in einem anderen Thread als im Hauptthread aktualisieren. In Ihrem Setup, was gut ist, die Delegatfunktion captureOutput: didOutputSampleBuffer: wird in einem sekundären Thread genannt. So können Sie die Bildansicht von dort nicht einstellen. Art Gillespies Antwort ist eine Möglichkeit, es zu lösen, wenn Sie loswerden der schlechten Zugriffsfehler erhalten.

Eine andere Möglichkeit ist es, die Probenpuffer in captureOutput zu ändern: didOutputSampleBuffer: und haben durch das Hinzufügen einer gezeigt AVCaptureVideoPreviewLayer Instanz auf Ihre Capture-Sitzung. Das ist sicherlich die bevorzugte Art und Weise, wenn Sie nur einen kleinen Teil des Bildes ändern, wie Hervorhebung etwas.

BTW:. Ihre schlechten Zugriffsfehler auftreten könnten, weil Sie das erstellte Bild im sekundären Thread nicht behalten und deshalb vor dem befreit werden cameraCaptureGotFrame ist auf dem Haupt-Thread genannt

Aktualisieren : Um richtig das Bild zu behalten, erhöhen den Referenzzähler in captureOutput: didOutputSampleBuffer: (im Sekundärgewinde) oder vermindern, in cameraCaptureGotFrame:. (im Hauptthread)

// Delegate routine that is called when a sample buffer was written
- (void)captureOutput:(AVCaptureOutput *)captureOutput 
        didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
        fromConnection:(AVCaptureConnection *)connection
{
    // Create a UIImage from the sample buffer data
    UIImage *image = [self imageFromSampleBuffer:sampleBuffer];

    // increment ref count
    [image retain];
    [self.delegate performSelectorOnMainThread:@selector(cameraCaptureGotFrame:)
        withObject:image waitUntilDone:NO];

}

- (void) cameraCaptureGotFrame:(UIImage*)image
{
    // whatever this function does, e.g.:
    imageView.image = image;

    // decrement ref count
    [image release];
}

Wenn Sie den Referenzzähler nicht erhöhen, wird das Bild durch den Auto-Release-Pool des zweiten Thread vor dem cameraCaptureGotFrame befreit wird: ist im Hauptthread genannt. Wenn Sie es nicht im Hauptthread verringern, werden die Bilder nie befreit und Sie laufen innerhalb weniger Sekunden von Speicher aus.

Machst du eine setNeedsDisplay auf der UIImageView nach jeder neuen Bildeigenschaft Update?

Edit:

Wo und wann aktualisieren Sie das Hintergrundbild Eigenschaft in Ihrem Bild Ansicht?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top