OpenCV中imwrite操作为何会影响图像捕获时长的测量结果?
imwrite()后帧捕获时长测量值变小? 这背后的核心原因是OpenCV的VideoCapture内部维护了一个帧缓冲区,再加上你的处理速度和摄像头采集速度的变化导致的,我来一步步给你拆解:
无imwrite()时的情况
当你没有添加imwrite()时,你的循环执行速度非常快:取帧、计算时间、立刻进入下一次循环。而你的摄像头是60fps,每16.6ms左右生成一帧。这时候你的循环速度比摄像头采集速度快,每次调用cap>>IMG时,缓冲区里还没有新的帧,程序会等待摄像头完成新帧的捕获并写入缓冲区,所以你测量的cap>>IMG前后的时间,就是摄像头实际捕获一帧的真实耗时(15~17ms,和60fps的帧间隔一致)。
添加imwrite()后计时放在cap>>IMG后的情况
当你加入imwrite()保存PNG图像后,情况彻底变了:imwrite()是个很耗时的操作(PNG压缩需要计算,连续保存文件也会占用磁盘IO),这让你的循环执行速度大幅变慢,远低于摄像头的60fps采集速度。
在你执行imwrite()的这段时间里,摄像头已经默默把好几帧都写入了VideoCapture的缓冲区。所以当你下一次循环调用cap>>IMG时,缓冲区里已经有现成的帧在等着了——程序不需要再等待摄像头捕获新帧,直接从缓冲区里读帧就行。这时候你测量的时间,只是从缓冲区读取帧的时间,而不是摄像头捕获帧的时间,自然就变短到5~6ms了。
把计时移到imwrite()后的情况
当你把第二次gettimeofday()移到imwrite()之后,你测量的是整个循环的总耗时:取帧(从缓冲区,很快) + 保存图像(耗时)。这时候整个循环的周期被imwrite()拉长,当你进入下一次循环时,缓冲区里的帧已经被取完了,程序又需要等待摄像头捕获新帧,所以总时长又回到了和摄像头帧间隔接近的15~17ms(本质是等待帧的时间加上保存图像的时间,刚好凑到了这个范围)。
额外小建议
如果你想准确测量摄像头捕获单帧的真实时间,可以尝试调整VideoCapture的缓冲区大小:
cap.set(cv::CAP_PROP_BUFFERSIZE, 1); // 设置缓冲区只保留1帧
这样缓冲区里不会积累多余的帧,每次cap>>IMG都需要等待摄像头的新帧,测量的时间会更接近真实的捕获耗时。
内容的提问来源于stack exchange,提问作者Ali Nouri

