Reputation: 658
I'm trying to convert a base64 representation of a JPEG to an image that can be used with OpenCV. The catch is that I'd like to be able to do this without having to physically save the photo (I'd like it to remain in memory). Is there an updated way of accomplishing this?
I'm using python 3.6.2 and OpenCV 3.3
Here is a partial example of the type of input I'm trying to convert:
/9j/4AAQSkZJRgABAQAASABIAAD/4QBYRXhpZgAATU0AKgAAAAgAAgESAAMAAAA....
I've already tried the solutions provided by these questions, but keep getting the same "bad argument type for built-in operation" error:
Upvotes: 15
Views: 42616
Reputation: 316
I have tried all these method but not works for me and have unidentified encoding error.
script that work for me. directly download image using requests and show using PIL
import requests
from io import BytesIO
import base64
from PIL import Image
def image_show(image_url=None):
img_response = requests.get(image_url)
if img_response.ok:
image_bytes = BytesIO(base64.b64decode(base64.b64encode(img_response.content)))
img = Image.open(image_bytes)
return img
else:
print("invalid image url response")
image_show(image_url= 'https://images.unsplash.com/photo-1515628640587-603301d8a4d4?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&dl=shane-stagner-mdS-6oNgRXc-unsplash.jpg')
Upvotes: 0
Reputation: 67
Here are some commands that could be helpful
import io
import cv2
import base64
import numpy as np
from PIL import Image
#convert image to byte type
with open("tes-img/example27.png", "rb") as image_file:
encoded_string1 = base64.b64encode(image_file.read())
#convert byte to string
encoded_string = encoded_string1.decode("utf-8")
#convert string to byte
base64_image = str.encode(encoded_string)
#save image locally
with open("tes-img/example27_2.png", "wb") as fh:
fh.write(base64.decodebytes(base64_image))
#convert byte to numpy array for cv2
img_color = cv2.cvtColor(np.array(Image.open(io.BytesIO(base64.b64decode(base64_image)))), cv2.COLOR_BGR2RGB)
Upvotes: 1
Reputation: 1047
You can also try this:
import numpy as np
import cv2
def to_image_string(image_filepath):
return open(image_filepath, 'rb').read().encode('base64')
def from_base64(base64_data):
nparr = np.fromstring(base64_data.decode('base64'), np.uint8)
return cv2.imdecode(nparr, cv2.IMREAD_ANYCOLOR)
You can now use it like this:
filepath = 'myimage.png'
encoded_string = to_image_string(filepath)
load it with open cv like this:
im = from_base64(encoded_string)
cv2.imwrite('myloadedfile.png', im)
Upvotes: 9
Reputation: 373
Here an example for python 3.6 that uses imageio instead of PIL. It first loads an image and converts it to a b64_string. This string can then be sent around and the image reconstructed as follows:
import base64
import io
import cv2
from imageio import imread
import matplotlib.pyplot as plt
filename = "yourfile.jpg"
with open(filename, "rb") as fid:
data = fid.read()
b64_bytes = base64.b64encode(data)
b64_string = b64_bytes.decode()
# reconstruct image as an numpy array
img = imread(io.BytesIO(base64.b64decode(b64_string)))
# show image
plt.figure()
plt.imshow(img, cmap="gray")
# finally convert RGB image to BGR for opencv
# and save result
cv2_img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
cv2.imwrite("reconstructed.jpg", cv2_img)
plt.show()
Upvotes: 19
Reputation: 658
I've been struggling with this issue for a while now and of course, once I post a question - I figure it out.
For my particular use case, I needed to convert the string into a PIL Image to use in another function before converting it to a numpy array to use in OpenCV. You may be thinking, "why convert to RGB?". I added this in because when converting from PIL Image -> Numpy array, OpenCV defaults to BGR for its images.
Anyways, here's my two helper functions which solved my own question:
import io
import cv2
import base64
import numpy as np
from PIL import Image
# Take in base64 string and return PIL image
def stringToImage(base64_string):
imgdata = base64.b64decode(base64_string)
return Image.open(io.BytesIO(imgdata))
# convert PIL Image to an RGB image( technically a numpy array ) that's compatible with opencv
def toRGB(image):
return cv2.cvtColor(np.array(image), cv2.COLOR_BGR2RGB)
Upvotes: 20