python opencv从bytearray创建图像

Posted

技术标签:

【中文标题】python opencv从bytearray创建图像【英文标题】:python opencv create image from bytearray 【发布时间】:2019-02-25 05:54:46 【问题描述】:

我正在使用 Ricoh Theta V 相机拍摄视频。 It delivers the video as Motion JPEG (MJPEG)。要获取视频,您必须执行 HTTP POST 唉,这意味着我无法使用 cv2.VideoCapture(url) 功能。

因此,根据网络上的众多帖子和 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。

【问题讨论】:

相关问题here 【参考方案1】:

再次更新

我使用 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.6 毫秒对 32.2 毫秒。

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() 包含在计时中,它仍然比内存更快——而且我的机器上有非常快的 3GB/s 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 标记,因为帧的结尾没有相应的无论如何 start 对你没有用 - 它是不完整的。

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

【讨论】:

cv2.imdecode 的性能问题。这是我无论如何都想回答的问题。也许我没有说清楚?如果我写入磁盘并从磁盘读回而不是 imdecode 它会快得多。我想知道谁/什么在对写/读操作进行解码。操作系统? 当我有时间时,我会仔细检查我关于 imread 的声明。但是尽管如此,根据您自己的上述时间,您甚至无法使用 imdecode 获得每秒 10 帧。这对视频来说不是很好!我们正在处理一个视频源。这是假设 python 代码尽可能快,它可能不像你说的那样快。因此,imdecode 再次无法以超过 10 FPS 的速度处理 MJPeg 视频流 我正在测试的图像实际上具有异常高的熵。我只是用更低的熵、更正常的图像再次尝试,这两种方法都花费了大约 30 毫秒,对应于 30+ fps。此外,这只是顺序代码,如果您使用多线程或多处理,则在大多数现代多核桌面上,您可能会将帧速率提高 2-4 倍。 我正在处理一个 1920x1080 的 jpeg 流。在 macbookpro 上。 OSX 10.12.6。处理每张图像需要 imdecode 大约 425000 微秒。 请忘记我关于阅读/写作更快的评论。那是一条红鲱鱼。我已经更新了我的问题。【参考方案2】:

我建议使用 turbo-jpeg。它有一个 python API:PyTurboJPEG。

【讨论】:

这可以是评论而不是答案。

以上是关于python opencv从bytearray创建图像的主要内容,如果未能解决你的问题,请参考以下文章

Python学习笔记015——序列(字节数组 bytearray)

Python 序列 - bytes 和 bytearray

OpenCV从url加载视频

python序列类型:strbytes bytearray list tuple range

python下使用OpenCV实现计算机视觉读书笔记2图像与字节的变换

Python 大白从零开始 OpenCV 学习课-3.图像的创建与修改