【问题标题】:Decode image bytes data stream to JPEG将图像字节数据流解码为 JPEG
【发布时间】:2020-10-02 12:17:03
【问题描述】:

我正在努力成功地从字节解码 JPEG 图像,然后再次解码为 JPEG。

我从 MJPG 字节流中的编码帧开始,我想对其进行解码以便使用 OpenCV 进行操作。我是 Python、numpy、opencv 等方面的新手!

我现在将文本文件中的帧 JPG 数据保存为:b'\xf\xd8\xff\xdb\x00..etc 等用于测试目的:

当我尝试在第 14 行 (npFlat.reshape((640,480)) 上将 numpy 数组的大小调整为原始视频流分辨率 (640, 480) 时,代码似乎失败了

**ValueError: 无法将大小为 228140 的数组重新整形为 (640,480)*

import io
import cv2
import numpy as np

BytesFile = open('FrameBytes.txt')
MyBytes=BytesFile.read()
BytesFile.close()

dt=np.dtype(np.unit8)
dt=dt.newbtyeorder('>')

npFlat = np.fromfile('FrameBytes.txt'.dtype=dt)
npResized = npFlat.reshape(640,480,3) #CODE FAILING TO RESIZE AT THIS LINE...
cv.imshow('resized',npResized)

难道即使我的视频帧是从 640、480 源中捕获的,但由于某种原因,在编码过程中大小发生了变化?这就是我目前所能想到的。欢迎任何/所有帮助。

我已经查看了相关帖子:Python - byte image to NumPy array using OpenCV,但试图避免 PIL,并且 frombuffer 方法对我来说似乎也失败了。

好的,所以我取得了一些进展,现在有了:

npFlat = np.frombuffer(MyBytes.encode('utf-8'),dtype=np.int8).

当我将 npFlat 'reshape' 为 (374, 610) 时,我现在也可以让代码成功。 IE。所以 374 x 610 = 长度为 228140 的平面 numpy 数组......但这一切似乎都很奇怪。缓冲区信息代表我正在尝试重新打开的 JPG……但还没有关闭。

MyBytes.txt" 数据输入文件可在此处查看: https://drive.google.com/file/d/18pqILl9myeTRjdiqtExFyOe94Km_aNNM/view?usp=sharing]1

【问题讨论】:

  • 嗯,因为 640*480*3 != 228140。调整大小是指整形还是重新采样?
  • 重塑 - 我在原始帖子中添加了更多信息。我正在尝试从缓冲区(已知帧)解码 JPG 以使用 opencv 打开和编辑...
  • YourMyBytes 对象具有实际的 JPG 文件字节 - 必须首先使用例如 PIL 将其解码为像素数据的内存表示,然后才能将其视为图像在 Python 代码中。
  • 请发布您的实际代码!我相当肯定import nump as np 不会运行。 newbtyorder 也没有。此外,请使用 Dropbox 或 GoogleDrive 或其他方式共享您的输入文件。谢谢。
  • 谢谢,马克明天晚上回来。在上面的 numpy 导入上修改了错字 - 我正在努力跨 VNC 复制我的实际代码。 newbyteorder 我现在没有使用。似乎没有必要。

标签: python-3.x numpy image-processing jpeg string-decoding


【解决方案1】:

您的 FrameBytes.txt 文件,尽管扩展名实际上是 JPG 文件 (除非你在保存时弄乱了它)。

所以,你没有用适当的图像阅读器阅读它,而不是字节, 如果您想将其作为图像进行操作。否则,你有 JPEG 编码字节 - 磁盘上的 228140 字节代表图像 解压后有 921600 字节的数据。 (这是合理的 高质量的 jpeg 文件)。

只需使用 PIL 即可:


from PIL import Image

img = Image.open("FrameBytes.txt")
print(img.size) # this should print (640, 480).

# to convert it to a numpy array:
import numpy as np
data = np.array(list(img.tobytes()), dtype="uint8")
data.shape = img.size + (3,)

...

如果您不想使用 PIL,当然,您可以使用其他库 - o​​pencv 本身具有开箱即用的 cv2.imread 方法。

【讨论】:

  • 嗨 jsbueno - 我得到:操作系统错误:当我尝试使用 Image.open() 打开时无法识别图像文件“FrameBytes.txt”。奇怪 - 我确信文本文件中的字节代表我从 MJPEG 流输出的帧。
  • 是的,但我包括了评论“除非你在保存时出现乱码”。您将文件错误地视为文本文件。由于您没有描述保存文件时使用的过程或代码,因此我无法猜测。如果您使用的是 Mac 或 Linux,请尝试运行“file”shell 命令来识别文件。在 Windows 上,将文件扩展名更改为“.jpg”而不是“txt”——尽管这不会干扰 PIL 识别它。
  • 使用 Linux Shell 文件命令,返回:“ASCII 文本,行很长,没有行终止符”。文件来源是:我将 JPG 帧作为字节打印到 python 终端,然后复制粘贴到文本文件中。这是为了让我练习和测试将字节转换为 openCV 图像以在处理程序上工作的方法,然后编码回字节以便在我输出字节的另一个工作视频流应用程序中继续流式传输。我会尽快分享文件。
【解决方案2】:

你搞得一团糟——你应该避免将二进制数据保存为文本文件!

将文件内容复制到剪贴板 - 在 Mac 上,命令是:

cat frame.txt | pbcopy

启动 Python 并创建一个名为 s 的变量并将其设置为剪贴板的内容:

s = PASTE_YOUR_CLIPBOARD

现在做:

from PIL import Image
from io import BytesIO

# Load image from BytesIO
im = Image.open(BytesIO(s))

# Display image and save image
im.show()
im.save('result.png')

如果您使用的是 OpenCV,请使用:

import cv2

# Make s as above
s = PASTE_YOUR_CLIPBOARD

i = np.frombuffer(s,dtype=np.uint8)

im = cv2.imdecode(i,cv2.IMREAD_UNCHANGED)

cv2.imwrite('result.png',im)

【讨论】:

  • 马克-谢谢!我认为是下游的“frombuffer”imdecode 位在我的(OpenCV)方法中失败了。感谢您确认情况并非如此!
  • 纯粹从学术角度来看,您能否分享应该如何将二进制数据保存到文件并导入(即不是文本文件!:-))?
  • 如果你有一个 Numpy 数组中的图像,你可以像这样使用np.save('frame.npy', image)...numpy.org/doc/1.18/reference/generated/numpy.save.html
  • 谢谢。我从这次经历中学到了很多东西,我原来的帖子试图用不正确的方式做一些事情,使用不正确的数据输入! - 我的问题现已解决,我可以继续寻找下一个问题!
猜你喜欢
  • 1970-01-01
  • 2011-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-05
  • 1970-01-01
  • 1970-01-01
  • 2013-01-12
相关资源
最近更新 更多