iOS + AVFoundation。具有相同手动曝光设置的不同照片亮度

时间:2015-12-29 12:49:25

标签: ios camera avfoundation

我使用AVFoundation拍照。麻烦的是,即使持续设置曝光持续时间,ISO和白平衡,我也能获得不同亮度的照片。火炬,闪光灯和所有可能的稳定都被禁用。

此问题也出现在使用相机的标准Apple应用程序中:https://developer.apple.com/library/ios/samplecode/AVCam/Introduction/Intro.html#//apple_ref/doc/uid/DTS40010112

这是我通过此应用拍摄的视频,除了在会话初始化期间设置手动曝光外不包含任何更改:

https://www.youtube.com/watch?v=g9NOWGVeftI

请注意,如果数码相机的曝光设置不变,则不应突然增亮(不,不是设置曝光设置并调用完成处理程序的时刻;设置已经设置)。

亮白并非总是发生,但无论如何,如果我将相机移开并再次瞄准对象,则可能存在明显的亮度差异。但如果我在没有移动相机的情况下制作一系列照片,那么亮度是一样的。

(当然,对象的照片是在相同的光线条件下拍摄的)

可能这个增亮是设置自定义曝光设置的一部分(因为它通常在第一时间发生)而且晚期激活是我应该加速的过程,但我不知道该怎么做。

我对iPod Touch 5& amp; iPad Air。我想它也可以在其他iOS设备上发生。

场景亮度似乎影响最终图像亮度(以及预览图层的亮度)。设备不仅设置给定的曝光设置;它会根据当前场景亮度添加一些校正,并在可见场景的常见亮度发生很大变化时更改此校正。

如果我用手关闭相机,将手移开并拍照,它可能比之前没有关闭相机拍摄的照片更亮。

可能不是[仅]亮度而是对比度,因为当我将相机从白色显示器移开时,当屏幕上的[相对较暗]物体变得可见时,可以瞬间变亮。

曝光目标偏移在增亮前略小于零,在增亮后略大于零。

我认为此值是此意外调整所基于的参数(如在自动曝光模式下)。

但是,通过观察目标偏移的变化并设置相等的曝光目标偏差来阻止它的尝试失败,因为目标偏移一直在变化,并且工作相机不可能永久地改变它的目标偏差。

尝试通过设置曝光目标偏差强制进行调整,使曝光目标偏移值远离零,然后捕获也失败,因为没有任何反应,我可以在尝试补偿后获得亮度。即使在自定义模式下,目标偏差也会影响曝光偏移[对客户端可见],但它似乎不会影响负责曝光的部件中的设备行为。

我还发现在锁定曝光模式下没有亮度跳跃(或者我错过了它们......)。我尝试在设置自定义曝光值后设置此模式,但问题是在锁定模式下设备不仅可以修复当前曝光值,还可以进行初始调整以更改曝光设置。

拍摄照片后我从exif数据和AVCaptureDevice实例获得的曝光值在跳转后不会改变。我试图通过KVO观察曝光值,但没有任何可疑之处。当我设置自定义模式曝光持续时间并且ISO被更改几次然后调用完成处理程序。增亮可以晚些,但它不会影响我可以得到的当前曝光值。

一切都令人困惑。如何在图像亮度和曝光设置之间提供直接的关系?

2 个答案:

答案 0 :(得分:1)

- (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采样器纹理相乘,以根据环境的亮度找到理想的亮度。现在,它使用后置摄像头;我可能会切换到前置摄像头,因为我只是改变了亮度"用于调整室内/室外观看的屏幕,用户的眼睛位于摄像机的正面(而不是背面)。

答案 1 :(得分:0)

修补后,我想出了如何轻松锁定曝光的方法。 在主摄像机初始化期间,添加:

device.exposureMode = AVCaptureDevice.ExposureMode.custom

设备锁定配置后立即

和(非常重要)

device.exposureMode = AVCaptureDevice.ExposureMode.locked

这两个都确保:
1.您可以使用自定义设置来初始化相机
2.更改后,相机保持完全锁定状态

您的相机初始化代码应如下所示:

 try device.lockForConfiguration()  
          device.exposureMode = AVCaptureDevice.ExposureMode.custom 
          device.setExposureModeCustom(duration: durationCust, iso: minISO, completionHandler: nil)
          device.setWhiteBalanceModeLocked(with: deviceGains) {
                    (timestamp:CMTime) -> Void in
            }
          device.exposureMode = AVCaptureDevice.ExposureMode.locked
            device.unlockForConfiguration()

当您要主动更改曝光参数时,请勿在实际更改曝光范围之外重新将曝光声明为锁定或自定义。函数中的代码应如下所示:

try device.lockForConfiguration()
                 device.setExposureModeCustom(duration: durationCust, iso: minISO, completionHandler: nil)
             device.unlockForConfiguration()

我很高兴发现这一点-希望有人觉得有帮助:)