Отправка изображения OpenCV в формате JSON - PullRequest
1 голос
/ 28 апреля 2019

Я пытаюсь отправить изображение OpenCV в формате json и получить его на другом конце, но у меня возникают бесконечные проблемы с кодированием и декодированием изображения

Я отправляю его в 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)

Но тогда я получаю 'NoneType' object has no attribute '__array_interface__' от Image.fromarray

Есть идеи, что я делаю неправильно?

1 Ответ

1 голос
/ 29 апреля 2019

Надеюсь, это поможет вам начать.Я думаю, что то, что вы попробовали, отправив необработанные байты из массива 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()

Поскольку вы не ответили на мой вопрос в комментариях о , почему вы хотите действовать таким образом, это может быть неоптимальным - отправка несжатых изображений в кодировке base64 по сети(предположительно) не очень эффективно.Вы можете использовать JPEG или PNG-кодированные данные для экономии пропускной способности сети, например.

Вы также можете использовать cPickle .


Обратите внимание, что некоторые люди не одобряютpickle, а также вышеописанный метод использует большую пропускную способность сети.Альтернативой может быть сжатие изображения JPEG перед отправкой и распаковка на принимающем конце прямо в изображение PIL.Обратите внимание, что это с потерями .

Или измените расширение .JPG в коде на .PNG, которое без потерь, но может быть медленнее и не будет работать для изображений с данными с плавающей запятой или 16-битными данными (хотя последнее может быть

Вы также можете посмотреть на TIFF, но, опять же, это зависит от характера ваших данных, пропускной способности сети, необходимой вам гибкости, производительности кодирования / декодирования вашего процессора ...

#!/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()
...