multiprocessing script using Pipes - python

When I try to run the following script, process 1 displays just 1 sec of video and get stuck. is there any problem with the code? My goal is to run two processes, one which display's the frames continuously and other process perform face detection and print the results whenever the process1 sets the event. Process 1 sets the event at regular intervals i.e, after every 20 or 30 frames.
def read(e,parent):
fps,st,frames_to_count,cnt = (0,0,30,0)
vid = cv2.VideoCapture('sample.mp4')
wid = 640
while(vid.isOpened()):
res,frame = vid.read()
if not res:
break
frame = imutils.resize(frame,width = wid)
cv2.imshow('VIDEO',frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
if cnt == frames_to_count:
try:
fps = round(frames_to_count/(time.time()-st))
parent.send(frame)
e.set()
st=time.time()
cnt=0
except:
pass
cnt+=1
cv2.destroyAllWindows()
def fd(e,child):
face_cascade=cv2.CascadeClassifier("path to xml")
while True:
e.wait()
faces=face_cascade.detectMultiScale(child.recv(),1.1,4)
print(faces)
e.clear()
def main():
e = Event()
(child,parent) = Pipe()
p1 = Process(target=read, args=(e,parent))
p2 = Process(target=fd, args=(e,child))
p1.start()
p2.start()
p1.join()
p2.join()
if __name__ == "__main__":
main()

See all my comments to your posted question. In the code below I have retained the Pipe that you are using but have specified duplex=False since you are not using the returned connections for two-way communication and have correspondingly renamed these connections from child and parent to the now more meaningful read_conn and send_conn. I have, of course, removed the Event instance.
Since fd appears to be in a loop that never terminates, main will never be able to join that process. Therefore, p2 should be created as a daemon process that will automatically terminate when all non-daemon processes and threads terminate.
def read(send_conn):
fps,st,frames_to_count,cnt = (0,0,30,0)
vid = cv2.VideoCapture('sample.mp4')
wid = 640
while(vid.isOpened()):
res,frame = vid.read()
if not res:
break
frame = imutils.resize(frame,width = wid)
cv2.imshow('VIDEO',frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
if cnt == frames_to_count:
try:
fps = round(frames_to_count/(time.time()-st))
send_conn.send(frame)
st=time.time()
cnt=0
except:
pass
cnt+=1
cv2.destroyAllWindows()
def fd(recv_conn):
face_cascade=cv2.CascadeClassifier("path to xml")
while True:
faces=face_cascade.detectMultiScale(recv_conn.recv(),1.1,4)
print(faces)
def main():
(recv_conn,send_conn) = Pipe(duplex=False)
p1 = Process(target=read, args=(send_conn,))
p2 = Process(target=fd, args=(recv_conn,), daemon=True)
p1.start()
p2.start()
p1.join()
if __name__ == "__main__":
main()

Related

How to close all the processes one by one in a program that operates with multiprocessing by means of an 'if' validation found in one of them process?

import multiprocessing
from threading import Thread
import speech_recognition as sr
def actions_func(conn1_3,conn2_3):
def capture_cam(conn1, conn1b):
def audio_listening(conn2, conn2b):
global catch_current_frame
catch_current_frame = False
# start dameon thread to handle frame requests:
Thread(target=handle_catch_current_frame_requests, args=(conn2,), daemon=True).start()
Thread(target=handle_cam_activate_requests, args=(conn2b,), daemon=True).start()
while True:
r = sr.Recognizer()
with sr.Microphone() as source:
catch_current_frame = False
r.adjust_for_ambient_noise(source)
print("Please say something...")
audio = r.listen(source)
try:
text = r.recognize_google(audio, language="es-ES")
print("You have said: \n " + repr(text))
#Verifications
if text.lower() == "capture":
catch_current_frame = True
elif text.lower() == "Close your program":
#This is where I need to close processes p1, p2 and p3
break
else:
pass
except Exception as e:
print("Error : " + str(e))
def main_process(finish_state):
conn1, conn1_3 = multiprocessing.Pipe(duplex=True)
conn2, conn2_3 = multiprocessing.Pipe(duplex=True)
conn1b, conn2b = multiprocessing.Pipe(duplex=True)
#Process 1
p1 = multiprocessing.Process(target=capture_cam, args=(conn1, conn1b, ))
p1.start()
#Process 2
p2 = multiprocessing.Process(target=audio_listening, args=(conn2, conn2b, ))
p2.start()
#Process 3
p3 = multiprocessing.Process(target=actions_func, args=(conn1_3 ,conn2_3 ,))
p3.start()
if __name__ == '__main__':
finish_state = multiprocessing.Event()
main_process(finish_state)
print("continue the code... ")
I need that when the variable text is equal to "Close your program" the 3 active processes(p1,p2,p3) are closed.
I have tried to do something like this:
elif text.lower() == "Close your program":
print("the process has been interrupted!")
finish_state.set()
for process in [p1, p2, p3]:
process.terminate()
But it is not working for me, and I would need a better code that allows me to close them one by one in that code block if text is equal to "Close your program".
What should I do so that under that condition all the processes are closed one by one?
You could try the following Event-based solution (but there are even simpler solutions to follow):
Have main_process pass to audio_listening an additional argument, finish_state:
def main_process():
conn1, conn1_3 = multiprocessing.Pipe(duplex=True)
conn2, conn2_3 = multiprocessing.Pipe(duplex=True)
conn1b, conn2b = multiprocessing.Pipe(duplex=True)
#Process 1
p1 = multiprocessing.Process(target=capture_cam, args=(conn1, conn1b, ))
p1.start()
#Process 2
finish_state = multiprocessing.Event()
p2 = multiprocessing.Process(target=audio_listening, args=(conn2, conn2b, finish_state))
p2.start()
#Process 3
p3 = multiprocessing.Process(target=actions_func, args=(conn1_3 ,conn2_3 ,))
p3.start()
finish_state.wait()
p1.terminate()
p2.terminate() # Not really necessary since the process is ending by itself
p3.terminate()
if __name__ == '__main__':
main_process()
Note that it is now main_process that is creating the finish_state multiprocessing.Event instance; there appears to be no need for it to be passed as an argument. When the event is set, the main process will terminate the subprocesses that it has created.
Then in audio_processing:
def audio_listening(conn2, conn2b, finish_state):
...
if text.lower() == "capture":
catch_current_frame = True
elif text.lower() == "Close your program":
# Set the finish state event:
finish_state.set()
break
There are even two simpler alternatives that do not even require an Event variable:
The audio_process process is in an infinite loop until it either gets a "Close your program" message or it gets an exception. In both cases it terminates and presumably we then want the other two processes to terminate, also. Therefore, the main process can just issue a call to p2.join() after it has started all the other processes in order to wait for the audio_process process to complete and then either:
Call p1.terminate() followed by p3.terminate().
Or start processes p1 and p3 specifying daemon=True, e.g. p1 = multiprocessing.Process(target=capture_cam, args=(conn1, conn1b), daemon=True). Being daemon processes they will now automatically terminate as soon as the main process terminates. Therefore, there is no need to call terminate on these processes.

Python Threading for Camera

I am trying to put the camera footage into a different thread as the cv2.wait() does not work correctly anymore for access keys even when using an '& and hexadecimal'.
Does anyone know what I have done wrong with the daemon thread I have created for displaying camera footage in the main as when placed in the main while loop it fails while loop?
How do I use a thread to continuously display camera footage in my while loop in the main program?
quote My thread for the ViewCamera function isn't working right - can anyone help?
from djitellopy import Tello
# Access the telopy libray.
import cv2, math, time
from time import sleep, perf_counter
from threading import Thread
stop = True
def ViewCamera():
global stop
while stop == True:
try:
#camera window
img = frame_read.frame
cv2.imshow("drone", img)
print ('thread test')
except Exception as e:
print ("Cerror is : ,", e)
drone = Tello()
'''
create an instance of the Tellopy libray
drone.connect() #connect to drone using wifi
drone.streamon()
#make use of a data stream to drone to pass on keyboard commands
#frame_read = drone.get_frame_read() #read cammera data using frame per frame rate
'''
key = 0
# drone.takeoff()
if __name__ == "__main__":
print ('main program')
# Create a camera thread - runs in background.
t1 = Thread(target=ViewCamera, args=())
t1.daemon = True
print('starting thread')
t1.start()
while True:
key = ord(input('please enter letter'))
if key == ord('j'):
drone.land()
print('stopping thread')
stop = False
break
elif key == ord('w'): # Forward
drone.move_forward(30)
print('moving forwards')
elif key == ord('s'): # Move backwards
drone.move_back(30)
elif key == ord('a'): # Move left
drone.move_left(30)
elif key == ord('d'): # Move right
drone.move_right(30)
elif key == ord('e'): # Rotate right
drone.rotate_clockwise(30)
elif key == ord('q'): # Rotate left
drone.rotate_counter_clockwise(30)
elif key == ord('r'): # Move up
drone.move_up(30)
elif key == ord('f'): # Move down
drone.move_down(30)
print('stopping thread')
t1.join()
drone.land()
The threading daemon isn't seeming to work it should be running in background and continually allowing the camera images in a window to be viewed - any ideas why it is not?

Running two function together with multiprocessing and share variables

i used multiprocessing but i don't know how to do it
the logic : a variable sign is equal to 0, with a function called timer count 20 seconds and each second check if sign is equal to 1 then it'll print something and breaks the loop, at the same time with a function called waiting waits for an input from another library as example "discord" or "socket" so if the input is equal to my key flip the variable sign to 1 and that affects the first function timer
import multiprocessing
from time import sleep
sign = 0
def timer():
for s in range(20):
if sign == 1: # if the input is equal to the secret key then break the timer
print("Yes!")
break
else:
sleep(1) #if not then continue timing
def waiting():
# maybe it waits for an input or a message from "discord or whatsapp"
if message == "secret_key":
sign = 1
p1 = multiprocessing.Process(target=timer)
p2 = multiprocessing.Process(target=waiting)
p1.start()
p2.start()
I mentioned it above in a comment, but here is how you would use an event
import time
import multiprocessing as mp
def timer(exit_event):
for s in range(20):
if exit_event.is_set():
print("Yes!")
break
else:
time.sleep(1) #if not then continue timing
def waiting(exit_event):
# maybe it waits for an input or a message from "discord or whatsapp"
time.sleep(5)
exit_event.set()
if __name__ == '__main__':
exit_event = mp.Event()
p1 = mp.Process(target=timer, args=(exit_event,))
p2 = mp.Process(target=waiting, args=(exit_event,))
p1.start()
p2.start()
p1.join()
p2.join()
However the real way to use an Event is to just to wait() for it to become true. No need for a sleep loop.
def timer(exit_event):
if exit_event.wait(timeout=20)
# returns True if the event is True. False if timed out
print("Yes!")

Python - creating a simple killswitch for a function that runs with multiprocessing

So, i would claim that i understand how Asyncio, Multiprocessing, Threading etc. works, basically. I know how to listen for keystrokes too - there are many good examples on this site.
However i was unable to combine both into one. I have a programm that runs continously in a loop, until it runs into certain cases where it stops. In these cases, it uses a Multiprocessing.Queue() to prompt for user input on wether it should continue or not.
All of this works, so far so good. Now i want to add a second catch case here: The programm should, once it starts running, immediatly cease working as soon as i press a certain button (lets say Escape).
This is the very dumbed down version of my programm:
test.py:
from test3 import Counter
from multiprocessing import Process, Queue
import sys
def main(q, passed_variable):
foo = Counter()
p1 = Process(target=foo.counting, args=(q,passed_variable))
p1.start()
p1.join()
if q.get() == False:
x = input("Keep going?")
print(x)
if x == "y":
main(q, user_Input)
else:
sys.exit()
if __name__ == "__main__":
q = Queue()
user_Input = ("What you want from me, man?")
print("Starting")
main(q, passed_variable=user_Input)
test3.py:
import time
class Counter:
def counting(self, q, user_input):
x = 0
while True:
print(str(x) + " " + user_input)
if x == 4:
q.put(False)
break
time.sleep(1)
x += 1
I tried everything i could think of, in no case did i get the desired result, and no question i found here was able to help me in this specific case.
You can solve this using keyboard and then creating a second Queue():
from test3 import Counter
from multiprocessing import Process, Queue
import sys
import keyboard
def main(q, queue2, passed_variable):
foo = Counter()
p1 = Process(target=foo.counting, args=(q,passed_variable))
p1.start()
p2 = Process(target=keyCatcher, args=(queue2,))
p2.start()
if queue2.get() == False:
p1.terminate()
print("Terminating Programm")
sys.exit()
if q.get() == False:
x = input("Keep going?")
print(x)
if x == "y":
main(q, queue2, user_Input)
else:
sys.exit()
def keyCatcher(queue2):
while True:
if keyboard.is_pressed('q'): # if key 'q' is pressed
queue2.put(False)
if __name__ == "__main__":
q = Queue()
queue2 = Queue()
user_Input = ("What you want from me, man?")
print("Starting")
main(q, queue2, passed_variable=user_Input)
The crux is:
p1.start()
p1.join()
Which means after main() starts p1, it waits for it to finish. So there's no chance to interrupt it while processing.
You need to:
wait for p1 to finish
while waiting, see if the main process gets a 'q'
if the main process gets a 'q', stop it.
Something like:
p1.start()
while p1.is_alive():
k = keyboard.read_key()
if k == 'q':
p1.terminate()

Python Video Processing

I have written a code which plays a video in two different frames using two threads.The code looks fine but the cv2.imshow method does not display the videos playing. The video player opens and closes immediately.
Help required in resolving the issue.
import threading
import cv2
def print_cube(num):
"""
function to print cube of given num
"""
print("start")
print(num)
cv2.imshow("video1",num)
print("end")
cv2.destroyAllWindows()
def print_square(num):
"""
function to print square of given num
"""
print("start1")
print(num)
cv2.imshow("video2",num)
print("end2")
if __name__ == "__main__":
# creating thread
cap = cv2.VideoCapture("C:\\Users\shakarna\Desktop\video.mp4")
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# Our operations on the frame come here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
t1 = threading.Thread(target=print_square, args=(frame,))
t2 = threading.Thread(target=print_cube, args=(gray,))
# starting thread 1
t1.start()
# starting thread 2
t2.start()
# wait until thread 1 is completely executed
t1.join()
# wait until thread 2 is completely executed
t2.join()
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
the problem could be that your code cannot find the video. To look whether this is the problem or not place your mp4 file into the same folder as your code, than
cap = cv2.VideoCapture("C:\Users\shakarna\Desktop\video.mp4")
should be
cap = cv2.VideoCapture("video.mp4")

Categories