通过Flask将Numpy数组从Python以字节形式发送到JS

8
使用 Flask 将 Numpy 数组从 Python 发送到 JS。我不想使用 jsonify 将其发送,因为这样会增加响应大小并最终增加响应时间。因此,我考虑使用 tobytes() 将 numpy 转换为字节,通过 Flask 将字节发送到 JS,并在 JS 中将字节转换回浮点数,我发现 Converting a string of packed bytes into an array of floats in Javascript 的解答很有用。
操作列表如下:
byte_arr = np.array([5.6], dtype=np.float32).tobytes()  # Used one value just to make it simple
return byte_arr  # Bytes can be directly sent from flask as response

在JS中,
str = response.text
bytes = Uint8Array.from(str, c => c.charCodeAt(0))
floats = new Float32Array(bytes.buffer)

但是在JS中转换为float时,我得不到正确的值。在调试过程中,我发现在JS中,一些Uint8数组中的值与从Python发送的字节值不匹配。

JS: console.log(bytes)  // [51, 51, 255, 64]
Python: for val in byte_arr: print(val, end=" ")  // 51, 51, 179, 64

仅为了验证,我在Python中创建了另一个客户端,发出了相同的请求,并将响应字节转换为浮点数。我在这里也遇到了相同的问题。因此,我缩小了问题范围,发现问题出现在服务器端而不是客户端。

在尝试多个值时,我发现有趣的一件事是,只有大于127(我猜是)的数字才会被转换为255。

在尝试一些随机的hack时,在发送响应之前,我尝试使用Python的chr()方法将字节整数转换为字符,并且在客户端上进行了转换。

byte_arr = np.array([5.6], dtype=np.float32).tobytes()
byte_arr_char = "".join([chr(i) for i in byte_arr])
return byte_arr_char

但我的问题是,这是否是一个理想的解决方案,或者我在进行一些 hack 才能使其正常工作?有人能帮我理解为什么发送普通字节而不使用 chr() 会失败吗?


你可以在问题中编辑一下,在Python中byte_arr的值是什么,JS中response.text的值是什么吗? - mostsquares
response 是如何接收的?你是否确保设置了适当的响应类型 - Martijn Pieters
@CharlieWindolf 当然可以。但是JS脚本中的值全部都是问号。 - Suba Selvandran
1个回答

11
如果您没有显式设置MIME类型,我认为Flask将把它视为文本数据。您的浏览器似乎使用ASCII解码了二进制数据,这可以解释为什么只有大于127的值受到影响。
因此,请尝试在Flask中设置响应的Content-Type
@app.route('/your/url/to/numpy/data')
def get_nparray():
    your_np_array = np.array([5.6], dtype=np.float32)
    response = flask.make_response(your_np_array.tobytes())
    response.headers.set('Content-Type', 'application/octet-stream')
    # response.headers.set('Content-Disposition', 'attachment', filename='np-array.bin')
    return response

另外,还有一个辅助函数flask.send_file可以在一行中构造响应。请在此处查找示例here

除了这个错误之外,还要注意您的二进制数据的endianness,这是硬件特定的。我建议您参考这个answerJavascript Typed Arrays and Endianness)。


谢谢你的回答。它按照我想要的方式工作。此外,我了解了send_file的用法,但是如果数据以图像形式接收,那么我不确定如何将图像作为数组/文本接收。 - Suba Selvandran
我在这里遇到了另一个问题。我能够在Python中获得正确的响应,但是在JS中,我使用angular的$http来获取响应,仍然卡在同样的问题上。我得到的响应不是“application/octet-stream”响应。这概括了问题 https://github.com/angular/angular.js/issues/10349。有任何解决方案吗? - Suba Selvandran

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