WebSocket传输图像至前端后宽高维度互换问题咨询
问题背景
为自有相机开发图像查看器界面,后端基于Python实现,工作流程如下:
- 获取numpy数组格式的原始图像
- 将numpy数组编码为JPEG格式
- 将JPEG数据转换为base64字符串
- 通过WebSocket发送该字符串到前端
后端核心代码如下:
def image_to_bytes(image): print('into: ', image.shape) buf = cv2.imencode('.jpg', image)[1] dec = cv2.imdecode(buf, cv2.IMREAD_COLOR) print('outa: ', dec.shape) return base64.b64encode(buf).decode('utf-8')
async def send_image(websocket: WebSocket): cam = Camera() for im in cam: w, h = im.shape[:2] resized = cv2.resize(im, (w // 4, h // 4), interpolation=cv2.INTER_LINEAR) await websocket.send_bytes(image_to_bytes(resized))
问题现象
JavaScript前端接收图像后,图像宽高维度互换,显示变形。前端接收渲染代码如下:
socket.onmessage = function(event) { let im = new Image(); const buf = event.data; im.src = 'data:image/jpeg;base64,' + buf; im.onload = function() { context.drawImage(im, 0, 0); console.log('w=' + im.width + ', h=' + im.height); }; };
已完成多环节校验:编码前检查了图像尺寸,编码后在后端重新解码验证,确认编码流程未交换宽高;但JS端图像加载完成后检测尺寸,宽高确实发生反转。
根本原因
核心问题是对OpenCV的数组维度顺序、cv2.resize参数顺序的理解存在错误:
- OpenCV中图像以numpy数组存储时,
shape属性的返回顺序是(高度, 宽度, 通道数),第一个值是图像高度(对应矩阵行数),第二个值才是图像宽度(对应矩阵列数)。代码中写的w, h = im.shape[:2]完全取反了两个值,把高度当成了宽度,宽度当成了高度。 cv2.resize的第二个参数dsize要求传入的目标尺寸元组顺序是(目标宽度, 目标高度),和numpy数组shape的顺序正好相反。把取反的w、h传入后,实际缩放的目标尺寸宽高正好是互换的。
举个实际例子:假设原始图像是1920px宽、1080px高,im.shape[:2]返回值是(1080, 1920),错误取值会得到w=1080, h=1920,传入resize的目标尺寸是(270, 480),最终输出的JPEG实际尺寸是270px宽、480px高,和预期的480px宽、270px高正好互换。
后端校验没发现问题的原因也很简单:用cv2.imdecode做验证时,返回的数组shape顺序还是(高度, 宽度),和编码前的数组顺序一致,就误以为尺寸没变化,实际上从最开始取宽高值的时候就搞反了两个维度的定义。
另外收发逻辑还有一个隐藏问题:image_to_bytes返回的是utf-8编码的base64字符串,调用send_bytes会把字符串按二进制发送,前端拿到的event.data是二进制对象,直接当字符串拼接到data URL上本身不符合逻辑,要么直接发送原始JPEG二进制、前端转Blob URL加载,要么调用send_text发送base64字符串、前端按文本接收拼接。
内容的提问来源于stack exchange,提问作者noel
相关产品推荐
相关产品推荐

