2

First of all, what I want to do: Sending Photos with Socket from my Raspberry Pi to my laptop.

Client:

#!/usr/bin/python

import socket
import cv2
import numpy as np
import pickle

#Upload image
img = cv2.imread('/path/to/image', 0)

#Turn image into numpy-array
arr = np.asarray(img)

#Receiver ip
ip = "XXX.XXX.X.XXX"

#Set up socket and stuff 
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

#Loop through each array (5 for test)
for each in range(5):

    #Encode each array
    msg = pickle.dumps(arr[each][0])

    #Send msg to ip with port
    s.sendto(msg, (ip, 50000))

s.close()

What happens here: I upload a picture and then turn it into an Numpy array. Then I take each line of the array (each list) and "encode" it with pickle to send it afterwards via Socket. Everything works fine to this point.

Server:

#!/usr/bin/python

import socket
import numpy as np
import cPickle as pickle

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

s.bind(("", 50000)) 

while True:
    data, addr = s.recvfrom(4096)
    conv = pickle.loads(data)
    print conv
    #print np.fromstring(conv,dtype=int)
s.close()

The server receives the encoded data and decodes it back into an Numpy array (that's what I want to achieve).

At the end, it should turn the array back into an image, but I didn't even get to that part, because of the issues I have at this point.

I've also tried to turn the array into a string first, encode it with pickle and then send it so when it gets decoded, it is an numpy array. But that didn't work well.

ValueError: string size must be a multiple of element size

I would appreciate any kind of help, be it a link or pointing out my mistake. Have been working on this for days and haven't found anything that could help me in this matter.

Thanks in advance.

Fur-gan
  • 107
  • 1
  • 3
  • 10
  • 1
    I don't know why you don't send image directly as bytes - `fh = open(... "rb")`, `sendto(fh.read())` – furas Oct 30 '16 at 17:09
  • Could you explain that a bit more? How does the sendto() function work? I'm actually quite new to socket and all that stuff, that's why ^^ – Fur-gan Oct 30 '16 at 17:23
  • Nevermind, I now understand what you mean, but the message gets too long, so it doesn't work. Is there a way to split the data into packages so I send them like that? `socket.error: [Errno 90] Message too long` – Fur-gan Oct 30 '16 at 17:29
  • you don't have to convert bytes from file into string (or any other thing) to send it. `pickle` converts Python object into bytes. `sendto()` always sends bytes. – furas Oct 30 '16 at 17:30
  • btw. if client sends data longer then 4096 then server has to use `recvfrom(4096)` in loop to receive all data. Problem is server doesn't know how many times use `recvfrom(4096)` so first you should send `size` - and this way you create own "protocol" like other protocols ie. HTTP, FTP. So it is easier to use HTTP. – furas Oct 30 '16 at 17:38
  • Thank you very much, that helped a lot! Now I have to find a way to turn the bytes back into a picture. – Fur-gan Oct 30 '16 at 17:52
  • if you write bytes in file then you get image file again. – furas Oct 30 '16 at 17:58

2 Answers2

1

You don't need OpenCV and NumPy for this. Instead, simply send the bytes of the file directly. If you have Python 3.5 you can even use socket.sendfile().

For more detail see: Sending a file over TCP sockets in Python

Community
  • 1
  • 1
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
0

I dont know how many decimal places you need but you could encode your numpy array values in UTF16 BE and then decode after socket send with

def retrieve_and_decode_data():
    try:
        data,addr = s.recvfrom(4096)                                                                                                                                                                                
        list_of_converted_utf16chars = (repr(data.decode('utf-16')).split("\\")[1:])

    except (ValueError, IndexError) as e:
        **perform some conversion-error exception...**

The "repr" function gives you a representation of the utf16 char you can look up in the utf-table

you can then convert this representation into a int or float with

integer_value = int(list_of_converted_utf16chars[index], 16)