【问题标题】:Sending OpenCV image in JSON以 JSON 格式发送 OpenCV 图像
【发布时间】:2019-04-28 16:34:57
【问题描述】:

我正在尝试以 json 格式发送 OpenCV 图像并在另一端接收它,但我在编码和解码图像时遇到了无穷无尽的问题

我通过以下方式以 JSON 格式发送:

dumps({"image": b64encode(image[y1:y2, x1:x2]).decode('utf-8')})

在另一端我尝试解码它(我需要它作为枕头图像):

image = Image.open(BytesIO(base64.b64decode(data['image'])))

但我收到了Exception cannot identify image file <_io.BytesIO object at 0x7fbd34c98a98>

也试过了:

nparr = np.fromstring(b64decode(data['image']), np.uint8)
image = cv2.imdecode(nparr, cv2.COLOR_BGR2RGB)
pil_image = Image.fromarray(image)

然后我得到来自Image.fromarray'NoneType' object has no attribute '__array_interface__'

任何想法我做错了什么?

【问题讨论】:

  • 您需要更清楚地了解您要发送的确切内容以及为什么要将其作为 JSON 发送。你想只发送与像素对应的字节,还是一个 Numpy 数组,或者你想发送 JPEG 或 PNG 压缩图像。也许您可以为每一端共享一段更完整的代码 - 发送和接收?
  • 我正在使用以下image[y1:y2, x1:x2] 从 OpenCV 图像中取出一个矩形(所以我认为它应该是一个 numpy 数组),我想以 json 格式发送它。我认为向其中添加不相关的代码不是一个好主意,只会让问题变得不那么清楚,它现在是
  • 好的,如果你要发送一个 Numpy 数组,你需要在接收端使用这个 PILimage = Image.fromarray(NumpyArray)
  • 已经试过了,我想我可能发送错误的图像

标签: python json opencv base64 python-imaging-library


【解决方案1】:

希望这可以帮助您入门。我认为您尝试通过从 Numpy 数组发送未经修饰的字节可能无法正常工作,因为接收器不会知道图像中通道的宽度、高度和数量,所以我使用 pickle 来存储它。

#!/usr/bin/env python3

import cv2
import numpy as np
import base64
import json
import pickle
from PIL import Image

def im2json(im):
    """Convert a Numpy array to JSON string"""
    imdata = pickle.dumps(im)
    jstr = json.dumps({"image": base64.b64encode(imdata).decode('ascii')})
    return jstr

def json2im(jstr):
    """Convert a JSON string back to a Numpy array"""
    load = json.loads(jstr)
    imdata = base64.b64decode(load['image'])
    im = pickle.loads(imdata)
    return im

# Create solid red image 
red = np.full((480, 640, 3), [0, 0, 255], dtype=np.uint8)  

# Make image into JSON string
jstr = im2json(red)

# Extract image from JSON string, and convert from OpenCV to PIL reversing BGR to RGB on the way
OpenCVim = json2im(jstr)
PILimage = Image.fromarray(OpenCVim[...,::-1])
PILimage.show()

由于您尚未在 cmets 中回答我关于 为什么 您想要以这种方式做事的问题,因此它可能不是最佳选择 - 通过网络(大概)发送未压缩的 base64 编码图像是效率不高。例如,您可以考虑使用 JPEG 或 PNG 编码数据来节省网络带宽。

您也可以改用cPickle


请注意,有些人不赞成pickle,而且上面的方法使用了大量的网络带宽。另一种方法可能是 JPEG 在发送之前压缩图像,然后在接收端直接解压缩为 PIL 图像。请注意,这是有损

或者将代码中的.JPG 扩展名更改为.PNG,这是无损的,但速度可能较慢,并且不适用于具有浮点数据或16 位数据的图像(尽管可以容纳后者)。

您也可以查看 TIFF,但同样,它取决于数据的性质、网络带宽、所需的灵活性、CPU 的编码/解码性能...

#!/usr/bin/env python3

import cv2
import numpy as np
import base64
import json
from io import BytesIO
from PIL import Image

def im2json(im):
    _, imdata = cv2.imencode('.JPG',im)
    jstr = json.dumps({"image": base64.b64encode(imdata).decode('ascii')})
    return jstr

def json2im(jstr):
    load = json.loads(jstr)
    imdata = base64.b64decode(load['image'])
    im = Image.open(BytesIO(imdata))
    return im

# Create solid red image 
red = np.full((480, 640, 3), [0, 0, 255], dtype=np.uint8)  

# Make image into JSON string
jstr = im2json(red)

# Extract image from JSON string into PIL Image
PILimage = json2im(jstr)
PILimage.show()

【讨论】:

  • 完美运行,谢谢!你能解释一下这部分OpenCVim[...,::-1],为什么不按原样传递图像?
  • OpenCV 以奇怪的 BGR 顺序存储图像,而 PIL 期望图像以正常的 RGB 顺序,所以如果你不做OpenCVim[...,::-1] 的事情来反转通道顺序,你的红色和蓝色将被交换.如果速度很重要,使用 OpenCV 的 cvtColor(...BGR2RGB...) 方法可能更快。
猜你喜欢
  • 2016-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多