Reputation: 943
I'm trying to load image from string like as PHP function imagecreatefromstring
How can I do that?
I have MySQL blob field image. I'm using MySQLdb and don't want create temporary file for working with images in PyOpenCV.
NOTE: need cv (not cv2) wrapper function
Upvotes: 65
Views: 176563
Reputation: 26572
This is what I normally use to convert images stored in database to OpenCV images in Python.
import numpy as np
import cv2
from cv2 import cv
# Load image as string from file/database
fd = open('foo.jpg','rb')
img_str = fd.read()
fd.close()
# CV2
nparr = np.fromstring(img_str, np.uint8)
img_np = cv2.imdecode(nparr, cv2.CV_LOAD_IMAGE_COLOR) # cv2.IMREAD_COLOR in OpenCV 3.1
# CV
img_ipl = cv.CreateImageHeader((img_np.shape[1], img_np.shape[0]), cv.IPL_DEPTH_8U, 3)
cv.SetData(img_ipl, img_np.tostring(), img_np.dtype.itemsize * 3 * img_np.shape[1])
# check types
print type(img_str)
print type(img_np)
print type(img_ipl)
I have added the conversion from numpy.ndarray
to cv2.cv.iplimage
, so the script above will print:
<type 'str'>
<type 'numpy.ndarray'>
<type 'cv2.cv.iplimage'>
EDIT:
As of latest numpy 1.18.5 +
, the np.fromstring
raise a warning, hence np.frombuffer
shall be used in that place.
Upvotes: 146
Reputation: 1183
One gotcha of imdecode:
If the buffer is too short or contains invalid data, the function returns [None]
This feels uncharacteristically lenient from OpenCV. Here's a function that accommodates for this:
import numpy as np
import cv2 as cv
def read_image(content: bytes) -> np.ndarray:
"""
Image bytes to OpenCV image
:param content: Image bytes
:returns OpenCV image
:raises TypeError: If content is not bytes
:raises ValueError: If content does not represent an image
"""
if not isinstance(content, bytes):
raise TypeError(f"Expected 'content' to be bytes, received: {type(content)}")
image = cv.imdecode(np.frombuffer(content, dtype=np.uint8), cv.IMREAD_COLOR)
if image is None:
raise ValueError(f"Expected 'content' to be image bytes")
return image
Upvotes: 3
Reputation: 5723
I was following the solution from @jabaldonedo but it seems it's a bit old and need some adjustments.
I am using OpenCV 3.4.8.29 by the way.
im_path = 'path/to/foo.jpg'
with open(im_path, 'rb') as fp:
im_b = fp.read()
image_np = np.frombuffer(im_b, np.uint8)
img_np = cv2.imdecode(image_np, cv2.IMREAD_COLOR)
im_cv = cv2.imread(im_path)
print('Same image: {}'.format(np.all(im_cv == img_np)))
Same image: True
Upvotes: 10
Reputation: 660
I think this answer provided on this stackoverflow question is a better answer for this question.
Quoting details (borrowed from @lamhoangtung from above linked answer)
import base64
import json
import cv2
import numpy as np
response = json.loads(open('./0.json', 'r').read())
string = response['img']
jpg_original = base64.b64decode(string)
jpg_as_np = np.frombuffer(jpg_original, dtype=np.uint8)
img = cv2.imdecode(jpg_as_np, flags=1)
cv2.imwrite('./0.jpg', img)
Upvotes: 32
Reputation: 2558
I've try to use this code to create an opencv from a string containing a raw buffer (plain pixel data) and it doesn't work in that peculiar case.
So here's how to do that for this kind of data:
image = np.fromstring(im_str, np.uint8).reshape( h, w, nb_planes )
(but yes you need to know your image properties)
if your B and G channel is permuted, here's how to fix it:
image = cv2.cvtColor(image, cv2.cv.CV_BGR2RGB)
Upvotes: 10