65

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

5 Answers 5

147

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.

Sign up to request clarification or add additional context in comments.

9 Comments

working with cv2 and cv (import cv2, from cv2 import cv). but returned not lplimage and not cvMat. Function GetSize not working
src=image_create_from_string(str) cv.GetSize(src)
I suggest you to work only with cv2 as long as it uses numpy arrays which are much more efficient in Python than cvMat and lplimage. Function GetSize doesn't work in cv2 because cv2 uses numpy and you use np.shape(image) to get the size of your image. In any case, if you want to convert form cv2 ndarray to cv lplimage check this answer: stackoverflow.com/questions/11528009/…
With OpenCV 3+ use cv2.IMREAD_COLOR instead of cv2.CV_LOAD_IMAGE_COLOR
np.fromstring is deprecated now, we should use np.frombuffer. Secondly, if we use raw string in np.frombuffer, it would not provide appropriate numpy arrays. Therefore, it would better to use base64 library for better reading of the string something link base64.b64decode(string). Lastly, I think this answer here (stackoverflow.com/a/58406222/1522905) is better match for this question.
|
32

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)

1 Comment

To make it more verbose: img = cv2.imdecode(jpg_as_np, cv2.IMREAD_COLOR)
11

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

Comments

10

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)

3 Comments

I have this problem too - why does it arise? Is there any way to circumvent the (h,w) issue as in the other answer? Thanks!
Could you define more precisely your problem ?
in this case, there's no header, so you can NOT guess image properties. (unless, you decide you always receive 4/3 or 16/9 ratio images)
3

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.