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

Igo*_*hev 5 camera avfoundation ios

我使用 AVFoundation 来拍照。问题是,即使曝光时间、ISO 和白平衡设置恒定,我也会得到不同亮度的照片。手电筒、闪光灯和所有可能的稳定功能均被禁用。

\n\n

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

\n\n

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

\n\n

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

\n\n

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

\n\n

增亮并不总是发生,但无论如何,如果我将相机移开并再次瞄准物体,可能会出现显着的亮度差异。但如果我在不移动相机的情况下拍摄一系列照片,亮度是相同的。

\n\n

(当然object\xe2\x80\x99s照片都是在相同光线情况下拍摄的)

\n\n

可能这种增亮是设置自定义曝光设置的一部分(因为它通常首先发生)并且 lt\xe2\x80\x99s 后期激活是我应该加快速度的过程,但我不\xe2\x80\x99t 知道如何做到这一点。

\n\n

我在 iPod Touch 5 和 iPad Air 上有这个效果。我想它也可能发生在其他 iOS 设备上。

\n\n

看来场景亮度会影响最终图像的亮度(以及预览层\xe2\x80\x99s 的亮度)。设备不\xe2\x80\x99只是设置给定的曝光设置;它根据当前场景亮度添加一些校正,并在可见场景的常见亮度变化较大时更改此校正。

\n\n

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

\n\n

可能\xe2\x80\x99 不[仅]亮度而是对比度,因为当我将相机移离白色显示器时,当屏幕之外的[相对较暗的]物体变得可见时,可能会瞬间变亮。

\n\n

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

\n\n

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

\n\n

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

\n\n

尝试通过设置曝光目标偏差来强制调整,使曝光目标偏移值在捕获之前远离零也失败了,因为什么也没有发生,并且我可以在尝试补偿后获得增亮。即使在自定义模式下,目标偏差也会影响曝光偏移[对客户端可见],但它似乎不会影响负责曝光的部分的设备行为。

\n\n

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

\n\n

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

\n\n

一切都令人困惑。如何提供 image\xe2\x80\x99s 亮度和曝光设置之间的直接关系?

\n

Jam*_*ush 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);
}
Run Code Online (Sandbox Code Playgroud)

lumaThreshold 变量作为统一变量发送到我的片段着色器,该着色器将 Y 采样器纹理相乘,以根据环境亮度找到理想的亮度。目前,它使用的是后置摄像头;我可能会切换到前置摄像头,因为我只是更改屏幕的“亮度”以适应室内/室外观看,并且用户的眼睛位于摄像头的前面(而不是后面)。