6

I know how to convert an image in the disk to base64 via reading the file. However, in this instance, I already have the image as a numpy array in my program, captured via a camera, like image[:,:,3]. How do I convert it to base64 string such that the image can still be recovered? I tried this.

from base64 import b64encode    
base64.b64encode(image)

It does indeed gives me a string, but when I tested with https://codebeautify.org/base64-to-image-converter, it could not render the image, which means there is something wrong in the conversion. Help please.

I know a solution is to write the image into the disk as a jpg picture and then read it into a base64 string. But obviously, I don't want a file i/o when I can avoid it.

Della
  • 1,264
  • 2
  • 15
  • 32
  • might have to do with the [file signature](https://en.wikipedia.org/wiki/List_of_file_signatures) – rigsby Oct 06 '17 at 05:19
  • It's not clear what type of object `image` is. If it's a `PIL Image`, then you'll need to convert it to a string by calling `save` with a [BytesIO fp parameter](https://pillow.readthedocs.io/en/3.4.x/reference/Image.html#PIL.Image.Image.save). Then you can encode the binary string as you've shown above. If `image` is a `NumPy` array, then you can create a `PIL Image` using `Image.fromarray(..)`. – import random Oct 06 '17 at 05:45
  • image is a numpy.ndarray of dimension [:,:3] and data int64, created via openCV, directly from the camera – Della Oct 06 '17 at 05:48

2 Answers2

8

Here's an example to show what you need to do:

from PIL import Image
import io
import base64
import numpy

# creare a random numpy array of RGB values, 0-255
arr = 255 * numpy.random.rand(20, 20, 3)

im = Image.fromarray(arr.astype("uint8"))
#im.show()  # uncomment to look at the image
rawBytes = io.BytesIO()
im.save(rawBytes, "PNG")
rawBytes.seek(0)  # return to the start of the file
print(base64.b64encode(rawBytes.read()))

I can paste the string printed into the base64 image converter and it'll look similar to im.show(), as the site enlarges the image.

You may need to manipulate your array or provide an appropriate PIL mode when creating your image

import random
  • 3,054
  • 1
  • 17
  • 22
  • If anyone is looking for a solution using OpenCV, this solution does not generate artifacts or discoloration as the solution above: https://stackoverflow.com/questions/40928205/python-opencv-image-to-byte-string-for-json-transfer – Soubriquet Jun 25 '20 at 23:32
0

This is a bit more round-about from the other answers, but in case someone else lands here trying to show an image as a Qt base-64 tooltip, the other methods won't work. I had more luck using a QBuffer and QImage:

# Adapted from https://stackoverflow.com/a/34836998/9463643
import qimage2ndarray as q2n

buffer = QtCore.QBuffer()
buffer.open(buffer.WriteOnly)
buffer.seek(0)

img = (np.random.random((100,100))*255).astype('uint8')
img = q2n.array2qimage(img)

img.save(buffer, "PNG", quality=100)
encoded = bytes(buffer.data().toBase64()).decode() # <-- Here's the base 64 image
html = f'<img src="data:image/png;base64,{encoded}">'
element.setToolTip(html)
ntjess
  • 570
  • 6
  • 10