再次更新
我使用 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 对你没有用 - 它是不完整的。
我的假设可能是错误的,(我以前曾经做过!)但至少如果它们是公开的,比我更聪明的人可以检查它们!!!