BeagleBone Black OpenCV Python 太慢了
BeagleBone Black OpenCV Python is too slow
我尝试使用 opencv 和 python 从网络摄像头获取图像。代码非常基本,例如:
import cv2
import time
cap=cv2.VideoCapture(0)
cap.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH,640)
cap.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT,480)
cap.set(cv2.cv.CV_CAP_PROP_FPS, 20)
a=30
t=time.time()
while (a>0):
now=time.time()
print now-t
t=now
ret,frame=cap.read()
#Some processes
print a,ret
print frame.shape
a=a-1
k=cv2.waitKey(20)
if k==27:
break
cv2.destroyAllWindows()
但它运行缓慢。程序输出:
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
HIGHGUI ERROR: V4L: Property <unknown property string>(5) not supported by device
8.82148742676e-06
select timeout
30 True
(480, 640, 3)
2.10035800934
select timeout
29 True
(480, 640, 3)
2.06729602814
select timeout
28 True
(480, 640, 3)
2.07144904137
select timeout
配置:
- Beaglebone Black RevC
- Debian-wheezly
- opencv 2.4
- python 2.7
"secret" 在使用 OpenCV 处理视频流时获得更高的 FPS 是移动 I/O(即从相机读取帧传感器)到一个单独的线程。
当调用 read()
方法和 cv2.VideoCapture
函数时,它使整个过程非常缓慢,因为它必须等待每个 I/O 操作完成才能继续到下一个 (Blocking Process).
为了降低 FPS increase/latency,我们的目标是将帧读取从网络摄像头或 USB 设备转移到完全不同的线程,与我们的主 Python 脚本完全分开.
这将允许从 I/O 线程连续读取帧,同时我们的根线程处理当前帧。一旦根线程处理完它的帧,它只需要从 I/O 线程获取当前帧。这是在无需等待阻塞 I/O 操作的情况下完成的。
您可以阅读Increasing webcam FPS with Python and OpenCV了解实现线程的步骤。
编辑
根据我们评论中的讨论,我觉得你可以重写代码如下:
import cv2
cv2.namedWindow("output")
cap = cv2.VideoCapture(0)
if cap.isOpened(): # Getting the first frame
ret, frame = cap.read()
else:
ret = False
while ret:
cv2.imshow("output", frame)
ret, frame = cap.read()
key = cv2.waitKey(20)
if key == 27: # exit on Escape key
break
cv2.destroyWindow("output")
我在Intel Edison平台上使用OpenCV 2.4.9做项目时遇到了类似的问题。在进行任何处理之前,执行帧抓取大约需要 80 毫秒。事实证明,OpenCV 的 Linux 相机捕获逻辑似乎没有正确实现,至少在 2.4.9 版本中是这样。底层驱动程序只使用一个缓冲区,因此不可能在应用程序层中使用多线程来解决它 - 在您尝试抓取下一帧之前,V4L2 驱动程序中唯一的缓冲区被锁定。
解决方案是不使用 OpenCV 的 VideoCapture class。也许在某些时候使用合理数量的缓冲区是固定的,但从 2.4.9 开始,它不是。事实上,如果您查看与@Nickil Maveli 提供的 link 同一作者撰写的 this 文章,您会发现一旦他提供了改进 [=25] 上的 FPS 的建议=],他停止使用 OpenCV 的 VideoCapture。我不相信这是巧合。
这是我在 Intel Edison 论坛上的 post 关于它的内容:https://communities.intel.com/thread/58544。
我基本上是直接使用 V4L2 编写自己的 class 来处理帧抓取。这样您就可以提供缓冲区的循环列表,并允许适当地解耦帧抓取和应用程序逻辑。但是,对于 C++ 应用程序,这是在 C++ 中完成的。假设上面的 link 实现了它的承诺,那可能是一个更简单的方法。我不确定它是否适用于 BeagleBone,但也许那里有类似于 PiCamera 的东西。祝你好运。
编辑:我查看了 OpenCV 2.4.11 的源代码。看起来他们现在默认使用 4 个缓冲区,但您必须使用 V4L2 才能利用它。如果您仔细查看错误消息 HIGHGUI ERROR: V4L: Property...
,您会发现它引用了 V4L,而不是 V4L2。这意味着您正在使用的 OpenCV 构建正在退回到旧的 V4L 驱动程序。除了导致性能问题的单一缓冲区之外,您使用的是一个古老的驱动程序,它可能有很多限制和它自己的性能问题。
最好的办法是自己构建 OpenCV 以确保它使用 V4L2。如果我没记错的话,OpenCV 配置过程会检查机器上是否安装了 V4L2 驱动程序并相应地构建它,因此您需要确保在用于构建 OpenCV 的机器上安装了 V4L2 和任何相关的开发包。
试试这个!我替换了 cap.set() 部分
中的一些代码
import cv2
import time
cap=cv2.VideoCapture(0)
cap.set(3,640)
cap.set(4,480)
cap.set(5, 20)
a=30
t=time.time()
while (a>0):
now=time.time()
print now-t
t=now
ret,frame=cap.read()
#Some processes
print a,ret
print frame.shape
a=a-1
k=cv2.waitKey(20)
if k==27:
break
cv2.destroyAllWindows()
输出(pc 网络摄像头)你的代码对我来说是错误的。
>>0.0
>>30 True
>>(480, 640, 3)
>>0.246999979019
>>29 True
>>(480, 640, 3)
>>0.0249998569489
>>28 True
>>(480, 640, 3)
>>0.0280001163483
>>27 True
>>(480, 640, 3)
>>0.0320000648499
我尝试使用 opencv 和 python 从网络摄像头获取图像。代码非常基本,例如:
import cv2
import time
cap=cv2.VideoCapture(0)
cap.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH,640)
cap.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT,480)
cap.set(cv2.cv.CV_CAP_PROP_FPS, 20)
a=30
t=time.time()
while (a>0):
now=time.time()
print now-t
t=now
ret,frame=cap.read()
#Some processes
print a,ret
print frame.shape
a=a-1
k=cv2.waitKey(20)
if k==27:
break
cv2.destroyAllWindows()
但它运行缓慢。程序输出:
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
HIGHGUI ERROR: V4L: Property <unknown property string>(5) not supported by device
8.82148742676e-06
select timeout
30 True
(480, 640, 3)
2.10035800934
select timeout
29 True
(480, 640, 3)
2.06729602814
select timeout
28 True
(480, 640, 3)
2.07144904137
select timeout
配置:
- Beaglebone Black RevC
- Debian-wheezly
- opencv 2.4
- python 2.7
"secret" 在使用 OpenCV 处理视频流时获得更高的 FPS 是移动 I/O(即从相机读取帧传感器)到一个单独的线程。
当调用 read()
方法和 cv2.VideoCapture
函数时,它使整个过程非常缓慢,因为它必须等待每个 I/O 操作完成才能继续到下一个 (Blocking Process).
为了降低 FPS increase/latency,我们的目标是将帧读取从网络摄像头或 USB 设备转移到完全不同的线程,与我们的主 Python 脚本完全分开.
这将允许从 I/O 线程连续读取帧,同时我们的根线程处理当前帧。一旦根线程处理完它的帧,它只需要从 I/O 线程获取当前帧。这是在无需等待阻塞 I/O 操作的情况下完成的。
您可以阅读Increasing webcam FPS with Python and OpenCV了解实现线程的步骤。
编辑
根据我们评论中的讨论,我觉得你可以重写代码如下:
import cv2
cv2.namedWindow("output")
cap = cv2.VideoCapture(0)
if cap.isOpened(): # Getting the first frame
ret, frame = cap.read()
else:
ret = False
while ret:
cv2.imshow("output", frame)
ret, frame = cap.read()
key = cv2.waitKey(20)
if key == 27: # exit on Escape key
break
cv2.destroyWindow("output")
我在Intel Edison平台上使用OpenCV 2.4.9做项目时遇到了类似的问题。在进行任何处理之前,执行帧抓取大约需要 80 毫秒。事实证明,OpenCV 的 Linux 相机捕获逻辑似乎没有正确实现,至少在 2.4.9 版本中是这样。底层驱动程序只使用一个缓冲区,因此不可能在应用程序层中使用多线程来解决它 - 在您尝试抓取下一帧之前,V4L2 驱动程序中唯一的缓冲区被锁定。
解决方案是不使用 OpenCV 的 VideoCapture class。也许在某些时候使用合理数量的缓冲区是固定的,但从 2.4.9 开始,它不是。事实上,如果您查看与@Nickil Maveli 提供的 link 同一作者撰写的 this 文章,您会发现一旦他提供了改进 [=25] 上的 FPS 的建议=],他停止使用 OpenCV 的 VideoCapture。我不相信这是巧合。
这是我在 Intel Edison 论坛上的 post 关于它的内容:https://communities.intel.com/thread/58544。
我基本上是直接使用 V4L2 编写自己的 class 来处理帧抓取。这样您就可以提供缓冲区的循环列表,并允许适当地解耦帧抓取和应用程序逻辑。但是,对于 C++ 应用程序,这是在 C++ 中完成的。假设上面的 link 实现了它的承诺,那可能是一个更简单的方法。我不确定它是否适用于 BeagleBone,但也许那里有类似于 PiCamera 的东西。祝你好运。
编辑:我查看了 OpenCV 2.4.11 的源代码。看起来他们现在默认使用 4 个缓冲区,但您必须使用 V4L2 才能利用它。如果您仔细查看错误消息 HIGHGUI ERROR: V4L: Property...
,您会发现它引用了 V4L,而不是 V4L2。这意味着您正在使用的 OpenCV 构建正在退回到旧的 V4L 驱动程序。除了导致性能问题的单一缓冲区之外,您使用的是一个古老的驱动程序,它可能有很多限制和它自己的性能问题。
最好的办法是自己构建 OpenCV 以确保它使用 V4L2。如果我没记错的话,OpenCV 配置过程会检查机器上是否安装了 V4L2 驱动程序并相应地构建它,因此您需要确保在用于构建 OpenCV 的机器上安装了 V4L2 和任何相关的开发包。
试试这个!我替换了 cap.set() 部分
中的一些代码import cv2
import time
cap=cv2.VideoCapture(0)
cap.set(3,640)
cap.set(4,480)
cap.set(5, 20)
a=30
t=time.time()
while (a>0):
now=time.time()
print now-t
t=now
ret,frame=cap.read()
#Some processes
print a,ret
print frame.shape
a=a-1
k=cv2.waitKey(20)
if k==27:
break
cv2.destroyAllWindows()
输出(pc 网络摄像头)你的代码对我来说是错误的。
>>0.0
>>30 True
>>(480, 640, 3)
>>0.246999979019
>>29 True
>>(480, 640, 3)
>>0.0249998569489
>>28 True
>>(480, 640, 3)
>>0.0280001163483
>>27 True
>>(480, 640, 3)
>>0.0320000648499