如何计算FOV?

时间:2014-03-03 08:59:47

标签: ios iphone camera avcapturesession fieldofview

初始上下文

我正在开发基于增强现实的应用程序位置,我需要获取视野[FOV](我只是在方向改变时更新值,所以我正在寻找一种方法,当我调用时可以获得此值它)

目标是让“学位标尺”与现实相关,如下所示: Degree Ruler - AR App

我已经在使用AVCaptureSession来显示相机流;和一个与CAShapeLayer相结合的路径来绘制标尺。这工作得很好,但现在我必须使用视野值将我的元素放在正确的位置(例如,选择160°和170°之间的正确空间!)。

实际上,我正在使用这些来源对这些值进行硬编码:https://stackoverflow.com/a/3594424/3198096(特别感谢@ hotpaw2!)但我不确定它们是否完全精确且这不是处理iPhone 5等。我无法从官方来源(Apple!)获取值,但是有一个链接显示我认为我需要的所有iDevice的值(4,4S,5,5S):AnandTech | Some thoughts about the iphone 5s camera improvements

注意:经过个人测试和其他在线研究后,我很确定这些值不准确!这也迫使我使用外部库来检查我使用哪种型号的iPhone手动初始化我的FOV ......我必须检查所有支持设备的值。

我更喜欢“代码解决方案”

阅读此帖后:iPhone: Real-time video color info, focal length, aperture?,我试图从建议的AVCaptureStillImageOutput中获取exif data。之后我能够从exif数据中读取焦距,然后通过公式计算水平和垂直视野! (或者可以直接获得如下所示的FOV:http://www.brianklug.org/2011/11/a-quick-analysis-of-exif-data-from-apples-iphone-4s-camera-samples/ - 注意:经过一定数量的更新后,似乎我们无法直接从exif获取视野!)


实际点

来自http://iphonedevsdk.com/forum/iphone-sdk-development/112225-camera-app-working-well-on-3gs-but-not-on-4s.htmlModified EXIF data doesn't save properly

的来源

以下是我正在使用的代码:

AVCaptureDevice* camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if (camera != nil)
{
    captureSession = [[AVCaptureSession alloc] init];

    AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:camera error:nil];

    [captureSession addInput:newVideoInput];

    captureLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:captureSession];
    captureLayer.frame = overlayCamera.bounds;
    [captureLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    previewLayerConnection=captureLayer.connection;
    [self setCameraOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
    [overlayCamera.layer addSublayer:captureLayer];
    [captureSession startRunning];

    AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVideoCodecJPEG, AVVideoCodecKey, nil];
    [stillImageOutput setOutputSettings:outputSettings];
    [captureSession addOutput:stillImageOutput];

    AVCaptureConnection *videoConnection = nil;
    for (AVCaptureConnection *connection in stillImageOutput.connections)
    {
        for (AVCaptureInputPort *port in [connection inputPorts])
        {
            if ([[port mediaType] isEqual:AVMediaTypeVideo] )
            {
                videoConnection = connection;
                break;
            }
        }
        if (videoConnection) { break; }
    }

    [stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection
                                                         completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error)
     {
         NSData *imageNSData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];

         CGImageSourceRef imgSource = CGImageSourceCreateWithData((__bridge_retained CFDataRef)imageNSData, NULL);

         NSDictionary *metadata = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imgSource, 0, NULL);

         NSMutableDictionary *metadataAsMutable = [metadata mutableCopy];

         NSMutableDictionary *EXIFDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy];

         if(!EXIFDictionary)
             EXIFDictionary = [[NSMutableDictionary dictionary] init];

         [metadataAsMutable setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary];

         NSLog(@"%@",EXIFDictionary);
     }];
}

这是输出:

{
    ApertureValue = "2.52606882168926";
    BrightnessValue = "0.5019629837352776";
    ColorSpace = 1;
    ComponentsConfiguration =     (
        1,
        2,
        3,
        0
    );
    ExifVersion =     (
        2,
        2,
        1
    );
    ExposureMode = 0;
    ExposureProgram = 2;
    ExposureTime = "0.008333333333333333";
    FNumber = "2.4";
    Flash = 16;
    FlashPixVersion =     (
        1,
        0
    );
    FocalLenIn35mmFilm = 40;
    FocalLength = "4.28";
    ISOSpeedRatings =     (
        50
    );
    LensMake = Apple;
    LensModel = "iPhone 4S back camera 4.28mm f/2.4";
    LensSpecification =     (
        "4.28",
        "4.28",
        "2.4",
        "2.4"
    );
    MeteringMode = 5;
    PixelXDimension = 1920;
    PixelYDimension = 1080;
    SceneCaptureType = 0;
    SceneType = 1;
    SensingMethod = 2;
    ShutterSpeedValue = "6.906947890818858";
    SubjectDistance = "69.999";
    UserComment = "[S.D.] kCGImagePropertyExifUserComment";
    WhiteBalance = 0;
}

