27

初始上下文

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

目标是制作与现实相关的“度数尺”,如下所示: 度数尺 - AR App

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

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

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

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

看完这篇文章:iPhone:实时视频色彩信息、焦距、光圈?,我正在尝试exif data从 AVCaptureStillImageOutput 中获取建议。之后我可以从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.html修改后的EXIF 数据不保存适当地

这是我正在使用的代码:

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;我会接受答案!
  • 增强现实视图控制器中禁用了缩放,因此在初始化相机时我的视野是固定的,并且在用户旋转手机之前无法改变!

4

5 回答 5

27

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

float FOV = camera.activeFormat.videoFieldOfView;

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

这是Apple 的参考资料

于 2014-04-03T11:20:23.823 回答
2

要回答您的问题:

我的方法和公式看起来对吗...?

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

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

我不知道,但如果目标是计算 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 !

于 2015-04-13T04:53:48.357 回答
2

Apple 还发布了一份包含所有相机规格详细信息的列表,包括 FOV(视野)。

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

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

float FOV = camera.activeFormat.videoFieldOfView;

于 2016-08-04T22:06:21.840 回答
1

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

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

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

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

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

于 2014-03-20T00:33:06.780 回答
0

视场的直径是您在显微镜下看到的光圈的直径。

如果一行中大约十个圆形单元格可以穿过视场的直径,并且如果您知道以毫米为单位的直径,那么您可以将总直径除以适合找到每个单元格大小的单元格数。

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

例子

如果视场的直径是 1.5 毫米,如果将它们排列成一条线就可以容纳十个电池,那么每个电池是:

1.5mm/10 = 0.15mm

0.15 毫米

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

如果你把尺子放在显微镜下,你放大得越多,你能看到的尺子上的线数就越少。

于 2014-03-18T22:59:21.947 回答