使用 OpenCv python 库从内存中读取 base 64 编码图像

2022-01-21 00:00:00 python numpy opencv encoding base64

问题描述

我正在开发一个应用程序,该应用程序可以从网络摄像头流中进行一些面部识别.我得到了画布的 base64 编码数据 uri,并想用它来做这样的事情:

cv2.imshow('image',img)

数据 URI 如下所示:

 <代码>数据:图像/GIF; BASE64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBS/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7

所以,为了清楚起见,我已经展示了图像的样子,因此 base64 字符串不会被破坏.

<预类= 片段码-HTML语言HTML的prettyprint-越权"> <代码>< IMG SRC = 数据:图像/GIF; BASE64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBS/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" >

官方文档说,imread 接受文件路径作为参数.从 this SO 回答,如果我这样做:

 导入 base64imgdata = base64.b64decode(imgstring) #我在下面的参考资料中使用 imgdata 作为这个变量本身文件名 = 'some_image.jpg'使用 open(filename, 'wb') 作为 f:f.write(imgdata)

上面的代码片段可以正常工作,并且图像文件可以正确生成.但是,考虑到我会为流的每一帧都这样做,我认为这么多文件 IO 操作是不可行的.我希望能够直接创建 img 对象将图像读入内存.

我尝试了两种似乎对某些人有效的解决方案.

  1. 使用 PIL 参考:

    pilImage = Image.open(StringIO(imgdata))npImage = np.array(pilImage)matImage = cv.fromarray(npImage)

    我得到 cv 未定义,因为我安装了 openCV3,它可以作为 cv2 模块使用.我试过 img = cv2.imdecode(npImage,0),这什么也没返回.

  2. 从解码的字符串中获取字节并将其转换为一个 numpy 数组

    file_bytes = numpy.asarray(bytearray(imgdata), dtype=numpy.uint8)img = cv2.imdecode(file_bytes, 0) #这里也没有返回

文档并没有真正提到 imdecode 函数返回什么.但是,根据我遇到的错误,我猜它期望 numpy arrayscalar 作为第一个参数.我如何在内存中处理该图像,以便我可以执行 cv2.imshow('image',img) 以及之后的各种很酷的东西.

我希望我能说清楚.

解决方案

你可以像这样同时使用cv2和pillow:

导入base64从 PIL 导入图像导入简历2从 StringIO 导入 StringIO将 numpy 导入为 npdef readb64(base64_string):sbuf = StringIO()sbuf.write(base64.b64decode(base64_string))pimg = Image.open(sbuf)返回 cv2.cvtColor(np.array(pimg), cv2.COLOR_RGB2BGR)cvimg = readb64( 'R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBS/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7')cv2.imshow(cvimg)

I'm working on an app that to do some facial recognition from a webcam stream. I get base64 encoded data uri's of the canvas and want to use it to do something like this:

cv2.imshow('image',img)

The data URI looks something like this:

 data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7

So, for clarity I've shown what the image looks like so the base64 string is not broken.

<img src="data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7">

The official doc says, that imread accepts a file path as the argument. From this SO answer, if I do something like:

 import base64
 imgdata = base64.b64decode(imgstring) #I use imgdata as this variable itself in references below
 filename = 'some_image.jpg'
 with open(filename, 'wb') as f:
    f.write(imgdata)

The above code snippet works and the image file gets generated properly. However I don't think so many File IO operations are feasible considering I'd be doing this for every frame of the stream. I want to be able to read the image into the memory directly creating the img object.

I have tried two solutions that seem to be working for some people.

  1. Using PIL reference:

    pilImage = Image.open(StringIO(imgdata))
    npImage = np.array(pilImage)
    matImage = cv.fromarray(npImage)
    

    I get cv not defined as I have openCV3 installed which is available to me as cv2 module. I tried img = cv2.imdecode(npImage,0), this returns nothing.

  2. Getting the bytes from decoded string and converting it into an numpy array of sorts

    file_bytes = numpy.asarray(bytearray(imgdata), dtype=numpy.uint8)
    img = cv2.imdecode(file_bytes, 0) #Here as well I get returned nothing
    

The documentation doesn't really mention what the imdecode function returns. However, from the errors that I encountered, I guess it is expecting a numpy array or a scalar as the first argument. How do I get a handle on that image in memory so that I can do cv2.imshow('image',img) and all kinds of cool stuff thereafter.

I hope I was able to make myself clear.

解决方案

You can just use both cv2 and pillow like this:

import base64
from PIL import Image
import cv2
from StringIO import StringIO
import numpy as np

def readb64(base64_string):
    sbuf = StringIO()
    sbuf.write(base64.b64decode(base64_string))
    pimg = Image.open(sbuf)
    return cv2.cvtColor(np.array(pimg), cv2.COLOR_RGB2BGR)

cvimg = readb64('R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7')
cv2.imshow(cvimg)

相关文章