![](/img/trans.png)
[英]OpenCV cv2.VideoCapture(0) is not working well with webcam
[英]Lower latency from webcam cv2.VideoCapture
我正在使用网络摄像头构建一个应用程序来控制视频游戏(有点像 kinect)。 它使用网络摄像头 (cv2.VideoCapture(0))、AI 姿势估计 ( mediapipe ) 和自定义逻辑将 pipe 输入到海豚模拟器。
问题是延迟。 我用手机的高速摄像头记录了自己的抓拍,发现我的手和屏幕上的帧之间的延迟约为 32 帧~ 133 毫秒。 这是在任何附加代码之前,只是一个带有视频read
和cv2.imshow
的循环(大约 15 毫秒)
有什么办法可以减少这种延迟?
我已经在一个单独的线程中抓取了帧,将CAP_PROP_BUFFERSIZE设置为 0,并降低了 CAP_PROP_FRAME_HEIGHT 和 CAP_PROP_FRAME_WIDTH,但我仍然得到约 133 毫秒的延迟。 还有什么我可以做的吗?
下面是我的代码:
class WebcamStream:
def __init__(self, src=0):
self.stopped = False
self.stream = cv2.VideoCapture(src)
self.stream.set(cv2.CAP_PROP_BUFFERSIZE, 0)
self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT, 400)
self.stream.set(cv2.CAP_PROP_FRAME_WIDTH, 600)
(self.grabbed, self.frame) = self.stream.read()
self.hasNew = self.grabbed
self.condition = Condition()
def start(self):
Thread(target=self.update, args=()).start()
return self
def update(self,):
while True:
if self.stopped: return
(self.grabbed, self.frame) = self.stream.read()
with self.condition:
self.hasNew = True
self.condition.notify_all()
def read(self):
if not self.hasNew:
with self.condition:
self.condition.wait()
self.hasNew = False
return self.frame
def stop(self):
self.stopped = True
应用程序需要尽可能接近实时地运行,因此延迟的任何减少,无论多小都会很好。 目前在网络摄像头延迟 (~133ms)、姿势估计和逻辑 (~25ms) 以及移动到正确姿势所需的实际时间之间,它的延迟大约为 350-400ms。 当我尝试玩游戏时绝对不理想。
编辑:这是我用来测试延迟的代码(在我的笔记本电脑上运行代码,记录我的手和屏幕,并计算捕捉时的帧差):
if __name__ == "__main__":
cap = WebcamStream().start()
while(True):
frame = cap.read()
cv2.imshow('frame', frame)
cv2.waitKey(1)
您上面描述的经验是一个很好的例子,累积的延迟如何破坏任何保持控制回路足够紧密、确实控制有意义的稳定的机会,就像我们希望保持的人机接口系统一样:
用户动议| CAM-捕捉| IMG-处理| GUI-显示| 用户视觉皮层场景捕捉| 用户的决定+行动| 环形
一个真实的情况,其中显示了 OpenCV 分析,以“感知”我们在各个采集-存储-转换-后处理-GUI 管道实际阶段花费了多少时间(根据需要放大)
暂时原谅我们累积每个特定延迟相关成本的原始草图:
CAM \____/ python code GIL-awaiting ~ 100 [ms] chopping
|::| python code calling a cv2.<function>()
|::| __________________________________________-----!!!!!!!-----------
|::| ^ 2x NNNNN!!!!!!!MOVES DATA!
|::| | per-call NNNNN!!!!!!! 1.THERE
|::| | COST NNNNN!!!!!!! 2.BACK
|::| | TTTT-openCV::MAT into python numpy.array
|::| | //// forMAT TRANSFORMER TRANSFORMATIONS
USBx | //// TRANSFORMATIONS
|::| | //// TRANSFORMATIONS
|::| | //// TRANSFORMATIONS
|::| | //// TRANSFORMATIONS
|::| | //// TRANSFORMATIONS
H/W oooo _v____TTTT in-RAM openCV::MAT storage TRANSFORMATIONS
/ \ oooo ------ openCV::MAT object-mapper
\ / xxxx
O/S--- °°°° xxxx
driver """" _____ xxxx
\\\\ ^ xxxx ...... openCV {signed|unsigned}-{size}-{N-channels}
_________\\\\___|___++++ __________________________________________
openCV I/O ^ PPPP PROCESSING
as F | .... PROCESSING
A | ... PROCESSING
S | .. PROCESSING
T | . PROCESSING
as | PPPP PROCESSING
possible___v___PPPP _____ openCV::MAT NATIVE-object PROCESSING
硬件延迟可能会有所帮助,但更改已购买的硬件可能会变得昂贵
已经优化了延迟的工具箱的软件延迟是可能的,但越来越难
设计效率低下是最后也是最常见的地方,延迟可能会被削减
OpenCV?
这里没什么可做的。 问题在于 OpenCV-Python 绑定细节:
... So when you call a function, say
res = equalizeHist(img1,img2)
in Python, you pass two numpy arrays and you expect anothernumpy
array as the output. So these numpy arrays are converted tocv::Mat
and then calls theequalizeHist()
function in C++. 最终结果, res 将被转换回 Numpy 数组。 所以简而言之,几乎所有的操作都在 C++ 中完成,这给了我们几乎与 C++ 相同的速度。
这在控制回路“外部”工作得很好,在我们的情况下,这两种运输成本、转换成本和任何新的或临时数据存储 RAM 分配成本都会导致我们的控制回路TAT
恶化.
因此,请避免从 Python(在绑定的延迟额外英里之后)调用任何和所有 OpenCV 原生函数,无论这些函数乍一看多么诱人或甜蜜。
忽略这个建议是一个相当[ms]
的代价。
Python?
是的,Python。 使用 Python 解释器本身会引入延迟,加上避免并发处理的问题,无论我们的硬件在多少个内核上运行(而最近的 Py3 尝试在解释器级软件下降低这些成本)。
我们可以测试并从(仍然不可避免,在 2022 年)GIL 锁交错中挤出最大值 - 检查sys.getswitchinterval()
并测试增加这个数量以减少交错的 python 端处理(调整取决于你的其他 python-应用目标(GUI、 分布式计算任务、python 网络 I/O 工作负载、python-HW-I/O,如果适用等)
RAM-内存-I/O成本?
我们的下一个主要敌人。 使用MediaPipe可以使用的最不足够的图像数据格式是这一领域的前进方向。
可避免的损失
所有其他(我们的)罪都属于这个部分。 避免任何图像数据格式转换(见上文,仅将已获取和格式化并存储numpy.array
转换为另一个颜色图,成本可能很容易增长到[us]
的数千)
媒体管道
列出了它可以使用的枚举格式:
// ImageFormat
SRGB: sRGB, interleaved: one byte for R,
then one byte for G,
then one byte for B for each pixel.
SRGBA: sRGBA, interleaved: one byte for R,
one byte for G,
one byte for B,
one byte for alpha or unused.
SBGRA: sBGRA, interleaved: one byte for B,
one byte for G,
one byte for R,
one byte for alpha or unused.
GRAY8: Grayscale, one byte per pixel.
GRAY16: Grayscale, one uint16 per pixel.
SRGB48: sRGB,interleaved, each component is a uint16.
SRGBA64: sRGBA,interleaved,each component is a uint16.
VEC32F1: One float per pixel.
VEC32F2: Two floats per pixel.
所以,选择MVF——最小可行格式——让手势识别工作并尽可能缩小像素数量( 400x600-GRAY8
是我的热门候选)
预配置(不缺少cv.CAP_PROP_FOURCC
详细信息)本机端OpenCV::VideoCapture
处理,仅在采集-&-预处理的本机端以 RAW 格式简单存储此 MVF链,因此不会发生其他后处理格式化。
如果确实被迫接触 python 端numpy.array
object,则更喜欢使用矢量化和跨步技巧驱动的操作而不是.view()
-s 或.data
-buffers,以避免任何不必要的附加延迟成本增加控制回路TAT
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.