You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Python Sockets传输摄像头帧遇图像截断错误求助

解决Python Socket图像传输的截断错误

你遇到的图像截断错误,本质是TCP流式协议没有消息边界导致的。当前代码里,服务端直接发送JPEG字节流,客户端用recv(8192)只能读取固定长度的字节,但一张640x480的JPEG大小通常远大于8192字节(多为几十KB),所以每次recv只拿到了图像的一部分,PIL自然无法解析完整的图像数据。

核心解决方案

必须在发送图像数据前,先发送图像的字节长度,客户端先接收这个长度值,再根据长度循环接收所有图像字节,直到拿到完整的JPEG数据。


修改后的服务端代码

import socket
import cv2
import io
import numpy as np
from PIL import Image
import struct  # 用于打包长度数据

HOST = "127.0.0.1" 
PORT = 65432

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
print(f"Connected by {addr}")

camera = cv2.VideoCapture(0)

while True:
    ret, frame = camera.read()
    if not ret:
        break  # 处理摄像头读取失败的情况
    frame = cv2.resize(frame, (640, 480))
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    frame = Image.fromarray(frame)
    frame_bytes = io.BytesIO()
    frame.save(frame_bytes, format="JPEG")
    frame_bytes = frame_bytes.getvalue()
    
    # 先发送图像字节长度(打包成4字节二进制数据)
    length = struct.pack('!I', len(frame_bytes))
    conn.sendall(length)
    # 再发送完整图像数据
    conn.sendall(frame_bytes)
    
    data = conn.recv(4096)
    print(data)
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

# 释放资源
camera.release()
cv2.destroyAllWindows()
conn.close()

修改后的客户端代码

import socket
import cv2
import io
import numpy as np
from PIL import Image
import struct  # 用于解包长度数据

HOST = "127.0.0.1" 
PORT = 65432 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

def recv_all(sock, count):
    # 循环接收指定长度的数据,确保拿到完整内容
    buf = b''
    while count:
        new_buf = sock.recv(count)
        if not new_buf:
            return None
        buf += new_buf
        count -= len(new_buf)
    return buf

while True:
    # 第一步:接收4字节的长度数据,解包得到图像字节数
    length_data = recv_all(s, 4)
    if not length_data:
        break
    length = struct.unpack('!I', length_data)[0]
    
    # 第二步:根据长度接收完整的图像数据
    frame_bytes = recv_all(s, length)
    if not frame_bytes:
        break
    
    # 解析并显示图像
    frame = Image.open(io.BytesIO(frame_bytes))
    frame = np.array(frame)
    frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
    cv2.imshow("frame", frame)
    
    # 发送响应
    s.sendall(b"OK")
    
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

# 释放资源
cv2.destroyAllWindows()
s.close()

关键修改说明

  1. 长度标记机制:用struct模块将图像长度打包为固定4字节的二进制数据,确保客户端能准确识别每帧图像的起始和结束。
  2. 完整接收函数:新增recv_all函数,循环接收直到获取指定长度的所有数据,彻底解决TCP流式传输的部分接收问题。
  3. 资源释放:添加了摄像头、窗口、Socket的资源释放代码,避免运行时资源泄漏。

内容的提问来源于stack exchange,提问作者Emir Ünalan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 13:43:12