web-dev-qa-db-fra.com

Lire une image codée en base 64 à partir de la mémoire en utilisant OpenCv python

Je travaille sur une application qui permet de faire une reconnaissance faciale à partir d'un flux webcam. J'obtiens des uri de données encodées en base64 du canevas et je veux l'utiliser pour faire quelque chose comme ceci:

cv2.imshow('image',img)

L'URI de données ressemble à ceci:

 data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7

Donc, pour plus de clarté, j'ai montré à quoi ressemble l'image afin que la chaîne base64 ne soit pas cassée.

<img src="data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7">

Le doc officiel dit que imread accepte un chemin de fichier comme argument. De this SO answer, si je fais quelque chose comme:

 import base64
 imgdata = base64.b64decode(imgstring) #I use imgdata as this variable itself in references below
 filename = 'some_image.jpg'
 with open(filename, 'wb') as f:
    f.write(imgdata)

L'extrait de code ci-dessus fonctionne et le fichier image est généré correctement. Cependant, je ne pense pas que tant d'opérations File IO sont possibles étant donné que je ferais cela pour chaque trame du flux. Je veux pouvoir lire l'image dans la mémoire en créant directement l'objet img.

J'ai essayé deux solutions qui semblent fonctionner pour certaines personnes.

  1. En utilisant PIL référence :

    pilImage = Image.open(StringIO(imgdata))
    npImage = np.array(pilImage)
    matImage = cv.fromarray(npImage)
    

    J'obtiens cv non défini car j'ai installé openCV3 qui est disponible pour moi en tant que module cv2. J'ai essayé img = cv2.imdecode(npImage,0), cela ne renvoie rien.

  2. Obtenir les octets de la chaîne décodée et la convertir en un tableau numpy de toutes sortes

    file_bytes = numpy.asarray(bytearray(imgdata), dtype=numpy.uint8)
    img = cv2.imdecode(file_bytes, 0) #Here as well I get returned nothing
    

La documentation ne mentionne pas vraiment ce que la fonction imdecode renvoie. Cependant, d'après les erreurs que j'ai rencontrées, je suppose qu'il attend un numpy array Ou un scalar comme premier argument. Comment puis-je obtenir une poignée sur cette image en mémoire afin que je puisse faire cv2.imshow('image',img) et toutes sortes de trucs sympas par la suite.

J'espère avoir pu me clarifier.

18
Vivek Pradhan

Vous pouvez simplement utiliser à la fois cv2 et oreiller comme ceci:

import base64
from PIL import Image
import cv2
from StringIO import StringIO
import numpy as np

def readb64(base64_string):
    sbuf = StringIO()
    sbuf.write(base64.b64decode(base64_string))
    pimg = Image.open(sbuf)
    return cv2.cvtColor(np.array(pimg), cv2.COLOR_RGB2BGR)

cvimg = readb64('R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7')
cv2.imshow(cvimg)
8
Jonno_FTW

Cela a fonctionné pour moi, et ne nécessite pas de PIL/oreiller ou d'autres dépendances (sauf cv2):

import cv2
import numpy as np

def data_uri_to_cv2_img(uri):
    encoded_data = uri.split(',')[1]
    nparr = np.fromstring(encoded_data.decode('base64'), np.uint8)
    img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    return img

data_uri = "data:image/jpeg;base64,/9j/4AAQ..."
img = data_uri_to_cv2_img(data_uri)
cv2.imshow(img)
22
Lior

Ceci est ma solution pour python 3.7 et sans utiliser PIL

import base64

def readb64(uri):
   encoded_data = uri.split(',')[1]
   nparr = np.fromstring(base64.b64decode(encoded_data), np.uint8)
   img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
   return img

j'espère que cette solution fonctionne pour tous

16
Javier Vallejos