python opencv从字节数组创建图像

时间:2019-02-25 05:54:46

标签: opencv python-3.7 opencv4

我正在从理光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。

2 个答案:

答案 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 标记,因为帧末没有相应的无论如何,开始对您没有用-它不完整。

我的假设可能是错误的,(我以前有过!),但至少如果它们是公开的,那么有人比我聪明可以检查它们!!!