我正在使用 iPhone/iPad 摄像头获取视频流并在流上进行识别,但随着照明的变化,它会对鲁棒性产生负面影响。我已经在不同的光线下测试了不同的设置并且可以让它工作,但是我需要在运行时调整设置。
我可以在每一帧上计算一个简单的亮度检查,但是相机会调整并抛出我的结果。我可以观察急剧的变化并进行检查,但渐进的变化也会使我的结果失效。
理想情况下,我想访问流的相机/EXIF数据,看看它注册了未过滤的亮度,有没有办法做到这一点?
(我正在为 iOS 5 及更高版本的设备工作)
谢谢
我正在使用 iPhone/iPad 摄像头获取视频流并在流上进行识别,但随着照明的变化,它会对鲁棒性产生负面影响。我已经在不同的光线下测试了不同的设置并且可以让它工作,但是我需要在运行时调整设置。
我可以在每一帧上计算一个简单的亮度检查,但是相机会调整并抛出我的结果。我可以观察急剧的变化并进行检查,但渐进的变化也会使我的结果失效。
理想情况下,我想访问流的相机/EXIF数据,看看它注册了未过滤的亮度,有没有办法做到这一点?
(我正在为 iOS 5 及更高版本的设备工作)
谢谢
适用于 iOS 4.0 及更高版本。可以从 CMSampleBufferRef 获取 EXIF 信息。
//Import ImageIO & include framework in your project.
#import <ImageIO/CGImageProperties.h>
在您的示例缓冲区委托中,免费桥接将从 CoreMedia 的 CMGetAttachment 获得结果的 NSDictionary。
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
NSDictionary* dict = (NSDictionary*)CMGetAttachment(sampleBuffer, kCGImagePropertyExifDictionary, NULL);
完整的代码,在我自己的应用程序中使用:
- (void)setupAVCapture {
//-- Setup Capture Session.
_session = [[AVCaptureSession alloc] init];
[_session beginConfiguration];
//-- Set preset session size.
[_session setSessionPreset:AVCaptureSessionPreset1920x1080];
//-- Creata a video device and input from that Device. Add the input to the capture session.
AVCaptureDevice * videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if(videoDevice == nil)
assert(0);
//-- Add the device to the session.
NSError *error;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
if(error)
assert(0);
[_session addInput:input];
//-- Create the output for the capture session.
AVCaptureVideoDataOutput * dataOutput = [[AVCaptureVideoDataOutput alloc] init];
[dataOutput setAlwaysDiscardsLateVideoFrames:YES]; // Probably want to set this to NO when recording
//-- Set to YUV420.
[dataOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange]
forKey:(id)kCVPixelBufferPixelFormatTypeKey]]; // Necessary for manual preview
// Set dispatch to be on the main thread so OpenGL can do things with the data
[dataOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
[_session addOutput:dataOutput];
[_session commitConfiguration];
[_session startRunning];
}
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL,
sampleBuffer, kCMAttachmentMode_ShouldPropagate);
NSDictionary *metadata = [[NSMutableDictionary alloc]
initWithDictionary:(__bridge NSDictionary*)metadataDict];
CFRelease(metadataDict);
NSDictionary *exifMetadata = [[metadata
objectForKey:(NSString *)kCGImagePropertyExifDictionary] mutableCopy];
self.autoBrightness = [[exifMetadata
objectForKey:(NSString *)kCGImagePropertyExifBrightnessValue] floatValue];
float oldMin = -4.639957; // dark
float oldMax = 4.639957; // light
if (self.autoBrightness > oldMax) oldMax = self.autoBrightness; // adjust oldMax if brighter than expected oldMax
self.lumaThreshold = ((self.autoBrightness - oldMin) * ((3.0 - 1.0) / (oldMax - oldMin))) + 1.0;
NSLog(@"brightnessValue %f", self.autoBrightness);
NSLog(@"lumaThreshold %f", self.lumaThreshold);
}
lumaThreshold 变量作为统一变量发送到我的片段着色器,它将 Y 采样器纹理相乘以根据环境的亮度找到理想的亮度。现在,它使用后置摄像头;我可能会切换到前置摄像头,因为我只是更改屏幕的“亮度”以适应室内/室外观看,并且用户的眼睛在摄像头的前面(而不是后面)。