Python OpenCV从字节字符串加载图像

61

我想从字符串中加载图像,就像PHP函数imagecreatefromstring一样。

我该怎么做?

我有一个MySQL blob字段图像。我正在使用MySQLdb,不想为在PyOpenCV中处理图像而创建临时文件。

注意:需要cv(而不是cv2)包装函数

5个回答

142
这是我通常在Python中使用的方法,将存储在数据库中的图像转换为OpenCV图像。
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)

我已经添加了从numpy.ndarraycv2.cv.iplimage的转换,所以上面的脚本将打印出:
<type 'str'>
<type 'numpy.ndarray'>
<type 'cv2.cv.iplimage'>

编辑: 截至最新的numpy版本1.18.5 +np.fromstring会引发警告,因此应该在该位置使用np.frombuffer


使用cv2和cv进行编程(import cv2,from cv2 import cv)。但返回的不是lplimage和cvMat。函数GetSize无法工作。 - featureoffuture
我了解。你能否用CV包装器编写该函数? - featureoffuture
我已更新代码,现在您可以按照CV格式输出。 - jabaldonedo
26
在使用OpenCV 3+时,使用cv2.IMREAD_COLOR代替cv2.CV_LOAD_IMAGE_COLOR - uglide
4
现在np.fromstring已经被弃用,我们应该使用np.frombuffer。其次,如果在np.frombuffer中使用原始字符串,则可能无法提供适当的numpy数组。因此,最好使用base64库来更好地读取字符串,例如base64.b64decode(string)。最后,我认为这个答案(https://dev59.com/j1gR5IYBdhLWcg3wu_f4#58406222)更适合这个问题。 - Anugraha Sinha
显示剩余4条评论

31

我认为在这个stackoverflow问题中提供的这个答案是更好的答案。

引用细节(借用自上面链接的@lamhoangtung)

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)

3
为了让它更加冗长: img = cv2.imdecode(jpg_as_np, cv2.IMREAD_COLOR) - Marcus

10

我尝试使用这段代码从包含原始缓冲区(即纯像素数据)的字符串创建一个OpenCV,但在这种特殊情况下它不起作用。

所以这里是如何处理这种类型的数据:

image = np.fromstring(im_str, np.uint8).reshape( h, w, nb_planes )

(但是,您需要了解图像属性。)

如果您的B和G通道被置换了,以下是如何修复它:

image = cv2.cvtColor(image, cv2.cv.CV_BGR2RGB)

我也有这个问题 - 为什么会出现这种情况?是否有任何方法可以像其他答案中那样规避(h,w)问题?谢谢! - jtlz2
你能更精确地定义你的问题吗? - Alexandre Mazel
在这种情况下,您不能猜测图像属性(除非您决定始终接收4/3或16/9比例的图像)。 - Alexandre Mazel

8

我正在关注@jabaldonedo的解决方案,但它似乎有点过时,需要进行一些调整。

顺便说一下,我正在使用OpenCV 3.4.8.29。

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)))

同一图像:真

2

imdecode 的一个注意点:

如果缓冲区太短或包含无效数据,则该函数返回 [None]

这在 OpenCV 中感觉不太严格。下面是一个可以适应此情况的函数:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接