gpt4 book ai didi

iOS:同步来自相机和运动数据的帧

转载 作者:可可西里 更新时间:2023-11-01 06:13:23 24 4
gpt4 key购买 nike

我正在尝试从相机和相关运动数据中捕捉帧。对于同步,我使用时间戳。视频和 Action 被写入文件,然后进行处理。在那个过程中,我可以计算每个视频的运动帧偏移量。

事实证明,相同时间戳的运动数据和视频数据彼此偏移了不同的时间,从 0.2 秒到 0.3 秒不等。此偏移量对于一个视频是恒定的,但因视频而异。如果每次都具有相同的偏移量,我将能够减去一些校准值,但事实并非如此。

有同步时间戳的好方法吗?也许我没有正确记录它们?有没有更好的方法让它们处于同一参照系?

CoreMotion 返回相对于系统正常运行时间的时间戳,因此我添加偏移量以获得 unix 时间:

uptimeOffset = [[NSDate date] timeIntervalSince1970] - 
[NSProcessInfo processInfo].systemUptime;

CMDeviceMotionHandler blk =
^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error){
if(!error){
motionTimestamp = motion.timestamp + uptimeOffset;
...
}
};

[motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical
toQueue:[NSOperationQueue currentQueue]
withHandler:blk];

为了获得高精度的帧时间戳,我使用了 AVCaptureVideoDataOutputSampleBufferDelegate。它也偏移了 unix 时间:

-(void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
CMTime frameTime = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer);

if(firstFrame)
{
firstFrameTime = CMTimeMake(frameTime.value, frameTime.timescale);
startOfRecording = [[NSDate date] timeIntervalSince1970];
}

CMTime presentationTime = CMTimeSubtract(frameTime, firstFrameTime);
float seconds = CMTimeGetSeconds(presentationTime);

frameTimestamp = seconds + startOfRecording;
...
}

最佳答案

关联这些时间戳实际上非常简单 - 虽然没有明确记录,但相机帧和运动数据时间戳均基于 mach_absolute_time() 时基。

这是一个在启动时重置的单调计时器,但重要的是,当设备处于 sleep 状态时也会停止计数。因此,没有简单的方法可以将其转换为标准的“挂钟”时间。

谢天谢地,您不需要这样做,因为时间戳可以直接比较 - motion.timestamp 以秒为单位,您可以在回调中注销 mach_absolute_time() 以查看它是否是相同的时基。我的快速测试显示,运动时间戳通常比处理程序中的 mach_absolute_time 早大约 2 毫秒,这对于将数据报告给应用程序可能需要多长时间似乎是正确的。

注意 mach_absolute_time() 是以滴答为单位的,需要转换为纳秒;在 iOS 10 及更高版本上,您可以使用等效的 clock_gettime_nsec_np(CLOCK_UPTIME_RAW); does the same thing .

    [_motionManager
startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryZVertical
toQueue:[NSOperationQueue currentQueue]
withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
// motion.timestamp is in seconds; convert to nanoseconds
uint64_t motionTimestampNs = (uint64_t)(motion.timestamp * 1e9);

// Get conversion factors from ticks to nanoseconds
struct mach_timebase_info timebase;
mach_timebase_info(&timebase);

// mach_absolute_time in nanoseconds
uint64_t ticks = mach_absolute_time();
uint64_t machTimeNs = (ticks * timebase.numer) / timebase.denom;

int64_t difference = machTimeNs - motionTimestampNs;

NSLog(@"Motion timestamp: %llu, machTime: %llu, difference %lli", motionTimestampNs, machTimeNs, difference);
}];

对于相机,时基也是一样的:

// In practice gives the same value as the CMSampleBufferGetOutputPresentationTimeStamp
// but this is the media's "source" timestamp which feels more correct
CMTime frameTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
uint64_t frameTimestampNs = (uint64_t)(CMTimeGetSeconds(frameTime) * 1e9);

这里时间戳和调用处理程序之间的延迟有点大,通常在 10 毫秒内。

我们现在需要考虑相机帧上的时间戳的实际含义 - 这里有两个问题;有限的曝光时间和滚动快门。

滚动快门意味着并非图像的所有扫描线实际上都同时被捕获 - 首先捕获顶行,最后捕获底行。数据的这种滚动读出分布在整个帧时间内,因此在 30 FPS 相机模式下,最终扫描线的曝光开始/结束时间几乎恰好在第一条扫描线的相应开始/结束时间之后的 1/30 秒。

我的测试表明 AVFoundation 帧中的呈现时间戳是帧读出的开始 - 即第一条扫描线曝光的结束。因此,最后一条扫描线的曝光结束是在此之后的 frameDuration 秒,而第一条扫描线的曝光开始是在此之前的 exposureTime 秒。因此,帧曝光中心(图像中间扫描线曝光的中点)的时间戳可以计算为:

const double frameDuration = 1.0/30; // rolling shutter effect, depends on camera mode
const double exposure = avCaptureDevice.exposureDuration;
CMTime frameTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
double midFrameTime = CMTimeGetSeconds(frameTime) - exposure * 0.5 + frameDuration * 0.5;

在室内设置中,曝光通常以全帧时间结束,因此上面的 midFrameTime 最终与 frameTime 相同。对于您通常从明亮的室外场景中获得的短曝光,差异很明显(在极快的运动下)。

为什么原来的方法有不同的偏移量

我认为您偏移的主要原因是您假设第一帧的时间戳是处理程序运行的时间 - 即它不考虑捕获数据和将其传送到您的应用程序之间的任何延迟。特别是如果您正在为这些处理程序使用主队列,我可以想象第一帧的回调会被您提到的 0.2-0.3 秒延迟。

关于iOS:同步来自相机和运动数据的帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42116314/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com