我想我拥有计算FOV所需的一切。但他们是正确的价值观吗?因为看了很多不同的网站给出了不同的焦距值,我有点困惑!我的PixelDimensions似乎也错了!

通过http://en.wikipedia.org/wiki/Angle_of_view这是我计划使用的公式:

FOV = (IN_DEGREES(   2*atan( (d) / (2  * f) )   ));
// d = sensor dimensions (mm)
// f = focal length (mm)

我的问题

我的方法和公式是否正确,如果是,我会将哪些值传递给函数?


精密工业

  • FOV是我认为我需要使用的,如果你有任何关于标尺如何与现实相匹配的建议;我会接受答案!
  • 在增强现实视图控制器中禁用缩放,因此我的视野在相机初始化时是固定的,并且在用户旋转手机之前无法更改!

也很抱歉我的英语错误,我是法国人......

5 个答案:

答案 0 :(得分:25)

在iOS 7及更高版本中,您可以按照以下方式执行操作:

float FOV = camera.activeFormat.videoFieldOfView;

其中camera是您的AVCaptureDevice。根据您为视频会话选择的预设,即使在同一台设备上也可以更改 。它是水平视野(以度为单位),因此您需要根据显示尺寸计算垂直视野。

这是Apple's reference material

答案 1 :(得分:1)

根据FOV方程,您需要焦距和传感器尺寸。 Exif数据具有焦距但不具有传感器尺寸。我发现只有一个摄像机供应商(佳能)在元数据中提供传感器尺寸 - 这就是他们的CRW原始文件。因此,您必须根据相机或智能手机查找传感器尺寸的表格。以下维基百科链接列出了许多相机和一些较新的iPhone的传感器尺寸。该列表接近Wiki文章的末尾。 http://en.wikipedia.org/wiki/Image_sensor_format

此类信息的另一个来源可能是各种摄影博客。 希望这会有所帮助。

如果使用数码变焦,请将焦距乘以变焦值。 Exif数据包含缩放系数。

摄影博客和网站(如http://www.kenrockwell.com)提供了大量有关相机传感器尺寸的信息。

校正:实际上有焦平面X分辨率和焦平面Y分辨率(以像素为单位)和焦平面分辨率单位的Exif标签,从这些标签和图像尺寸,您可以计算传感器尺寸。但并非所有相机都提供这些Exif标签。例如,iPhone 4不提供这些标签。

答案 2 :(得分:1)

回答你的问题:

  

我的方法和公式看起来是否正确......?

也许,但它们看起来也太复杂了。

  

...如果是,我会将哪些值传递给函数?

我不知道,但如果目标是计算HFOV和VFOV,这里是一个代码示例,它以编程方式找到水平视角,这是目前可以在Swift中访问的唯一视角,然后根据iPhone 6,16:9的宽高比计算垂直视角。

    let devices = AVCaptureDevice.devices()
    var captureDevice : AVCaptureDevice?
    for device in devices {
        if (device.hasMediaType(AVMediaTypeVideo)) {
            if(device.position == AVCaptureDevicePosition.Back) {
                captureDevice = device as? AVCaptureDevice
            }
        }
    }
    if let retrievedDevice = captureDevice {
        var HFOV : Float = retrievedDevice.activeFormat.videoFieldOfView
        var VFOV : Float = ((HFOV)/16.0)*9.0
    }

如果你想让它工作,还记得导入AVFoundation!

答案 3 :(得分:1)

Apple还发布了一份包含所有相机规格细节的清单,包括FOV(Field of View)。

https://developer.apple.com/library/ios/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Cameras/Cameras.html

值匹配可以使用以下方法检索的值:

float FOV = camera.activeFormat.videoFieldOfView;

答案 4 :(得分:0)

视野的直径是您在观察显微镜时可以看到的光圈直径。

如果一行中大约十个圆形单元格可以跨越视场直径,如果您知道直径以毫米为单位,那么您可以将总直径除以适合查找每个单元格大小的单元格数量。细胞。

总直径除以适合的细胞数等于每个细胞的大小(直径)

示例

如果视场直径为1.5毫米,如果它们排成一行,则十个单元格适合,那么每个单元格都是:

1.5mm / 10 = 0.15mm

0.15毫米

请记住,每次更改放大倍率时,都可以更改可以看到的光圈直径。所以每个放大倍数都有自己的直径。

如果将标尺放在显微镜下,放大的越多,标尺上的线条就越少。