问题摘要
我已经建立了一个18相机阵列的USB网络摄像头,连接到一个树莓Pi 400作为控制器。我的Python3.8从每个摄像头获取图像的代码很慢,我正在设法加快速度。
FFMPEG和video4linux2命令行选项使我感到困惑,因此我不确定延迟是否是由于我对参数选择不当造成的,更好的选项集将解决这个问题。
目标
我正试图尽快从每台相机上捕捉到一张图像。
我正在使用video4linux2、FFMPEG、和命令行选项来捕获所有相机的循环中的每个图像,如下所示。
预期结果
我只想从每台相机里得到一个画面。帧速率是30 fps,所以我原以为捕获时间是第二个最坏情况的1/30到1/10。但是性能计时器告诉我每次捕获都需要2-3秒。
此外,我并不真正理解ffmpeg输出,但是这个输出让我担心:
frame= 0 fps=0.0 q=0.0 size=N/A time=00:00:00.00 bitrate=N/A speed= 0x
frame= 0 fps=0.0 q=0.0 size=N/A time=00:00:00.00 bitrate=N/A speed= 0x
frame= 0 fps=0.0 q=0.0 size=N/A time=00:00:00.00 bitrate=N/A speed= 0x
frame= 1 fps=0.5 q=8.3 Lsize=N/A time=00:00:00.06 bitrate=N/A speed=0.0318x
video:149kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing 我不明白为什么"frame=“这一行被重复了4次。在第四次重复中,fps表示0.5,我将其解释为每2秒一帧,而不是我指定的30 fps。
特定问题:
有人能向我解释一下这个ffmpeg输出是什么意思吗?为什么每拍一张图像要花2秒,而不是接近1/30秒?
有谁能向我解释如何在每次捕获的时间更短的时间内捕获图像?
我是否应该为每个ffmpeg调用生成一个单独的线程,以便它们异步运行,而不是串行运行?或者这样做不能在实践中真正节省时间吗?
实际结果
Input #0, video4linux2,v4l2, from '/dev/video0':
Duration: N/A, start: 6004.168748, bitrate: N/A
Stream #0:0: Video: mjpeg, yuvj422p(pc, bt470bg/unknown/unknown), 1920x1080, 30 fps, 30 tbr, 1000k tbn, 1000k tbc
Stream mapping:
Stream #0:0 -> #0:0 (mjpeg (native) -> mjpeg (native))
Press [q] to stop, [?] for help
Output #0, image2, to '/tmp/video1.jpg':
Metadata:
encoder : Lavf58.20.100
Stream #0:0: Video: mjpeg, yuvj422p(pc), 1920x1080, q=2-31, 200 kb/s, 30 fps, 30 tbn, 30 tbc
Metadata:
encoder : Lavc58.35.100 mjpeg
Side data:
cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
frame= 0 fps=0.0 q=0.0 size=N/A time=00:00:00.00 bitrate=N/A speed= 0x
frame= 0 fps=0.0 q=0.0 size=N/A time=00:00:00.00 bitrate=N/A speed= 0x
frame= 0 fps=0.0 q=0.0 size=N/A time=00:00:00.00 bitrate=N/A speed= 0x
frame= 1 fps=0.5 q=8.3 Lsize=N/A time=00:00:00.06 bitrate=N/A speed=0.0318x
video:149kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
Captured /dev/video0 image in: 3 seconds
Input #0, video4linux2,v4l2, from '/dev/video2':
Duration: N/A, start: 6007.240871, bitrate: N/A
Stream #0:0: Video: mjpeg, yuvj422p(pc, bt470bg/unknown/unknown), 1920x1080, 30 fps, 30 tbr, 1000k tbn, 1000k tbc
Stream mapping:
Stream #0:0 -> #0:0 (mjpeg (native) -> mjpeg (native))
Press [q] to stop, [?] for help
Output #0, image2, to '/tmp/video2.jpg':
Metadata:
encoder : Lavf58.20.100
Stream #0:0: Video: mjpeg, yuvj422p(pc), 1920x1080, q=2-31, 200 kb/s, 30 fps, 30 tbn, 30 tbc
Metadata:
encoder : Lavc58.35.100 mjpeg
Side data:
cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
frame= 0 fps=0.0 q=0.0 size=N/A time=00:00:00.00 bitrate=N/A speed= 0x
frame= 0 fps=0.0 q=0.0 size=N/A time=00:00:00.00 bitrate=N/A speed= 0x
frame= 0 fps=0.0 q=0.0 size=N/A time=00:00:00.00 bitrate=N/A speed= 0x
frame= 1 fps=0.5 q=8.3 Lsize=N/A time=00:00:00.06 bitrate=N/A speed=0.0318x
video:133kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
Captured /dev/video2 image in: 3 seconds
...代码:
list_of_camera_ids = ["/dev/video1","/dev/video2", "/dev/video3", "/dev/video4",
"/dev/video5","/dev/video6", "/dev/video7", "/dev/video8",
"/dev/video9","/dev/video10", "/dev/video11", "/dev/video12",
"/dev/video13","/dev/video14", "/dev/video15", "/dev/video16",
"/dev/video17","/dev/video18"
]
for this_camera_id in list_of_camera_ids:
full_image_file_name = '/tmp/' + os.path.basename(this_camera_id) + 'jpg'
image_capture_tic = time.perf_counter()
run_cmd = subprocess.run([
'/usr/bin/ffmpeg', '-y', '-hide_banner',
'-f', 'video4linux2',
'-input_format', 'mjpeg',
'-framerate', '30',
'-i', this_camera_id,
'-frames', '1',
'-f', 'image2',
full_image_file_name
],
universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
print(run_cmd.stderr)
image_capture_toc = time.perf_counter()
print(f"Captured {camera_id} image in: {image_capture_toc - image_capture_tic:0.0f} seconds")附加数据:针对Mark的回答,即需要更多信息来回答这个问题,我现在在这里详细说明所要求的信息:
摄像机:相机是USB-3摄像机,它们将自己标识为:
idVendor 0x0bda Realtek Semiconductor Corp.
idProduct 0x5829 我试图为其中一个摄像机添加冗长的lsusb转储,但是这个帖子超过了30000字符的限制。
相机的连接方式: USB 3端口Pi到主USB-3 7端口集线器,3支路7端口集线器(并非所有的端口都被占用)。
相机分辨率:高清格式1920x1080
如果我只想要一个图像,为什么我要设置一个帧速率??
我设置了一个帧速率,这看起来很奇怪,因为它指定了帧之间的时间,但是您只需要一个帧。我这么做是因为我不知道如何从FFMPEG获得一个图像。这是我在网上讨论过的FFMPEG命令选项的一个例子,我可以获得它来成功捕获单个图像。我发现了无数的不起作用的选项!我写这篇文章是因为我的网络搜索没有给出一个对我有用的例子。我希望一个比我更有见地的人能向我展示一种行之有效的方法!
,为什么我要按顺序而不是平行地扫描摄像机呢?
我这么做只是为了先保持简单,然后循环一下列表看起来很简单,而且是奏鸣曲。我很清楚,以后我可能能够为每个FFMPEG调用生成一个单独的线程,并可能以这种方式获得并行的速度。事实上,我欢迎一个如何这样做的例子。
但无论如何,用3秒拍摄的单个图像似乎太长了。
为什么我只使用你的覆盆子上的4个核心中的一个?
我发布的示例代码只是我整个程序的一个片段。当前,图像捕获在子线程中进行,而带有事件循环的窗口GUI则在主线程中运行,因此在成像过程中不会阻塞用户输入。
对于Raspberry Pi 400的内核,或者Raspberry Pi OS (又名Raspbian)如何管理线程分配给内核,或者Python是否能够或应该显式地指示线程在特定内核中运行,我都不太了解。
我欢迎Mark (或其他熟悉这些问题的人)的建议,推荐最佳实践并包括示例代码。
发布于 2021-08-12 22:18:12
首先,感谢https://stackoverflow.com/users/1109017/llogan在下面的评论中为我提供了所需的线索。
我在这里记录这个解决方案,以便于其他可能不会阅读评论的人发现。
以下是我修订的计划:
list_of_camera_ids = ["/dev/video1","/dev/video2", "/dev/video3", "/dev/video4",
"/dev/video5","/dev/video6", "/dev/video7", "/dev/video8",
"/dev/video9","/dev/video10", "/dev/video11", "/dev/video12",
"/dev/video13","/dev/video14", "/dev/video15", "/dev/video16",
"/dev/video17","/dev/video18"
]
for this_camera_id in list_of_camera_ids:
full_image_file_name = '/tmp/' + os.path.basename(this_camera_id) + 'jpg'
image_capture_tic = time.perf_counter()
run_cmd = subprocess.run([
'v4l2-ctl','-d',
this_camera_id,
'--stream-mmap',
'--stream-count=1',
'--stream-to=' +
full_image_file_name,"&"
],
universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
print(run_cmd.stderr)
image_capture_toc = time.perf_counter()
print(f"Captured {camera_id} image in: {image_capture_toc - image_capture_tic:0.0f} seconds")附加注释:,这个代码是一个实质性的加速!
用我以前的方法,每个图像需要3到4秒才能捕捉到。在序列化的循环中,如最初的文章所示,18个图像通常需要45到60秒才能完成。
使用我修改的代码,使用llogan的建议,现在每台摄像机的捕获时间不到1秒。此外,简单地通过在命令中添加一个"&“来生成背景中的每一个,它们就会自动并行运行,而18个摄像机的总时间现在大约是10秒,所以现在每个摄像机的平均时间大约是.55秒。
我怀疑我可能会因为使用"&“方法并行化而产生一些额外的开销。如果我只需要生成线程,而不是完整的进程,那么其中的一些可能会进一步减少。但是这是一个我还没有经验的性能调优级别。
发布于 2021-08-11 20:16:38
您可以使用v4l2-ctl直接捕获帧:
v4l2-ctl -d /dev/video0 --stream-mmap --stream-count=1 --stream-to=output.jpg您的输入已经是JPG,因此它将捕获它。
有关更多信息,请参见v4l2-ctl --help-streaming。
发布于 2021-08-11 00:27:18
这里有很多问题:
,
,
F 213上的4个核心中的一个。
https://stackoverflow.com/questions/68734375
复制相似问题