如何在HTML中展示通过WebSocket传输的GoCV Mat类型图片
问题原因
- 服务端直接发送的是GoCV Mat类型的原始像素数据,没有编码为浏览器可识别的JPG/PNG等标准图片格式,浏览器无法解析原始像素流为可显示的图片
- 前端代码存在变量引用错误、冗余事件绑定的逻辑问题,即使数据正确也无法正常渲染
- 服务端原有逻辑会先回显收到的文本消息,干扰后续二进制图片消息的处理
修复方案
1. Go服务端修改
- 删掉无用的消息回写逻辑,避免文本消息干扰
- 使用
gocv.IMEncode将Mat编码为JPG格式的字节流再发送 - 及时释放编码产生的缓存
修改后的reader函数核心代码:
func reader(conn *websocket.Conn) { Img := gocv.NewMat() for { // read in a message messageType, p, err := conn.ReadMessage() fmt.Println(string(p)) if err != nil { log.Println(err) return } // 删掉原来的回写消息逻辑 if string(p) == "someone is going to take a selfie" { webcam, err := gocv.OpenVideoCapture(0) if err != nil { fmt.Printf("Error opening video capture device: %v\n", 0) return } img := gocv.NewMat() if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", 0) return } Img = img webcam.Close() conn.SetWriteDeadline(time.Now().Add(10 * time.Second)) w, err := conn.NextWriter(websocket.BinaryMessage) if err != nil { return } // 将Mat编码为JPG格式再发送 buf, err := gocv.IMEncode(".jpg", img) if err != nil { log.Println(err) return } defer buf.Close() w.Write(buf.GetBytes()) if err := w.Close(); err != nil { return } } if string(p) == "someone is going to save the selfie" { fmt.Println("要存照片囉!!") gocv.IMWrite("selfie.jpg", Img) } } }
2. 前端页面修改
- 删除
onmessage回调内冗余的事件绑定逻辑,收到二进制消息直接渲染 - 修复变量名错误,新增消息类型判断,只处理二进制图片消息
- 增加内存释放逻辑,避免Blob URL占用内存
修改后的socket.onmessage代码:
let imgdom = document.getElementById("img"); socket.onmessage = (e) => { // 只处理二进制图片消息,文本消息直接打日志 if (e.data instanceof Blob) { const blobUrl = URL.createObjectURL(e.data) imgdom.src = blobUrl // 图片加载完成后释放内存 imgdom.onload = () => { URL.revokeObjectURL(blobUrl) } imgdom.onerror = () => { console.error("图片加载失败") URL.revokeObjectURL(blobUrl) } } else { console.log("收到文本消息:", e.data) } }; // 删掉onmessage回调内原来的createImageFromBlob、handleBlobs、capture.addEventListener等冗余逻辑
修改完成后重新运行服务端,点击拍照按钮即可正常显示拍摄的图片。
内容的提问来源于stack exchange,提问作者GeNoX88
相关产品推荐
相关产品推荐

