Search code examples
pythonpython-3.xsocketsraspberry-pi

Python sockets data sent and received are not the same


I have a raspberry pi and usb webcam. I will take an image from the USB webcam I connected to the Raspberry Pi and send this image to my computer. My computer will perform a few operations on this image and send the resulting data back to the Raspberry. The program will repeat these steps as long as it runs (infinite loop). Raspberry pi sends data, but the length of the data the computer receives and the data sent by the raspberry pi are not the same. How can I solve this problem

Server.py :

import socket
import cv2
import io
from PIL import Image
import numpy as np
import struct

def encode_image(frame):
    stream = io.BytesIO()
    frame = cv2.resize(frame, (640, 480))
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    frame = Image.fromarray(frame)
    frame.save(stream, format="JPEG")
    stream.seek(0)
    return stream

def decode_image(image_bytes):
    stream = io.BytesIO(image_bytes)
    return cv2.cvtColor(np.array(Image.open(stream)), cv2.COLOR_RGB2BGR)

server_socket = socket.socket()
server_socket.bind(('0.0.0.0', 8000))
server_socket.listen(0)
c, addr = server_socket.accept()

cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
    x = encode_image(frame).read()
    print(len(x))
    print(x)   
    c.send(struct.pack('<L', len(x)))
    c.send(x)
    data = c.recv(1024)
    if data == "q":
        break
    print(data.decode('utf-8'))

c.close()
server_socket.close()

Client.py :

import socket
import cv2
import io
from PIL import Image
import numpy as np
import struct

cl_socket = socket.socket()
cl_socket.connect(('192.168.1.108', 8000))


def encode_image(frame):
    stream = io.BytesIO()
    frame = cv2.resize(frame, (640, 480))
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    frame = Image.fromarray(frame)
    frame.save(stream, format="JPEG")
    return stream.getvalue()

def decode_image(image_bytes):
    stream = io.BytesIO(image_bytes)
    return cv2.cvtColor(np.array(Image.open(stream)), cv2.COLOR_RGB2BGR)

while True:
    image_len = struct.unpack('<L', cl_socket.recv(struct.calcsize('<L')))[0]
    print(image_len)
    if not image_len:
        break
    image_bytes = io.BytesIO()
    image_bytes.write(cl_socket.recv(image_len))
    image_bytes.seek(0)
    print(image_bytes.getvalue())
    image_bytes.seek(0)
    x = decode_image(image_bytes.read())
    cv2.imshow('frame', x)
    cv2.waitKey(1)
    
cl_socket.close()

Solution

  • You should consider using a loop to receive all the data since it may not be received in a single call to 'recv'.

    Also, when sending data from the client to the server, you need to encode the string before sending and decode it after receiving.

    Server.py:

    import socket
    import cv2
    import io
    from PIL import Image
    import numpy as np
    import struct
    
    def encode_image(frame):
    stream = io.BytesIO()
    frame = cv2.resize(frame, (640, 480))
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    frame = Image.fromarray(frame)
    frame.save(stream, format="JPEG")
    stream.seek(0)
    return stream.read()
    
    def decode_image(image_bytes):
    stream = io.BytesIO(image_bytes)
    return cv2.cvtColor(np.array(Image.open(stream)), cv2.COLOR_RGB2BGR)
    
    server_socket = socket.socket()
    server_socket.bind(('0.0.0.0', 8000))
    server_socket.listen(0)
    c, addr = server_socket.accept()
    
    cap = cv2.VideoCapture(0)
    
    while True:
    ret, frame = cap.read()
    x = encode_image(frame)
    image_len = struct.pack('<L', len(x))
    c.sendall(image_len)
    c.sendall(x)
    
    data = c.recv(1024)
    if data.decode('utf-8') == "q":
        break
    
    c.close()
    server_socket.close()
    

    Client.py:

    import socket
    import cv2
    import io
    from PIL import Image
    import numpy as np
    import struct
    
    cl_socket = socket.socket()
    cl_socket.connect(('192.168.1.108', 8000))
    
    def encode_image(frame):
    stream = io.BytesIO()
    frame = cv2.resize(frame, (640, 480))
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    frame = Image.fromarray(frame)
    frame.save(stream, format="JPEG")
    return stream.getvalue()
    
    def decode_image(image_bytes):
    stream = io.BytesIO(image_bytes)
    return cv2.cvtColor(np.array(Image.open(stream)), cv2.COLOR_RGB2BGR)
    
    while True:
    image_len = struct.unpack('<L', cl_socket.recv(struct.calcsize('<L')))[0]
    if not image_len:
        break
    
    image_data = b''
    while len(image_data) < image_len:
        to_read = min(image_len - len(image_data), 4096)
        image_data += cl_socket.recv(to_read)
    
    x = decode_image(image_data)
    cv2.imshow('frame', x)
    cv2.waitKey(1)
    
    message = input("Enter 'q' to quit: ")
    cl_socket.sendall(message.encode('utf-8'))
    
    cl_socket.close()