I want to send an image from one server to another. I don't want to save the file on disk. I directly want to read the send data. I've written a script for this.
server.py
import socket
import cv2
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("", 6002))
s.listen(10)
c, addr = s.accept()
print('{} connected.'.format(addr))
img = cv2.imread("test.jpg")
img = cv2.imencode('.jpg', img)[1].tostring()
c.send( str(len(img)).ljust(16));
c.send(img)
i = 0
datas = img[i:i+1024]
i = i + 1024
while datas:
datas = img[i:i+1024]
c.send(datas)
i = i + 1024
print("Done sending...")
client.py
import socket
import numpy as np
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("", 6002))
img = ""
while True:
datas = s.recv(1024)
while datas:
img = img + str(datas)[2:-1]
datas = s.recv(1024)
break
print("Done receiving")
img_np = np.fromstring(img, np.uint8)
img_np = cv2.imdecode(img_np, cv2.IMREAD_COLOR)
I'm receiving image in img but when decoding it using opencv, I'm getting empty matrix img_np.
I suggest you to use Memory-Mapped File instead of ZeroMQ as it yields less latency.
Here is an example I wrote that you can use: https://github.com/off99555/python-mmap-ipc
Related
I'm trying to send images from my pi to windows so I can use yolo on windows then send code back to my pi to control my robot.
I can't display the pictures sent by the pi on my pc in real time because the bytes are different every time and it messes up opencv. (opens half photo)
How would my code on windows know how many bytes are going to be in the photo being sent from the pi? Or is there another way to go about this?
Pi code:
from picamera.array import PiRGBArray
from picamera import PiCamera
import socket
import time
import cv2
listensocket = socket.socket() #Creates an instance of socket
Port = 8000 #Port to host server on
maxConnections = 999
IP = socket.gethostname() #IP address of local machine
listensocket.bind(('',Port))
# Starts server
listensocket.listen(maxConnections)
print("Server started at " + IP + " on port " + str(Port))
# Accepts the incoming connection
(clientsocket, address) = listensocket.accept()
print("New connection made!")
# Initialize the camera
camera = PiCamera()
camera.resolution = (640, 480)
camera.framerate = 20
raw_capture = PiRGBArray(camera, size=(640, 480))
time.sleep(0.1)
# Capture frames continuously from the camera
for frame in camera.capture_continuous(raw_capture, format="bgr", use_video_port=True):
image = frame.array
#cv2.imshow("Frame", image)
# Wait for keyPress for 1 millisecond
key = cv2.waitKey(1) & 0xFF
cv2.imwrite("image.jpg", image)
file = open('image.jpg', 'rb')
file_data = file.read(56000)
clientsocket.send(file_data)
print("Data has been transmitted successfully")
raw_capture.truncate(0)
time.sleep(0.050)
if key == ord("q"):
camera.close()
cv2.destroyAllWindows()
break
camera.close()
cv2.destroyAllWindows()
Windows code:
import socket
#import time
import cv2
#import sys
s = socket.socket()
hostname = 'raspi' #Server IP/Hostname
port = 8000 #Server Port
s.connect((hostname, port)) #Connects to server
file = open('image.jpg', 'wb')
file_data = s.recv(2048)
cap = cv2.VideoCapture('image.jpg')
while file_data:
# Save recent image from server
file.write(file_data)
file_data = s.recv(56000)
print("File has been received successfully.")
# Display image as video
ret, img = cap.read()
# Show image
cv2.imshow("Image", img)
key = cv2.waitKey(50)
if key == 27:
break
file.close()
cv2.destroyAllWindows()
I don't have pi to test it with the exact setup but I did a similar project a while ago. My approach to this problem is either using a null-terminated header that will tell the client how many bytes the image will be. Alternatively, you can use a constant size header you decide before hands. For example first 4 bytes will tell the client how many bytes to be received. Here is a sample code snippet for the first solution I described:
sender:
import socket
import cv2 as cv
# read a test image
img = cv.imread('panda.jpg')
# encode it to jpg format, you can do this without redundant file openings
retval, buf = cv.imencode(".JPEG", img)
# get number of bytes
number_of_bytes = len(buf)
# create a null terminated string
header = "" + str(number_of_bytes) + "\0"
# encode it to utf-8 byte format
raw_header = bytes(header, "utf-8")
# create server socket
sock = socket.socket()
sock.bind(('localhost', 8000))
sock.listen()
conn, addr = sock.accept()
# send header first, reciever will use it to recieve image
conn.send(raw_header)
# send the rest of image
conn.send(buf)
reciever:
import socket
# create client socket
sock = socket.socket()
sock.connect(('localhost', 8000))
# recieve bytes until null termination
raw_header = []
recv_byte = sock.recv(1)
while recv_byte != b"\0":
raw_header.append(recv_byte)
recv_byte = sock.recv(1)
# decode header
header = str(b''.join(raw_header), "utf-8")
# recieve the amount of bytes foretold by header
recv_img = sock.recv(int(header))
# save image to file or you can use cv2.imendecode to turn it back to numpy.ndarray (cv2 image format)
with open("traveller_panda.jpg", 'wb+') as im_file:
im_file.write(recv_img)
# transform back from jpg to numpy array
image_decoded = np.frombuffer(recv_img, dtype=np.uint8)
image_decoded = cv.imdecode(image_decoded, cv.IMREAD_COLOR)
# display image
cv.imshow("recieved", image_decoded)
cv.waitKey()
I have a problem with my program I am trying to send the images I collect from the MLX90640 thanks to the Raspberry to process them in a remote PC.
I am using a Raspberry 4 as a client and the data is routed to a PC. I am using the socket to start the server which is to receive and the images and thermal images. For the images connected to the camera, I took care of it my problem is to transfer the thermal images. I am currently using a wifi connection that I share with my cellphone for the tests.If necessary I will post the server code. But I have this error message I have tried many solutions and I have not found it. In fact, the Raspberry is the client and the PC is the server. So I collect data from the raspberry to transmit it to the PC for processing. I want to detect the temperature of the face and for that the MLX90640 which is connected to the Raspberry must send the thermal data. Knowing that it collects 768 values, so I want these values to be transmitted or the maximum value to be returned to the PC. Can someone help me
import cv2
import io
import socket
import struct
import time
import pickle
import zlib
import adafruit_mlx90640
import board
import busio
import numpy as np
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('192.168.43.134', 8485))
connection = client_socket.makefile('wb')
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000)
mlx = adafruit_mlx90640.MLX90640(i2c)
print("MLX addr detected on I2C")
print([hex(i) for i in mlx.serial_number])
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_4_HZ
frame1 = np.zeros((24*32,))
#max_t=0
#moy = 0
#cam = cv2.VideoCapture(0)
#mlx.set(3, 32);
#mlx.set(4, 24);
img_counter = 0
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
while True:
frame = mlx.getFrame(frame1)
result, frame = cv2.imencode('.jpg', frame, encode_param)
# data = zlib.compress(pickle.dumps(frame, 0))
data = pickle.dumps(frame, 0)
size = len(data)
print("{}: {}".format(img_counter, size))
client_socket.sendall(struct.pack(">L", size) + data)
img_counter += 1
```Traceback (most recent call last): File "client1.py", line 37, in <module> result, frame = cv2.imencode('.jpg', frame, encode_param) cv2.error: OpenCV(4.1.1) /home/pi/opencv/modules/imgcodecs/src/grfmt_base.cpp:145: error: (-10:Unknown error code -10) Raw image encoder error: Empty JPEG image (DNL not supported) in function 'throwOnEror'
Do you manage to get thermal at Raspberry pi? I did a similar approach but i am not using thermal camera. If your problem is not able to transfer image from raspberry pi to your computer
Server code at Raspberry pi
#!/usr/bin/env python3
import os
import datetime
import numpy as np
import cv2
import sys
import socket
import select
import queue
import pickle
import struct
import time
from threading import Thread
class WebcamVideoStream:
def __init__(self, src=0):
self.stream = cv2.VideoCapture(src)
cv2.VideoWriter_fourcc('M','J','P','G')
self.stream .set(cv2.CAP_PROP_BUFFERSIZE,1)
self.stream .set(5, 60)
self.stream .set(3,640)
self.stream .set(4,480)
(self.grabbed, self.frame) = self.stream.read()
self.stopped = False
def start(self):
Thread(target=self.update, args=()).start()
return self
def update(self):
while True:
if self.stopped:
return
(self.grabbed, self.frame) = self.stream.read()
time.sleep(0.1)
def read(self):
img= cv2.cvtColor(self.frame , cv2.COLOR_BGR2GRAY)
data = pickle.dumps(img)
return data
def stop(self):
self.stopped = True
def commandParser(cmd, stream):
reply = ""
if(cmd == "getimage"):
reply = stream.read()
time.sleep(0.1)
else:
reply = '/n'.encode()
return(reply)
if __name__ == '__main__':
camera_idx = 0
for i in range(3):
stream = cv2.VideoCapture(i)
test,frame = stream.read()
stream.release()
if test == True:
camera_idx = i
break
#stream = cv2.VideoCapture(camera_idx)
vs = WebcamVideoStream(src=camera_idx).start()
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
port = 8080
server.bind(('192.168.128.14', port))
server.listen(5)
inputs = [server]
outputs = []
message_queues = {}
cmd =""
while inputs:
readable, writable, exceptional = select.select(inputs, outputs, inputs, 1)
for s in readable:
if s is server:
connection, client_address = s.accept()
inputs.append(connection)
message_queues[connection] = queue.Queue(1024)
else:
data = s.recv(4096)
if data:
cmd = data.decode()
message_queues[s].put(commandParser(data.decode(), vs))
if s not in outputs:
outputs.append(s)
else:
if s in outputs:
outputs.remove(s)
inputs.remove(s)
s.close()
del message_queues[s]
for s in writable:
try:
next_msg = message_queues[s].get_nowait()
except queue.Empty:
outputs.remove(s)
else:
if(cmd == "getimage"):
size = len(next_msg)
s.sendall(struct.pack(">L", size) + next_msg)
else:
s.send("ABCDEFGHIJKLMNONOOO".encode())
for s in exceptional:
print ('handling exceptional condition for', s.getpeername())
inputs.remove(s)
if s in outputs:
outputs.remove(s)
s.close()
del message_queues[s]
vs.stop()
Client Code at PC
#!/usr/bin/env python3
import os
import datetime
import numpy as np
import cv2
import socket
import socket
import sys
import pickle
import struct ## new
import zlib
import time
server_address = ('192.168.128.14', 8080)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#print ('connecting to %s port %s' % server_address)
s.connect(server_address)
cv2.namedWindow('Streaming')
payload_size = struct.calcsize(">L")
while True:
s.send("getimage".encode())
data = b""
while len(data) < payload_size:
data += s.recv(4096)
packed_msg_size = data[:payload_size]
data = data[payload_size:]
msg_size = struct.unpack(">L", packed_msg_size)[0]
while len(data) < msg_size:
data += s.recv(4096)
frame_data = data[:msg_size]
data = data[msg_size:]
frame=pickle.loads(frame_data, fix_imports=True, encoding="bytes")
cv2.imshow('Streaming',frame)
cv2.waitKey(1)
#cv2.imwrite("test.tiff", frame)
s.close()
I'm an intermediate in python and new to libraries like numpy and opencv. I'm trying to make a video calling app using sockets.This code is just a try. I've tried in the following way but as it receives the array it's size becomes 0 and shape becomes null. Please help me do this. I'm sorry for anymistakes I've done
any help will be appreciated
Thank you. Have a nice day enter
Server:-
import socket
import threading
from _thread import *
import cv2
import numpy as np
srvr = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_ip = socket.gethostbyname(socket.gethostname())
port = 9999
client = []
try:
srvr.bind((server_ip, port))
except socket.error as e:
print(e)
def connected_client(conn, addr):
global client
print("[SERVER]: CONNECTED WITH ", addr)
check_msg = "Welcome Client"
conn.send(str.encode(check_msg))
while True:
try:
data = conn.recv(5000)
if not data:
print("[SERVER]: DISCONNECTED..")
break
for i in client:
i.sendall(data)
except:
break
conn.close()
srvr.listen(5)
while True:
print("[SERVER]: STARTED...\n [SERVER]: ACCEPTING CONNECTIONS....")
conn, addr = srvr.accept()
start_new_thread(connected_client, (conn, addr))
client.append(conn)
Client:-
import socket, cv2
import threading
from _thread import *
import numpy as np
import time
import base64
video = cv2.VideoCapture(0)
clt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
SERVER = socket.gethostbyname(socket.gethostname())
PORT = 9999
ADDR = (SERVER, PORT)
clt.connect(ADDR)
print(clt.recv(2048).decode())
#recieving data from server
def recieve():
global clt
while True:
recv_frame = clt.recv(5000)
nparr = np.frombuffer(recv_frame, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
key = cv2.waitKey(1)
if key == ord('a'):
break
print(img)
# cv2.imshow("aman", recv_frame)
# break
# https://stackoverflow.com/questions/17967320/python-opencv-convert-image-to-byte-string
# new thread while to continuously recieve data
start_new_thread(recieve, ())
# loop for continuously sending data
while True:
check, frame = video.read()
str_frame = cv2.imencode('.jpg', frame)[1].tobytes()
clt.sendall(str_frame)
video.release()
cv2.destroyAllWindows()
I'm trying to take a screenshot and send it to another computer using python.
I've tried to do it in many different ways. Unfortunately, I didn't find a way to do it.
I would appreciate your help!
server:
from PIL import Image
from PIL import ImageGrab
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 1111))
server_socket.listen(1)
print('Waiting For Connection...')
(client_socket, client_address) = server_socket.accept()
print('Connected to: ', client_address[0])
img = ImageGrab.grab(bbox=(10, 10, 500, 500))
photo_to_send= img.tobytes()
size = len(photo_to_send)
client_socket.send(bytes(str(size), 'utf-8'))
while size >= 0:
msg = photo_to_send[:4096]
client_socket.send(bytes(str(msg), 'utf-8'))
photo_to_send= photo_to_send[4096:]
client:
import socket
from PIL import Image
my_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_socket.connect(('127.0.0.1', 1111))
print("Connected to the server")
size = int(my_socket.recv(1024).decode('utf-8'))
the_photo = ""
the_photo = the_photo.encode('utf-8')
while size > 0:
data = my_socket.recv(4096)
size -= len(data)
the_photo += data
img_to_save = Image.frombytes("RGB", (490,490), the_photo)
img_to_save .save("screenshot.png")
You can use pickle to serialize your Image objects. Pickle just converts an python object into bytes. pickle.dumps just encodes it to bytes and pickle.loads decodes it back.
Hope this helps!
The problem is that you are sending the textual value of the length immediately before the data itself. For example, if the image data started with AAABBB, you would be sending
1234AAABBB...
But if the image was bigger, you might send something like
56789AAABBB...
The client has no way of telling where the length ends and the data starts! To fix this, you need to send a fixed size length parameter. If you still want to a textual length, you could use zfill:
client_socket.send(str(size).zfill(16).encode())
...
size = int(my_socket.recv(16).decode())
(where 16 is chosen to be long enough to fit any possible image size)
This is not terribly efficient; real protocols usually use binary encoding:
client_socket.send(struct.pack('>I', size))
...
size, = struct.unpack('>I', my_socket.recv(4))
But this may be more complex than you need for your application.
The problem was that I encoded the photo twice.
Thanks for your help!
I really appreciate it!
Here is the solution:
server:
from PIL import ImageGrab
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 1112))
server_socket.listen(1)
print('Waiting For Connection...')
(client_socket, client_address) = server_socket.accept()
print('Connected to: ', client_address[0])
img = ImageGrab.grab(bbox=(10, 10, 500, 500))
photo_to_send = img.tobytes()
size = len(photo_to_send)
print(size)
print(photo_to_send)
client_socket.send(bytes(str(size), 'utf-8'))
client_socket.send(photo_to_send)
client:
import socket
from PIL import Image
my_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_socket.connect(('127.0.0.1', 1112))
print("Connected to the server")
size = int(my_socket.recv(10).decode('utf-8'))
print(size)
the_photo = my_socket.recv(size)
print(the_photo)
img_to_save = Image.frombytes("RGB", (490, 490), the_photo)
img_to_save.save("screenshot.png")
struct and pickle makes everything easy for you.
server.py
imageBytes = pickle.dumps(image)
sock.sendall(struct.pack("L", len(imageBytes)) + imageBytes)
client.py
data = b""
payload_size = struct.calcsize("L")
while True:
data += sock.recv(payload_size)
packedImageSize = data[:payload_size]
imageSize = struct.unpack("L", packedImageSize)[0]
data = data[payload_size:]
while len(data) < imageSize:
data += sock.recv(65000)
frameData = data[:imageSize]
data = data[imageSize:]
frame = pickle.loads(frameData)
I wanted to make a client, that sends images and a list of strings to an server.
First I wanted to put eerything in one List, and make it one string with pickle, so I can send it.
But unfortunatley, the string became to big for pickle to handle, so I just used two sockets, one for the list, and one for the image.
It worked, but the Image I recived is broken.
This is the original image:
And here is the copied image:
As you can see, the bottom part is not there, but the real problem is, that I can't use the image in my kivy app, while the original image work.
How can I solve this problem?
Here is the server:
import socket
import errno
import base64
import pickle
from PIL import Image
import StringIO
def connect(c):#recursive funktion, that deals with the errorno 11
try:
strings = c.recv(8192)
return strings
except IOError as e:
if e.errno == errno.EWOULDBLOCK:
connect(c)
def Main():
host = IP
port = 12345
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind((host, port))
s.listen(5)
while True:
c, addr = s.accept()
print "Connection from: " + str(addr)
strings = connect(c)
#gets the image
c.send('give image')
#c.flush()
c.close()
c, addr = s.accept()
image = connect(c)
imgname = 'test.png'
if image == 'cusdom_image':
with open('images.png', "rb") as imageFile:
image = ''
image = base64.b64encode(imageFile.read())
print image
fh = open(imgname, "wb")
fh.write(image.decode('base64'))
fh.close()
if __name__ == '__main__':
Main()
And here is the client:
import socket
import base64
import pickle
from PIL import Image
import StringIO
import os, sys
ip = '138.106.181.133'
port = 12345
print 'Add event executed'
s = socket.socket()#makes socket for the first time
s.connect((ip, port))
image_path = '/home/gilgamesch/PTTT/icon.png'
print os.getcwd()
olddir = os.getcwd()
os.chdir('/')
print os.getcwd()
new_list = ['Some', 'random', 'string', 'list', ]
new_compact_list = pickle.dumps(new_list)
s.send(new_compact_list)
recived = s.recv(1023)
if image_path != '':
with open(image_path, "rb") as imageFile:
image_data = base64.b64encode(imageFile.read())
print 'open worked'
else:
image_data = 'cusdom_image'
os.chdir(olddir)
if recived == 'give image':
s.close()
s = socket.socket()#remakes socket to send image
s.connect((ip, port))
s.sendall(image_data)
s.close()
And By the way, the bitcode is fine, when the client reads it, I tested it, it gets broken, when it is send to the server.