Bidirectional Mode enables seamless support for Bidirectional data transmission between Client/Consumer and Sender/Publisher along with video-frames through its synchronous messaging patterns such as zmq.PAIR (ZMQ Pair Pattern) & zmq.REQ/zmq.REP (ZMQ Request/Reply Pattern).
In Bidirectional Mode, we utilizes the NetGear API's message parameter of send() method for sending data from Server-to-Client, and return_data parameter of recv() method to return data back from Client-to-Server all while transferring frames in real-time.
This mode can be easily activated in NetGear through bidirectional_mode attribute of its options dictionary parameter during initialization.
Important Information regarding Bidirectional Mode
In Bidirectional Mode, zmq.PAIR(ZMQ Pair) & zmq.REQ/zmq.REP(ZMQ Request/Reply) are ONLY Supported messaging patterns. Accessing this mode with any other messaging pattern, will result in ValueError.
Bidirectional Mode enables you to send data of ANY1 Data-type along with frame bidirectionally.
Bidirectional Mode may lead to additional LATENCY depending upon the size of data being transfer bidirectionally. User discretion is advised!
Bidirectional Mode is smart enough to sense data (if available or not), and DOES NOT interfere with transferring of video-frames (unless data is huge), as both mechanisms works independently.
# import required librariesfromvidgear.gearsimportVideoGearfromvidgear.gearsimportNetGear# open any valid video stream(for e.g `test.mp4` file)stream=VideoGear(source="test.mp4").start()# activate Bidirectional modeoptions={"bidirectional_mode":True}# Define NetGear Server with defined parametersserver=NetGear(logging=True,**options)# loop over until KeyBoard InterruptedwhileTrue:try:# read frames from streamframe=stream.read()# check for frame if NonetypeifframeisNone:break# {do something with the frame here}# prepare data to be sent(a simple text in our case)target_data="Hello, I am a Server."# send frame & data and also receive data from Clientrecv_data=server.send(frame,message=target_data)# (1)# print data just received from Clientifnot(recv_dataisNone):print(recv_data)exceptKeyboardInterrupt:break# safely close video streamstream.stop()# safely close serverserver.close()
Everything except numpy.ndarray datatype data is accepted as target_data in message parameter.
# import required librariesfromvidgear.gearsimportNetGearimportcv2# activate Bidirectional modeoptions={"bidirectional_mode":True}# define NetGear Client with `receive_mode = True` and defined parameterclient=NetGear(receive_mode=True,logging=True,**options)# loop overwhileTrue:# prepare data to be senttarget_data="Hi, I am a Client here."# receive data from server and also send our datadata=client.recv(return_data=target_data)# check for data if NoneifdataisNone:break# extract server_data & frame from dataserver_data,frame=data# again check for frame if NoneifframeisNone:break# {do something with the extracted frame and data here}# lets print extracted server dataifnot(server_dataisNone):print(server_data)# Show output windowcv2.imshow("Output Frame",frame)# check for 'q' key if pressedkey=cv2.waitKey(1)&0xFFifkey==ord("q"):break# close output windowcv2.destroyAllWindows()# safely close clientclient.close()
Using Bidirectional Mode with Variable Parameters¶
Open a terminal on Client System (where you want to display the input frames received from the Server) and execute the following python code:
Note down the local IP-address of this system(required at Server's end) and also replace it in the following code. You can follow this FAQ for this purpose.
You can terminate client anytime by pressing Ctrl+C on your keyboard!
# import required librariesfromvidgear.gearsimportNetGearimportcv2# activate Bidirectional modeoptions={"bidirectional_mode":True}# Define NetGear Client at given IP address and define parameters # !!! change following IP address '192.168.x.xxx' with yours !!!client=NetGear(address="192.168.x.xxx",port="5454",protocol="tcp",pattern=1,receive_mode=True,logging=True,**options)# loop overwhileTrue:# prepare data to be senttarget_data="Hi, I am a Client here."# receive data from server and also send our datadata=client.recv(return_data=target_data)# check for data if NoneifdataisNone:break# extract server_data & frame from dataserver_data,frame=data# again check for frame if NoneifframeisNone:break# {do something with the extracted frame and data here}# lets print received server dataifnot(server_dataisNone):print(server_data)# Show output windowcv2.imshow("Output Frame",frame)# check for 'q' key if pressedkey=cv2.waitKey(1)&0xFFifkey==ord("q"):break# close output windowcv2.destroyAllWindows()# safely close clientclient.close()
Now, Open the terminal on another Server System (a Raspberry Pi with Camera Module), and execute the following python code:
Replace the IP address in the following code with Client's IP address you noted earlier.
You can terminate stream on both side anytime by pressing Ctrl+C on your keyboard!
Backend PiGear API now fully supports the newer picamera2 python library under the hood for Raspberry Pi camera modules. Follow this guide ➶ for its installation.
# import required librariesfromvidgear.gearsimportVideoGearfromvidgear.gearsimportNetGearfromvidgear.gearsimportPiGearfromlibcameraimportTransform# add various Picamera2 API tweaksoptions={"queue":True,"buffer_count":4,"controls":{"Brightness":0.5,"ExposureValue":2.0},"transform":Transform(hflip=1),"auto_align_output_config":True,# auto-align camera configuration}# open pi video stream with defined parametersstream=PiGear(resolution=(640,480),framerate=60,logging=True,**options).start()# activate Bidirectional modeoptions={"bidirectional_mode":True}# Define NetGear server at given IP address and define parameters # !!! change following IP address '192.168.x.xxx' with client's IP address !!!server=NetGear(address="192.168.x.xxx",port="5454",protocol="tcp",pattern=1,logging=True,**options)# loop over until KeyBoard InterruptedwhileTrue:try:# read frames from streamframe=stream.read()# check for frame if NonetypeifframeisNone:break# {do something with the frame here}# prepare data to be sent(a simple text in our case)target_data="Hello, I am a Server."# send frame & data and also receive data from Clientrecv_data=server.send(frame,message=target_data)# (1)# print data just received from Clientifnot(recv_dataisNone):print(recv_data)exceptKeyboardInterrupt:break# safely close video streamstream.stop()# safely close serverserver.close()
Everything except numpy.ndarray datatype data is accepted as target_data in message parameter.
Under the hood, Backend PiGear API (version 0.3.3 onwards) prioritizes the new picamera2 API backend.
However, the API seamlessly switches to the legacy picamera backend, if the picamera2 library is unavailable or not installed.
It is advised to enable logging(logging=True) to see which backend is being used.
The picamera library is built on the legacy camera stack that is NOT (and never has been) supported on 64-bit OS builds.
You could also enforce the legacy picamera API backend in PiGear by using the enforce_legacy_picamera user-defined optional parameter boolean attribute.
# import required librariesfromvidgear.gearsimportVideoGearfromvidgear.gearsimportNetGearfromvidgear.gearsimportPiGear# add various Picamera tweak parameters to dictionaryoptions={"hflip":True,"exposure_mode":"auto","iso":800,"exposure_compensation":15,"awb_mode":"horizon","sensor_mode":0,}# open pi video stream with defined parametersstream=PiGear(resolution=(640,480),framerate=60,logging=True,**options).start()# activate Bidirectional modeoptions={"bidirectional_mode":True}# Define NetGear server at given IP address and define parameters # !!! change following IP address '192.168.x.xxx' with client's IP address !!!server=NetGear(address="192.168.x.xxx",port="5454",protocol="tcp",pattern=1,logging=True,**options)# loop over until KeyBoard InterruptedwhileTrue:try:# read frames from streamframe=stream.read()# check for frame if NonetypeifframeisNone:break# {do something with the frame here}# prepare data to be sent(a simple text in our case)target_data="Hello, I am a Server."# send frame & data and also receive data from Clientrecv_data=server.send(frame,message=target_data)# (1)# print data just received from Clientifnot(recv_dataisNone):print(recv_data)exceptKeyboardInterrupt:break# safely close video streamstream.stop()# safely close serverserver.close()
Everything except numpy.ndarray datatype data is accepted as target_data in message parameter.
Using Bidirectional Mode for Video-Frames Transfer¶
In this example we are going to implement a bare-minimum example, where we will be sending video-frames (3-Dimensional numpy arrays) of the same Video bidirectionally at the same time, for testing the real-time performance and synchronization between the Server and the Client using this(Bidirectional) Mode.
This example is useful for building applications like Real-Time Video Chat.
We're also using reducer() method for reducing frame-size on-the-go for additional performance.
Remember, Sending large HQ video-frames may required more network bandwidth and packet size which may lead to video latency!
# import required librariesfromvidgear.gearsimportNetGearfromvidgear.gears.helperimportreducerimportnumpyasnpimportcv2# open any valid video stream(for e.g `test.mp4` file)stream=cv2.VideoCapture("test.mp4")# activate Bidirectional modeoptions={"bidirectional_mode":True}# Define NetGear Server with defined parametersserver=NetGear(pattern=1,logging=True,**options)# loop over until KeyBoard InterruptedwhileTrue:try:# read frames from stream(grabbed,frame)=stream.read()# check for frame if not grabbedifnotgrabbed:break# reducer frames size if you want more performance, otherwise comment this lineframe=reducer(frame,percentage=30)# reduce frame by 30%# {do something with the frame here}# prepare data to be sent(a simple text in our case)target_data="Hello, I am a Server."# send frame & data and also receive data from Clientrecv_data=server.send(frame,message=target_data)# (1)# check data just received from Client is of numpy datatypeifnot(recv_dataisNone)andisinstance(recv_data,np.ndarray):# {do something with received numpy array here}# Let's show it on output windowcv2.imshow("Received Frame",recv_data)key=cv2.waitKey(1)&0xFFexceptKeyboardInterrupt:break# safely close video streamstream.release()# safely close serverserver.close()
Everything except numpy.ndarray datatype data is accepted as target_data in message parameter.
# import required librariesfromvidgear.gearsimportNetGearfromvidgear.gears.helperimportreducerimportcv2# activate Bidirectional modeoptions={"bidirectional_mode":True}# again open the same video streamstream=cv2.VideoCapture("test.mp4")# define NetGear Client with `receive_mode = True` and defined parameterclient=NetGear(receive_mode=True,pattern=1,logging=True,**options)# loop overwhileTrue:# read frames from stream(grabbed,frame)=stream.read()# check for frame if not grabbedifnotgrabbed:break# reducer frames size if you want more performance, otherwise comment this lineframe=reducer(frame,percentage=30)# reduce frame by 30%# receive data from server and also send our datadata=client.recv(return_data=frame)# check for data if NoneifdataisNone:break# extract server_data & frame from dataserver_data,frame=data# again check for frame if NoneifframeisNone:break# {do something with the extracted frame and data here}# lets print extracted server dataifnot(server_dataisNone):print(server_data)# Show output windowcv2.imshow("Output Frame",frame)# check for 'q' key if pressedkey=cv2.waitKey(1)&0xFFifkey==ord("q"):break# close output windowcv2.destroyAllWindows()# safely close video streamstream.release()# safely close clientclient.close()
Using Bidirectional Mode for Video-Frames Transfer with Frame Compression ¶