1

I am doing a project that needs to live stream the video at the client side using USB webcam at the server side.

I am using (Opencv 3.2.0 + python 3.4.3).

The below given code works fine, I want to know how this code actually works and how it is transferring the frames to the client.

There is a delay in this code, and how to overcome that delay. I tried to set resolution but it gives error at the client side like ([Error]: total size of new array must be unchanged).when i set it to default resolution (i.e.,640*480) it works fine.

Help me 
    1. to set the resolution. -answered
    2. why dtype uint8 is used? -answered
    3. what is role fileDescriptor? -answered

updated questions:

  1. In server side - I am getting a problem like ( ctrl+c needs to be pressed two times to stop the server - why is that happening ) - new
  2. server is alternatively running successfully (i.e., for the first time it is not connecting, and second time it is connecting ,third time is getting stopped, fourth time running good -why is it happening ? - new
  3. How to reduce delay ? - new

Lets see who will answer all these questions !!!

server:

import cv2
import time
import json
import socket
import base64
import numpy as np
from threading import Thread

SERVER_IP = "x.x.x.x"
SERVER_PORT = xxxx
MAX_NUM_CONNECTIONS = 20
DEVICE_NUMBER = 0

class ConnectionPool(Thread):

    def __init__(self, ip_, port_, conn_, device_):
        Thread.__init__(self)
        self.ip = ip_
        self.port = port_
        self.conn = conn_
        self.device = device_
        print("[+] New server socket thread started for " + self.ip + ":" +str(self.port))

    def run(self):
        try:
            while True:
                ret, frame = self.device.read()
                a = b'\r\n'
                data = frame.tostring()
                da = base64.b64encode(data)
                self.conn.sendall(da + a)

        except Exception as e:
            print("Connection lost with " + self.ip + ":" + str(self.port) +"\r\n[Error] " + str(e.message))
        self.conn.close()

if __name__ == '__main__':
    cap = cv2.VideoCapture(DEVICE_NUMBER)
    print("Waiting connections...")
    connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connection.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    connection.bind((SERVER_IP, SERVER_PORT))
    connection.listen(MAX_NUM_CONNECTIONS)
    while True:
        (conn, (ip, port)) = connection.accept()
        thread = ConnectionPool(ip, port, conn, cap)
        thread.start()
    connection.close()
    cap.release()

client:

import cv2
import socket
import base64
import numpy as np

IP_SERVER = "x.x.x.x"
PORT_SERVER = xxxx
TIMEOUT_SOCKET = 10
SIZE_PACKAGE = 4096


IMAGE_HEIGHT = 480
IMAGE_WIDTH = 640
COLOR_PIXEL = 3  # RGB


if __name__ == '__main__':
    connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connection.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    connection.settimeout(TIMEOUT_SOCKET)
    connection.connect((IP_SERVER, PORT_SERVER))

    while True:
        try:
            fileDescriptor = connection.makefile(mode='rb')
            result = fileDescriptor.readline()
            fileDescriptor.close()
            result = base64.b64decode(result)
            frame = np.fromstring(result, dtype=np.uint8)
            frame_matrix = np.array(frame)
            frame_matrix = np.reshape(frame_matrix, (IMAGE_HEIGHT, IMAGE_WIDTH,COLOR_PIXEL))
            cv2.imshow('Window title', frame_matrix)

            if cv2.waitKey(1) & 0xFF == ord('q'):
                break

        except Exception as e:
            print("[Error] " + str(e))

    connection.close()
voli
  • 25
  • 1
  • 11
  • Most of the questions can be resolved by using google.... for instance, search RGB and you will understand why is 3, and actually OpenCV uses by default BGR (hint: is a colorspace with 3 channels). I suggest you to look a tutorial in google of how to use opencv in python, and another one of sockets in python and threads in python. Also, take a look into [How to ask](https://stackoverflow.com/help/how-to-ask) page of Stackoverflow. You should ask what you are not understanding of the code. Do not expect for people to translate programming code to human language line by line. – api55 Sep 07 '17 at 10:44
  • Thanks for the advice Bro,i am new to stackoverflow. can u tell me how this code actually works. and why i am not able to set resolutions? – voli Sep 07 '17 at 11:02
  • I can tell you that you probably change it in the client side and not the server side, if you want smaller you have to change it in both, this means not only the image height and width in the client side. In the server side you can use opencv [resize](http://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html#resize) function with the frame variable in the run function. Here is a [tutorial](http://docs.opencv.org/trunk/da/d6e/tutorial_py_geometric_transformations.html) about it :) – api55 Sep 07 '17 at 11:13
  • Nothing worked bro. Changed in both server and client, it is giving error like ([Error]: total size of new array must be unchanged) at the client side. – voli Sep 07 '17 at 11:39
  • Bro, see that in server side the code has sendall for sending frames but in client side there is no recv used instead they used filedescriptor why? – voli Sep 07 '17 at 11:46
  • I found that,In Unix and related computer operating systems, a file descriptor (FD, less frequently fildes) is an abstract indicator (handle) used to access a file or other input/output resource, such as a pipe or network socket. File descriptors form part of the POSIX application programming interface. so, using filedescriptor - directly gets access for webcam from client side is it possible ? Is that the reason for not able to change resolution. – voli Sep 07 '17 at 11:50
  • If you look at my answer, it explains why it is used and how. Basically you get in the server the webcam image, serialize it and send it via socket. The client reads a line as if it was a file from the socket. A line ends with a character \n. This line is deserialized and reshaped as an image – api55 Sep 07 '17 at 11:59

1 Answers1

1
  1. to set the resolution.

You have to change it in both places, server side and client side. Most probably the error you have comes from the reshape function. This function will take the data from the image and reshape it, this means that the data will be untouched and only the size will changed... In this case it is used to change a 1D data array to a 2D matrix 3 channel matrix (however the data order is unchanged). How to change it, you have to change it first in the server part.

Where it says

ret, frame = self.device.read()

After it you can add the resize function of OpenCV:

frame = cv2.resize(frame ,(width/2, height/2), interpolation = cv2.INTER_LINEAR )

This will be half the size. Now in the client side you can reduce to:

IMAGE_HEIGHT = 480 / 2
IMAGE_WIDTH = 640 / 2
  1. why dtype uint8 is used?

This comes from the image representation used by default by OpenCV (BGR), this means that each pixel color it is represented by 3 channels, Blue Green and Red. Each of this channels goes from 0-255 in value, which means that it can be represented with 8 bits, and that is why dtype uint8. Later on the function reshape will create pixels from 3 continuous values (COLOR_PIXEL value).

In this part the code reads a line of text, which is the image data and puts it in an 1D array. This will tell that each 8bit of that line is a value and should be seen as an integer.

  1. what is role fileDescriptor?

This is one way to read data from a socket. See the documentation. This way you can use readline, and get a chunk of data limited by a character of new line. In you case '\r\n'. See the lines:

a = b'\r\n'
data = frame.tostring()
da = base64.b64encode(data)
self.conn.sendall(da + a)

a is the return character, which is sent after the whole image data represented as a string and encoded with base 64.

api55
  • 11,070
  • 4
  • 41
  • 57
  • frame = cv2.resize(frame ,(width/2, height/2), interpolation = cv2.INTER_LINEAR ) IMAGE_HEIGHT = 480 / 2 IMAGE_WIDTH = 640 / 2 TypeError: integer argument expected, got float – voli Sep 07 '17 at 12:04
  • it is weird that you get float out a division of 2 ints... nevertheless you can put the numbers so 240 for the height and 320 for the width. – api55 Sep 07 '17 at 12:16
  • @voli I did type(640/2) and gives me int? are you sure the numbers do not have a '.' like 640/2. ? – api55 Sep 07 '17 at 12:17
  • i have not used (640/2.). I have also changed the numbers and checked it is showing the same error Boss. – voli Sep 08 '17 at 03:45
  • I found the solution for that error : The culprit is the half variable, since it involves a division, in Python 2 it'll give you an int, however in Python 3 a division will give a float unless you use the int division operator // – voli Sep 08 '17 at 03:52
  • Bro it works great yeah!!! . Thanks for the help u r a star - superstar. Bro I am getting a delay in the client side help me to reduce delay. – voli Sep 08 '17 at 04:09
  • Bro i have updated my question - please check it out. – voli Sep 08 '17 at 09:57
  • @voli for more questions do another question, do not update the question. This way more people can answer it and also it makes other people with similar problems easy to find and understand the solution. – api55 Sep 08 '17 at 10:04
  • Bro it is showing that you have reached max limit what to do that's why i updated the questions. – voli Sep 08 '17 at 10:48
  • bro can u answer this (server is alternatively running successfully (i.e., for the first time it is not connecting, and second time it is connecting ,third time is getting stopped, fourth time running good -why is it happening ?) - help me to solve this error boss. (**error**: OpenCV Error: Assertion failed (ssize.width > 0 && ssize.height > 0) in resize, file /home/pi/miniconda3/conda-bld/work/opencv-3.2.0/modules/imgproc/src/imgwarp.cpp, line 3492 ) – voli Sep 12 '17 at 08:31
  • @voli just check if ret is true, if not continue to the next iteration... sometimes it fails to grab an image from the webcam – api55 Sep 12 '17 at 09:43
  • when it is true it will run, if false just stopping and i need to terminate it and rerun it to make it true. – voli Sep 12 '17 at 12:07
  • @voli just extend the server connectionPool, reinitialize webcam and send again data. – api55 Sep 12 '17 at 13:21
  • can u explain me like u did above with codes - thanks in advance bro !!! – voli Sep 13 '17 at 03:55