在 Flask 上处理 opencv 图像(字节,编码为 jpg)API

Dealing with an opencv image (bytes, encoded as jpg) on a Flask API

我的挑战

我需要使用 Flask 发送和接收图像,以便对 1000 多个摄像头流进行实时对象检测。

第 1 部分:将我的视频帧发送到 API

我不想将图像帧保存在我的磁盘上,现在我没有 .png/.jpg 文件可以发送到 Flask API. 我已经将图像数据作为 numpy.array 存储在内存中(我正在使用 cv2.VideoCapture() 从视频流中提取帧)。

如何将 numpy.array 的这些字节发送到 Flask API?

现在我正在尝试使用 cv2.imencode() 对图像进行编码,将其转换为字节,然后使用 base64 对其进行编码。

### frame is a numpy.array with an image
img_encoded = cv2.imencode('.jpg', frame)[1]
img_bytes = img_encoded.tobytes()

所以 img_bytes 是这样的:

b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00C\x00\x02\x01\x01\x01\x01\x01\x02\x01\x01\x01\x02\x02\x02\x02\x02\x04\x03\x02\x02\x02\x02\x05\x04\x04\x03'

我正在尝试在我的 requests.post() 上发送 img_bytes:

files = {'imageData': img_bytes}
res = requests.post('http://127.0.0.1/image', files=files)

我收到 <Response [200]>,但 API 没有按预期工作。我相信我的 Flask 服务器不能很好地处理这个编码字节...所以我的问题可能在第 2 部分。

第 2 部分:在我的 Flask 服务器上接收图像字节并将其转换为 PIL.Image

我定义了一个函数 predict_image(),它接收 PIL.Image.open() 的输出并执行所有对象检测任务。

我的问题是我的变量 imageData 显然无法被 PIL.Image.open() 正确打开。 imageDatatype()<class 'werkzeug.datastructures.FileStorage'>.

在下面的这个片段中,我的网络服务正在检索根据请求接收到的图像,并对其执行 predict_image() 对象检测:

def predict_image_handler(project=None, publishedName=None):
    try:
        imageData = None
        if ('imageData' in request.files):
            imageData = request.files['imageData']
        elif ('imageData' in request.form):
            imageData = request.form['imageData']
        else:
            imageData = io.BytesIO(request.get_data())

        img = Image.open(imageData)
        results = predict_image(img)
        return jsonify(results)

    except Exception as e:
        print('EXCEPTION:', str(e))
        return 'Error processing image', 500

我在向 API 发送图像时没有收到错误消息,但 API 没有按预期工作。我相信它没有以正确的方式将字节转换回图像。

我在这段代码中遗漏了什么?在使用 PIL.Image.open() 打开对象 imageData 之前,我需要对它做什么?

您要向 'imageData' 发送 img_encoded 或 img_bytes 吗?我确实认为将 img_bytes 作为 base64 发送可能会导致类似的行为。 werkzeug.datastructures。 FileStorage 应该代理流方法,但您是否尝试过使用 imageData.stream?

我的代码有一点错误,我试图在 post 上发送 img_encoded 而不是 img_bytes。现在一切正常了。

第 1 部分:发出请求

### frame is a numpy.array with an image
img_encoded = cv2.imencode('.jpg', frame)[1]
img_bytes = img_encoded.tobytes()

files = {'imageData': img_bytes}
response = requests.post(url,
files=files)

第 2 部分:处理接收到的字节

def predict_image_handler(project=None, publishedName=None):
    try:
        imageData = None
        if ('imageData' in request.files):
            imageData = request.files['imageData']
        elif ('imageData' in request.form):
            imageData = request.form['imageData']
        else:
            imageData = io.BytesIO(request.get_data())

        img = Image.open(imageData)
        results = predict_image(img)
        return jsonify(results)

    except Exception as e:
        print('EXCEPTION:', str(e))
        return 'Error processing image', 500