我正在从理光Theta V摄像机捕获视频。 It delivers the video as Motion JPEG (MJPEG)。要获取视频,您必须执行HTTP POST las,这意味着我无法使用cv2.VideoCapture(url)
功能。
因此,在Web和SO上的大量帖子中执行此操作的方式如下:
bytes = bytes()
while True:
bytes += stream.read(1024)
a = bytes.find(b'\xff\xd8')
b = bytes.find(b'\xff\xd9')
if a != -1 and b != -1:
jpg = bytes[a:b+2]
bytes = bytes[b+2:]
i = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
cv2.imshow('i', i)
if cv2.waitKey(1) == 27:
exit(0)
除了速度慢之外,它实际上是可行的。我正在处理1920x1080 jpeg流。在运行OSX 10.12.6的Mac Book Pro上。调用imdecode
大约需要425000微秒来处理每个图像
有没有想法如何在没有imdecode
的情况下执行此操作或使imdecode
更快?我希望它能以60FPS的速度播放高清视频(至少)。
我正在使用Python3.7和OpenCV4。
答案 0 :(得分:0)
我建议使用turbo-jpeg。它具有python API:PyTurboJPEG。
答案 1 :(得分:0)
再次更新
我使用PyTurboJPEG从内存缓冲区中进行JPEG解码,代码类似于OpenCV的imdecode()
:
#!/usr/bin/env python3
import cv2
from turbojpeg import TurboJPEG, TJPF_GRAY, TJSAMP_GRAY
# Load image into memory
r = open('image.jpg','rb').read()
inp = np.asarray(bytearray(r), dtype=np.uint8)
# Decode JPEG from memory into Numpy array using OpenCV
i0 = cv2.imdecode(inp, cv2.IMREAD_COLOR)
# Use default library installation
jpeg = TurboJPEG()
# Decode JPEG from memory using turbojpeg
i1 = jpeg.decode(r)
cv2.imshow('Decoded with TurboJPEG', i1)
cv2.waitKey(0)
答案是TurboJPEG快7倍!这是4.6ms和32.2ms。
In [18]: %timeit i0 = cv2.imdecode(inp, cv2.IMREAD_COLOR)
32.2 ms ± 346 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [19]: %timeit i1 = jpeg.decode(r)
4.63 ms ± 55.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
对@Nuzhny第一次发现表示敬意!
更新后的答案
我一直在对此进行进一步的基准测试,但无法验证您的主张,即将图像保存到磁盘并用imread()
读取比使用内存中的imdecode()
更快。 。这是我在IPython中进行测试的方式:
import cv2
# First use 'imread()'
%timeit i1 = cv2.imread('image.jpg', cv2.IMREAD_COLOR)
116 ms ± 2.86 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# Now prepare the exact same image in memory
r = open('image.jpg','rb').read()
inp = np.asarray(bytearray(r), dtype=np.uint8)
# And try again with 'imdecode()'
%timeit i0 = cv2.imdecode(inp, cv2.IMREAD_COLOR)
113 ms ± 1.17 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
因此,我发现imdecode()
比计算机上的imread()
快3%。即使我将np.asarray()
包含在时间中,它在内存上的速度仍然比磁盘快-而且我的计算机上的3ME / NVME磁盘速度非常快...
原始答案
我还没有测试过,但是在我看来,您是在循环执行此操作:
read 1k bytes
append it to a buffer
look for JPEG SOI marker (0xffdb)
look for JPEG EOI marker (0xffd9)
if you have found both the start and the end of a JPEG frame, decode it
1)现在,大多数具有任何有趣内容的JPEG图像都在30kB到300kB之间,因此您将对缓冲区执行30-300次追加操作。我对Python知之甚少,但我想这可能会导致内存重新分配,这可能很慢。
2)接下来,您将在前1kB中查找 SOI 标记,然后在前2kB中再次查找,然后在前3kB中再次查找,然后在前4kB中再次查找-即使您已经找到了!
3)同样,您将在前1kB,前2kB中寻找 EOI 标记...
所以,我建议您尝试:
1)在开始时分配更大的缓冲区,并以适当的偏移量直接获取到其中
2)如果已经找到 SOI 标记,则不进行搜索-例如在每帧开始时将其设置为-1
,只有在它仍然-1
时才尝试找到它
3)仅在每次迭代的新数据中寻找 EOI 标记,而不是在先前迭代中已搜索的所有数据中寻找
4)而且,实际上,除非您已经找到了 SOI 标记,否则不要费心寻找 EOI 标记,因为帧末没有相应的无论如何,开始对您没有用-它不完整。
我的假设可能是错误的,(我以前有过!),但至少如果它们是公开的,那么有人比我聪明可以检查它们!!!