Python OpenCV 图像到字节字符串以进行 json 传输

Posted

技术标签:

【中文标题】Python OpenCV 图像到字节字符串以进行 json 传输【英文标题】:Python OpenCV Image to byte string for json transfer 【发布时间】:2017-04-17 03:04:13 【问题描述】:

我将 python3numpy、scipy 和 opencv 一起使用。

我正在尝试将通过 OpenCV 和连接的相机接口读取的图像转换为二进制字符串,以通过某些网络连接在 json 对象中发送。

我尝试将数组编码为 jpg 并解码 UTF-16 字符串,但没有得到可用的结果。例如,与

img = get_image()
converted = cv2.imencode('.jpg', img)[1].tostring()
print(converted)

我得到一个字节串作为结果:

b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00C\x00\x02\x01\ x01\x01\x01\x01\x02\x01....

但是这个数据不能作为json对象的内容,因为它包含无效字符。有没有办法可以显示这个字符串后面的真实字节? 我相信\xff代表字节值FF,所以我需要像FFD8FFE0这样的字符串...等等,而不是\xff\xd8\xff\xe0。我做错了什么?

我尝试在上面的代码之后将其编码为 UTF-8 和 UTF16,但我得到了几个错误:

utf_string = converted.decode('utf-16-le')

UnicodeDecodeError:“utf-16-le”编解码器无法解码位置 0-1 中的字节:非法 UTF-16 代理

text = strrrrrr.decode('utf-8')

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte

我想不出办法来解决这个问题。

我还尝试将其转换为 base64 编码字符串,如在 http://www.programcreek.com/2013/09/convert-image-to-string-in-python/ 但这也行不通。 (这个解决方案不是首选,因为它需要将图像临时写入磁盘,这不是我所需要的。最好图像应该只保存在内存中,而不是保存在磁盘上。)

解决方案应该包含一种将图像编码为 json-conform 字符串的方法,以及一种将其解码回 numpy-array 的方法,因此它可以再次与 cv2.imshow() 一起使用。

感谢您的帮助。

【问题讨论】:

可以使用base64编码"in-memory" 【参考方案1】:

您不需要将缓冲区保存到文件中。以下脚本从网络摄像头捕获图像,将其编码为 JPG 图像,然后将该数据转换为可用于 JSON 的可打印 base64 编码:

import cv2
import base64

cap = cv2.VideoCapture(0)
retval, image = cap.read()
retval, buffer = cv2.imencode('.jpg', image)
jpg_as_text = base64.b64encode(buffer)
print(jpg_as_text)
cap.release()

给你一些类似的东西:

/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAMEBgUGBgYFBgYGBwkIBgcJBwYGCAsICQoKCg

这可以扩展为显示如何将其转换回二进制,然后将数据写入测试文件以表明转换成功:

import cv2
import base64

cap = cv2.VideoCapture(0)
retval, image = cap.read()
cap.release()

# Convert captured image to JPG
retval, buffer = cv2.imencode('.jpg', image)

# Convert to base64 encoding and show start of data
jpg_as_text = base64.b64encode(buffer)
print(jpg_as_text[:80])

# Convert back to binary
jpg_original = base64.b64decode(jpg_as_text)

# Write to a file to show conversion worked
with open('test.jpg', 'wb') as f_output:
    f_output.write(jpg_original)

要将图像作为图像缓冲区(而不是 JPG 格式)取回,请尝试:

jpg_as_np = np.frombuffer(jpg_original, dtype=np.uint8)
image_buffer = cv2.imdecode(jpg_as_np, flags=1)

【讨论】:

看起来不错,但是如何将其解码回 numpy 数组? b64decode() 返回解码后的字符串。我试过 image2 = cv2.imdecode(jpg_original, -1),但我得到 TypeError: buf is not a numpy array, not a scalar. 要将其作为图像缓冲区(而不是 JPG 格式)取回,请尝试:jpg_as_np = np.frombuffer(jpg_original, dtype=np.uint8); image_buffer = cv2.imdecode(jpg_as_np, flags=1) 是的,现在它正在使用这个添加。非常感谢! 无法加载图像“test.jpg”。解释 JPEG 图像文件时出错(不是 JPEG 文件:以 0x2f 0x39 开头)打开 test.jpg 时出现此错误【参考方案2】:

上面的答案对我不起作用,它需要一些更新。这是对此的新答案:

为 JSON 编码:

import base64
import json
import cv2

img = cv2.imread('./0.jpg')
string = base64.b64encode(cv2.imencode('.jpg', img)[1]).decode()
dict = 
    'img': string

with open('./0.json', 'w') as outfile:
    json.dump(dict, outfile, ensure_ascii=False, indent=4)

解码回np.array

import base64
import json
import cv2
import numpy as np

response = json.loads(open('./0.json', 'r').read())
string = response['img']
jpg_original = base64.b64decode(string)
jpg_as_np = np.frombuffer(jpg_original, dtype=np.uint8)
img = cv2.imdecode(jpg_as_np, flags=1)
cv2.imwrite('./0.jpg', img)

希望这可以帮助某人:P

【讨论】:

拜托,你已经读过 cv2.imencode 到 base64encode 有什么用? @AndoJurai 有时我们已经将 img 作为 np 数组,而不是我们可以读取并获取 base64 字符串表示的文件

以上是关于Python OpenCV 图像到字节字符串以进行 json 传输的主要内容,如果未能解决你的问题,请参考以下文章

Python - 使用 OpenCV 将字节图像转换为 NumPy 数组

如何在python中使用opencv复制图像区域?

python opencv3 图像与原始字节转换

如何在Python中使用OpenCV以特定顺序显示图像?

Flask OpenCV 以字节为单位发送和接收图像

[opencv-python]学习-图像分割