python receive image over socket
Question: I'm trying to send an image over a socket - I'm capturing an image on my
raspberry pi using pycam, sending to a remote machine for processing, and
sending a response back.

On the server (the pi), I'm capturing the image, transforming to an array,
rearranging to a 1D array and using the tostring() method.

On the server, the string received is not the same length. Any thoughts on
what is going wrong here? Attached is the code I'm running, as well as the
output on both the server and the client

SERVER CODE:

    
    
    from picamera.array import PiRGBArray
    from picamera import PiCamera
    import socket
    import numpy as np
    from time import sleep
    import sys
    
    camera = PiCamera()
    camera.resolution = (640,480)
    
    rawCapture = PiRGBArray(camera)
    
    s = socket.socket()
    
    host = 'myHost'
    port = 12345
    s.bind((host,port))
    s.listen(1)
    while True:
        c,addr = s.accept()
    
        signal = c.recv(1024)
        print 'received signal: ' + signal
    
        if signal == '1':
            camera.start_preview()
            sleep(2)
    
            camera.capture(rawCapture, format = 'bgr')
            image = rawCapture.array
            print np.shape(image)
            out = np.reshape(image,640*480*3)
    
            print out.dtype
            print 'sending file length: ' + str(len(out))
    
            c.send(str(len(out)))
            print 'sending file'
            c.send(out.tostring())
    
    
            print 'sent'
    
            c.close()
            break
    

CLIENT CODE:

    
    
    import socket, pickle
    import cv2
    import numpy as np
    
    host = '192.168.1.87'
    port = 12345
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((host, port))
    
    s.send('1')
    
    #while true:
    x = long(s.recv(1024))
    rawPic = s.recv(x)
    
    print 'Received'
    print x
    
    print len(rawPic)
    type(rawPic)
    
    #EDITED TO INCLUDE DTYPE
    image = np.fromstring(rawPic,np.uint8)
    s.close()
    

SERVER OUTPUT:

    
    
    received signal: 1
    (480, 640, 3)
    uint8
    sending file length: 921600
    sending file
    

CLIENT OUTPUT:

    
    
    Received
    921600
    27740
    str
    
    ValueError                                Traceback (most recent call last)
    <ipython-input-15-9c39eaa92454> in <module>()
    ----> 1 image = np.fromstring(rawPic)
    
    ValueError: string size must be a multiple of element size
    

I'm wondering if the issue is i'm calling tostring() on a uint8, and if the
fromstring() is assuming it's a uint32? I can't figure out why the received
string is so much smaller than what is sent.

**EDIT** It seems for some reason the server is not fully sending the file. It
never prints 'sent', which it should do at completion. If I change the send
line to:

    
    
    c.send(str(len(out[0:100])))
    print 'sending file'
    c.send(out[0:100].tostring())
    

Everything works fine. Thoughts on what could be cutting off my sent file
midway through?


Answer: # Decoding to the Proper Type

When you call `tostring()`, datatype (and shape) information is lost. You must
supply numpy with the datatype you expect.

Ex:

    
    
    import numpy as np
    
    image = np.random.random((50, 50)).astype(np.uint8)
    image_str = image.tostring()
    
    # Works
    image_decoded = np.fromstring(image_str, np.uint8)
    
    # Error (dtype defaults to float)
    image_decoded = np.fromstring(image_str)
    

# Recovering Shape

If shape is always fixed, you can do

    
    
    image_with_proper_shape = np.reshape(image_decoded, (480, 640, 3))
    

In the client.

Otherwise, you'll have to include shape information in your message, to be
decoded in the client.

