I created one program with pygame, imageGrab and sockets but it doesn't work. It should take a printscreen of the server with ImageGrab, convert it to a string, and send it to the client. However, the client upon receiving the information and converting it to an image raises an error:
image = pygame.image.frombuffer(img, (800,600), "RGB")
ValueError: Buffer length does not equal format and resolution size
code Server
import sys, os, socket, pygame
from PIL import ImageGrab
from pygame.locals import *
print "streaming sever 0.1"
try:
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print "Error creating socket"
sys.exit(1)
host = "127.0.0.1"
port = raw_input("Port:")
socket.bind((host, int(port)))
socket.listen(2)
socket2,client = socket.accept()
print "Client conectado: " + str(client[0]) + "\nPorta usada: " + str(client[1])
#Capture and send
while True:
img=ImageGrab.grab().resize((800,600))
img.tostring()
socket2.sendall(img)
socket2.close()
code Client
import sys, os, socket, pygame
from PIL import ImageGrab
from pygame.locals import *
print "streaming client 0.1"
pygame.init()
try:
s_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print "streaming protocol started"
except socket.error:
print "Error creating socket"
sys.exit(1)
host = "127.0.0.1"
porta = raw_input("Port:")
q_bytes = raw_input("Enter the number of MBs to transfer: ")
t_bytes = 1024*1024*int(q_bytes)
try:
s_client.connect((host,int(porta)))
except socket.error:
print "Error connecting to: " + host
sys.exit(1)
print "Conectado!"
size = width, height = 800, 600
screen = pygame.display.set_mode(size)
num = 0
while True:
img = s_client.recv(t_bytes)
image = pygame.image.frombuffer(img, (800,600), "RGB")
screen.blit(image,(0,0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
os._exit(1)
#recebimento
s_client.close()
The deal with sockets is you have to know exactly how long the message you're receiving is if you plan keep using the same socket connection. You seem to have some idea of this with your q_bytes = raw_input("Enter the number of MBs to transfer: "), but we need to know exactly, not to the nearest MB. Sometimes this information is sent at the front part of the data, so we can read it first and then know when to stop reading.
The exception to this is if we don't need the connection anymore; we just want this one picture. In that case, it's fine to ask for as much data as we want, we'll get an empty string back at the end.
As for the max_bytes argument to recv, that's just one maximum - there's another hardware-dependent maximum imposed on us, for my tests it was 1MB.
The code below just keeps asking for data, stops when it receives an empty string because there is no more data, then combines all this gathered data into the full string.
There are many levels of abstraction that could (and should) be built up to distance us from these complications, but the code below is just yours, working, with some irrelevant bits taken out.
Client.py
import sys, os, socket, pygame
from pygame.locals import *
pygame.init()
s_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = "127.0.0.1"
porta = 12350
t_bytes = 1024*1024*1
s_client.connect((host,int(porta)))
print "Conectado!"
size = width, height = 300, 500
screen = pygame.display.set_mode(size)
message = []
while True:
s = s_client.recv(t_bytes)
if not s:
break
else:
message.append(s)
full_s = "".join(message)
print 'string received size', len(full_s)
image = pygame.image.frombuffer(full_s, size, "RGB")
#image = pygame.image.fromstring(s, size, "RGB")
screen.blit(image,(0,0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
os._exit(1)
raw_input()
s_client.close()
Server.py
import sys, os, socket, pygame
from pygame.locals import *
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "127.0.0.1"
port = 12350
socket.bind((host, int(port)))
socket.listen(2)
socket2,client = socket.accept()
print "Client conectado: " + str(client[0]) + "\nPorta usada: " + str(client
img = Image.open('tiny.jpg').resize((300, 500))
s = img.tostring()
print 'size of string', len(s)
socket2.sendall(s)
socket2.close()
edit: As per Mark's correction, len() calls were previously __sizeof__() method calls. __sizeof__ returns the size of the python object in bytes, not the number of bytes/characters in the string.
Related
I'm tryin to program dji tello drone for take off. I'm geeting the following error. [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted.
Can some one please help me find a workaround? I have tried
from djitellopy import Tello
import cv2
width = 320
height = 240
startCounter =1 #0 for flight
me = Tello()
me.connect()
me.for_back_velocity = 0
me.left_right_velocity = 0
me.up_down_velocity = 0
me.yaw_velocity = 0
me.speed = 0
print(me.get_battery())
me.streamoff()
me.streamon()
while True:
frame_read = me.get_frame_read()
myFrame = frame_read.frame
img = cv2.resize(myFrame(width,height))
if startCounter ==0:
me.takeoff()
me.move_left(20)
me.rotate_clockwise(90)
#time.sleep(3)
#me.move_left(35)
#time.sleep(3)
# me.land()
startCounter = 1
cv2.imshow("MyResult", img)
if cv2.waitKey(1) & 0xFF == ord('q'):
me.land()
break
import socket
import threading
import time
# IP and port of Tello
tello_address = ('192.168.10.1', 8889)
# IP and port of local computer
local_address = ('', 9000)
# Create a UDP connection that we'll send the command to
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Bind to the local address and port
sock.bind(local_address)
# Send the message to Tello and allow for a delay in seconds
def send(message, delay):
# Try to send the message otherwise print the exception
try:
sock.sendto(message.encode(), tello_address)
print("Sending message: " + message)
except Exception as e:
print("Error sending: " + str(e))
# Delay for a user-defined period of time
time.sleep(delay)
# Receive the message from Tello
def receive():
# Continuously loop and listen for incoming messages
while True:
# Try to receive the message otherwise print the exception
try:
response, ip_address = sock.recvfrom(128)
print("Received message: " + response.decode(encoding='utf-8'))
except Exception as e:
# If there's an error close the socket and break out of the loop
sock.close()
print("Error receiving: " + str(e))
break
# Create and start a listening thread that runs in the background
# This utilizes our receive functions and will continuously monitor for incoming messages
receiveThread = threading.Thread(target=receive)
receiveThread.daemon = True
receiveThread.start()
# Initiate command mode and takeoff
def takeoff():
send("command", 3)
send("takeoff", 5)
# Land
def land():
send("land", 5)
# Tello commands respond with an OK when sucessful. This means Tello recognizes
# the command, but the instruction hasn't completed. OK is Tello saying "I got
# the message" but not necessarily saying "I completed the command"
# This means we need to calculate how long the spin will take before we execute the next command.
# Based on our tests a single 360 rotation takes 7 seconds. We'll use this in our spin function to delay
# before the next command. Your rotation time may vary. You can calculate this by
# sending a "cw 360" or "ccw 360" command and measuring the rotation time.
# 7 seconds per rotation
rotationTime = 7
# Spin right or left X number of times
def spin(direction, times):
# One rotation is 360 degrees
oneRotation = 360
# Convert the number of rotations to degrees
rotations = oneRotation * times
# Calculate the delay to let the spin function complete
delay = rotationTime * times
# Spin right (cw) or left (ccw)
if (direction == "right"):
send("cw " + str(rotations), delay)
elif (direction == "left"):
send("ccw " + str(rotations), delay)
# Use 20 cm/sec as vertical speed
verticalSpeed = 20.0
def bounce(distance, times):
bounceDelay = distance/verticalSpeed
for i in range(times):
send("down " + str(distance), bounceDelay)
send("up " + str(distance), bounceDelay)
# Takeoff
takeoff()
# Spin right 2 times
spin("right", 2)
# Bounce up and down 60 cm and repeat 3 times
bounce(60, 3)
# Spin left 3 times
spin("left", 3)
# Land
land()
# Close the socket
sock.close()
I'm trying to send python-opencv frames over sockets. I'm pickling the data and unpickling but for some reason it's blank or nothing is showing up.
This is my terminal when I run client.py
new message length: b'720 '
It should be streaming the webcam from server but nothing is showing up.
Here is my code for the client and server:
client.py
import socket
import numpy as np
import cv2
import pickle
HEADERSIZE = 10
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((socket.gethostname(), 1232))
while True:
full_msg = b''
new_msg = True
while True:
msg = s.recv(16)
if new_msg:
print(f'new message length: {msg[:HEADERSIZE]}')
msglen = int(msg[:HEADERSIZE])
new_msg = False
full_msg += msg
if len(full_msg)-HEADERSIZE == msglen:
print('full msg recvd')
print(full_msg[HEADERSIZE:])
d = pickle.loads(full_msg[HEADERSIZE:])
print(d)
cv2.namedWindow('Webcam', cv2.WINDOW_NORMAL)
cv2.imshow('Webcam', full_msg[HEADERSIZE:])
new_msg = True
full_msg = b''
print(full_msg)
server.py
import socket
import numpy as np
import cv2
import time
import pickle
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE, SIG_DFL)
HEADERSIZE = 10
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((socket.gethostname(), 1232))
s.listen(5)
cap = cv2.VideoCapture(0)
while True:
clientsocket, address = s.accept()
print(f"Connection from {address} has been established!")
while True:
ret, frame = cap.read()
msg = pickle.dumps(frame)
print(frame)
msg = bytes(f'{len(frame):<{HEADERSIZE}}', "utf-8") + msg
clientsocket.send(msg)
I have no idea why nothing is showing up. I don't even know if anything is coming though. Does it have to do with numpy data? I heard that can be tricky.
When you stream frames of 720 bytes from server, you are actually sending 730 bytes (length 10 bytes + data 720 bytes) per frame continuously, one frame after another.
In client you are reading 16 bytes per recv(). Hence your condition if len(full_msg)-HEADERSIZE == msglen: will never be true, with header size 10, as 730 is not divisible by 16.
So your program is looping indefinitely on while True: in client.
Try below program for client. I tested with dummy data.
client.py
import socket
import numpy as np
import cv2
import pickle
HEADERSIZE = 10
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((socket.gethostname(), 1232))
while True:
msg_length=int(s.recv(HEADERSIZE))
full_msg=b''
while len(full_msg)<msg_length:
full_msg+=s.recv(msg_length-len(full_msg))
print(full_msg)
d = pickle.loads(full_msg)
cv2.namedWindow('Webcam', cv2.WINDOW_NORMAL)
cv2.imshow('Webcam', full_msg)
i am trying to stream from webcam to another computer and save the stream in a pickle file in numpy array. i will later process the frames in iskits library. ****i m sending strings from sender and convert it in numpy array and save it to pickle file.****
but when i try to load stream from .pkl file it is showing error.
when i try to print the size of the array it shows 0 or 1 or 2.
with open('/home/siplab/samples.pkl','rb') as f:
data = pickle.load(f)
print shape(data)
the output shows
siplab#siplab-OptiPlex-9020:~$ python gh.py
(2,)
the code for client is
import socket
import pygame
import sys
import numpy as np
import pickle
host = "127.0.1.1"
port=5000
screen = pygame.display.set_mode((640,480),0)
pygame.display.set_caption('Webcam Viewer')
while True:
clientsocket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket.connect((host, port))
received = []
while True:
recvd_data = clientsocket.recv(1024000)
if not recvd_data:
break
else:
received.append(recvd_data)
dataset = ''.join(received)
image = pygame.image.fromstring(dataset,(640,480),"RGB")
screen.blit(image,(0,0))
pygame.display.update()
k = np.asarray('received',dtype=float,sep=', ')
with open('samples.pkl','wb') as f:
pickle.dump(k,f)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
the code for the server is
import socket
import pygame
import pygame.camera
import sys
import time
port = 5000
pygame.init()
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind(("127.0.1.1",port))
serversocket.listen(5)
pygame.camera.init()
screen = pygame.display.set_mode((640,480))
webcam = pygame.camera.Camera("/dev/video0",(640,480))
webcam.start()
while True:
connection, address = serversocket.accept()
image = webcam.get_image()
screen.blit(image,(0,0))
data = pygame.image.tostring(image,"RGB")
connection.sendall(data)
pygame.display.update()
time.sleep(0.1)
connection.close()
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?
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.
This is my code:
server.py:
#The server receives the data
import socket
from PIL import Image
import pygame,sys
import pygame.camera
from pygame.locals import *
import time
host = "localhost"
port = 1890
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,port))
s.listen(1)
conn, addr = s.accept()
print "connected by",addr
screen = pygame.display.set_mode((640,480))
while 1:
data = conn.recv(921637)
image = pygame.image.fromstring(data,(640,480),"RGB")
screen.blit(image,(0,0))
pygame.display.update()
if not image:
break;
conn.send(data)
conn.close()
client.py
#The client sends the data
import socket
from PIL import Image
import pygame,sys
import pygame.camera
from pygame.locals import *
import time
host = "localhost"
port = 1890
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
pygame.init()
pygame.camera.init()
cam = pygame.camera.Camera("/dev/video0",(640,480))
cam.start()
while 1:
image = cam.get_image()
data = pygame.image.tostring(image,"RGB")
s.sendall(data)
s.close()
print "recieved", repr(data)
Just to test, I tried the following code and it's working fine, but the above does not...
Working code when implemeted without sockets: camcapture.py
import sys
import time
import pygame
import pygame.camera
from pygame.locals import *
pygame.init()
pygame.camera.init()
cam = pygame.camera.Camera("/dev/video0",(640,480))
cam.start()
screen = pygame.display.set_mode((640,480))
while 1:
image = cam.get_image()
data = pygame.image.tostring(image,"RGB")
img = pygame.image.fromstring(data,(640,480),"RGB")
screen.blit(img,(0,0))
pygame.display.update()
The error is:
image = pygame.image.fromstring(data,(640,480),"RGB")
ValueError: String length does not equal format and resolution size
Where did I go wrong?
The problem is not the camera.
The problem is that you send a very large string over the socket and you incorrectly assume that you can read the entire string at once with conn.recv(921637).
You'll have to call recv multiple times to receive all over your data. Try printing the length of data you send in client.py and print the length of data in server.py before calling pygame.image.fromstring and you'll see.
There are several ways to solve this:
make a new connection for each image you send
send the size of your data so the server knows how much data to read
use some kind of end marker
Here's a simple example:
sender:
import socket
import pygame
import time
host = "localhost"
port = 1890
pygame.init()
image = pygame.surface.Surface((640, 480))
i=0
j=0
while 1:
image.fill((i,j,0))
i+=10
j+=5
if i >= 255: i = 0
if j >= 255: j = 0
data = pygame.image.tostring(image,"RGB")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.sendall(data)
s.close()
time.sleep(0.5)
receiver:
import socket
import pygame
host="localhost"
port=1890
screen = pygame.display.set_mode((640,480))
while 1:
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,port))
s.listen(1)
conn, addr = s.accept()
message = []
while True:
d = conn.recv(1024*1024)
if not d: break
else: message.append(d)
data = ''.join(message)
image = pygame.image.fromstring(data,(640,480),"RGB")
screen.blit(image,(0,0))
pygame.display.update()