How to run time.sleep() without stopping while loop - python-3.x

Is there a way to call a function which has wait(time.sleep()) from infinite while loop without disturbing the loop?
I am trying to run a few task that require to wait for a few seconds but the issue is that the while loop also stops when the wait process is happening.
This is what I have tried out-
Here is my code:
import cv2
import time
def waiting():
print("Inside function")
# Running Some Tasks
time.sleep(5)
print("Done sleeping")
def main():
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
cv2.imshow("Webcam", frame)
k = cv2.waitKey(10)
if k == 32: # Press SPACEBAR for wait function
waiting()
elif k == 27: # Press ESC to stop code
break
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()

Thanks for the quick responses from #JLT and #TerePiim. Here is the updated code for anyone who might benefit from this:
import cv2
import time
import threading
def waiting():
print("Inside parallel function")
# Running some Tasks
time.sleep(5)
print("Done sleeping")
def main():
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
cv2.imshow("Webcam", frame)
k = cv2.waitKey(10)
if k == 32: # Press SPACEBAR for wait function
t = threading.Thread(target=waiting)
t.start()
elif k == 27: # Press ESC to stop code
break
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()

You are working in a single thread script at the moment. You should use threading or multiprocessing. This makes (it look like) multiple processes (are) active. Dependent on if you use threading or multiprocessing.

You should use threads. It will look like the computer is doing them both at the same time.
import threading
t = threading.Thread(target=function)
t.start()

Related

How to safely terminate a thread in Python

I have below code, where I am using OpenCV to start webcam video. Along with that I also have a thread running that pings www.google.com to check network connectivity.
import time
import cv2
import os
from threading import Thread
stopThread = False
def CheckNetwork():
global stopThread
while True:
time.sleep(60)
host = "www.google.com"
response = os.system("ping " + host)
if response == 0:
print("Internet host reachable")
else:
print("Internet host not reachable")
if stopThread:
break
def main():
global stopThread
Thread(target=CheckNetwork).start()
cam = cv2.VideoCapture(0)
while True:
ret_val, img = cam.read()
cv2.imshow('Camera', img)
key = cv2.waitKey(1)
if key == ord('q'):
stopThread = True
break
cv2.destroyAllWindows()
main()
This code is running fine. If I have to close the application by pressing q, OpenCV window closes but application keeps running for 60sec because of the thread and only after 60sec whole application terminates safely.
I wanted to know if this is a good way to close the threads. Is there any better way available which can immediately terminate threads in Python?
There's no native way of stopping a thread in Python. Instead of using a stop flag, you can also use ctypes that calls the Python API to raise an exception in the thread.
import ctypes
# Other imports...
class ThreadWithException(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
def run(self):
# code here...
def get_id(self):
# returns id of the respective thread
if hasattr(self, '_thread_id'):
return self._thread_id
for id, thread in threading._active.items():
if thread is self:
return id
def raise_exception(self):
thread_id = self.get_id()
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id,
ctypes.py_object(SystemExit))
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
print('Exception raise failure')

Sharing camera frames between threads

I'm trying to build a script to manage multiple threads that are supposed to be running in parallel, and exchange data between them.
As a starting point, I have two threads...the first one should be reading frames from a USB camera and send them to queue, while the second should read them and display them.
I tried:
import json
import queue, threading
from queue import Queue
import cv2
class system_manager():
def __init__(self, source):
## camera reader
self.camera_queue = queue.Queue()
self.camera_reader = threading.Thread(target=camera_reader, args=(source, self.camera_queue))
self.camera_reader.daemon = True
self.camera_reader.run()
self.camera_display = threading.Thread(target=camera_display, args=(self.camera_queue))
self.camera_display.daemon = True
self.camera_display.run()
def camera_reader(source, camera_queue):
print("Cam Loading...")
cap = cv2.VideoCapture(source)
print("Cam Loaded...")
while(True):
ret, frame = cap.read()
camera_queue.put(frame)
def camera_display(camera_queue):
print("doing something")
while(True):
frame = camera_queue.get()
key = cv2.waitKey(1)
if (key == ord('q')):
break
cv2.imshow("frame", frame)
if __name__ == "__main__":
SM = system_manager(source=0)
but it's not really working. The first thread, the one supposed to read frames, is actually doing that, but the second one is not displaying anything (there's a print statement at the beginning, and it's not shown). Also, after running for a few minutes, it got my computer completely stuck, so I assume I'm accidentally continuously occupying memory.
I'm fairly new to multiprocessing/multithreading, so I'm probably doing some very basic mistake somewhere.
EDIT
Ok, fixed the memory problem by using:
self.camera_queue = queue.Queue(maxsize=5)
but the second thread is not working yet
Use thread.start() instead of thread.run() , fix the thread target method and add comma after the argument. This works.
import json
import queue, threading
from queue import Queue
import cv2
class system_manager():
def __init__(self, source):
## camera reader
self.camera_queue = queue.Queue(maxsize=5)
self.camera_reader = threading.Thread(target=camera_reader, args=(source, self.camera_queue))
self.camera_reader.daemon = True
self.camera_reader.start()
self.camera_display = threading.Thread(target=camera_display, args=(self.camera_queue,))
self.camera_display.daemon = True
self.camera_display.start()
def camera_reader(source, camera_queue):
print("Cam Loading...")
cap = cv2.VideoCapture(source)
print("Cam Loaded...")
while(True):
ret, frame = cap.read()
camera_queue.put(frame)
def camera_display(camera_queue):
print("doing something")
while(True):
frame = camera_queue.get()
key = cv2.waitKey(1)
if (key == ord('q')):
break
cv2.imshow("frame", frame)
if __name__ == "__main__":
SM = system_manager(source=0)

Running opencv in a thread, unable to start a second time

When I try to start openvc in a thread, its working once, but after I call it a second time, it won’t start again. The code stuck’s when it reaches a cv2 function in this casecv2.imshow() (but after cv2.VideoCapture()).
If I call the start_videofeed() function right after it receives the signal of the socket, its working properly, but I would like to have the sock.recvfrom() to continue receiving for other commands.
This code is only a small example of my script, but I tried a lot and also searched on web but I couldn’t find any answer, only others with similar problems.
I’m running the latest opencv-python package, with python3.8 on manjaro.
I hope someone knows an answer how to solve this issue.
Thanks in advance.
import socket
from threading import Thread
import cv2
class VideoFeed():
def __init__(self):
self.url = 0
self.window_name = "Video"
def run(self):
sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
sock.bind( ('',54666) )
while True:
d, addr = sock.recvfrom( 1024 )
payload = d.decode()
if payload == "show_video":
self.start_video()
if payload == "exit":
break
def start_video(self):
vs = Thread(target=self.start_videofeed)
vs.start()
def start_videofeed(self):
cap = cv2.VideoCapture(self.url)
if (cap.isOpened()== False):
print("Error opening video file")
print("Starting videofeed")
while True:
ret, self.frame = cap.read()
cv2.imshow(self.window_name, self.frame)
key = cv2.waitKey(10)
if key == 27 or key == ord('q'):
break
if cv2.getWindowProperty(self.window_name, cv2.WND_PROP_VISIBLE) < 1:
break
cv2.destroyAllWindows()
cap.release()
print("Video release and Destroy")
return
vf = VideoFeed()
vf.run()
Edit:
I finally found an answer. It seems it's not possible to start the video from or in a thread a second time, so I set a boolean in the socket thread to start the videofeed from the main program.
class VideoFeed():
def __init__(self):
self.url = "http://192.168.178.103:8081"
self.window_name = "Video"
self.start_video = False
def run(self):
Thread(target=self.start_socket).start()
while True:
if self.start_video:
self.start_videofeed()
self.start_video = False
def start_socket(self):
sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
sock.bind( ('',54666) )
while True:
d, addr = sock.recvfrom( 1024 )
payload = d.decode()
if payload == "show_video":
self.start_video = True
if payload == "exit":
break
def start_videofeed(self):
cap = cv2.VideoCapture(self.url)
if (cap.isOpened()== False):
print("Error opening video file")
print("Starting videofeed")
while True:
ret, self.frame = cap.read()
cv2.imshow(self.window_name, self.frame)
key = cv2.waitKey(10)
if key == 27 or key == ord('q'):
break
if cv2.getWindowProperty(self.window_name, cv2.WND_PROP_VISIBLE) < 1:
break
cv2.destroyAllWindows()
cap.release()
print("Video release and Destroy")
return

How to implement a "background" or concurrent thread?

Figured it out, i think? Runs as expected. I'm not able to view the original code so I wrote this new one up. Is there a better way to do this?
import time
import threading
def threadee():
f = open(r'log.txt')
for line in f:
print(line)
time.sleep(0.2)
def threader():
while True:
threadee()
def main():
thread = threading.Thread(target=threader)
thread.start()
while True:
print('main thread running')
print(threading.enumerate())
time.sleep(1)
if __name__ == '__main__':
main()

Using multiprocessing and ProcessPoolExecutor simultaneously

I am trying to create a simple script for python3.5 that can execute heavy computer vision algorithms in parallel. I have created a process by multiprocessing.Process in main process.
Inside that process I create concurrent.futures.ProcessPoolExecutor. Spawned process submits tasks to processPoolExecutor and it works perfectly fine. But when I try to stop and join spawned process it hangs on join.
Also if replace processPoolExecuter to threadPoolExecuter everything works perfectly. What did I miss?
Here is main file:
import multiprocessing as mp
import queue as Queue
import numpy as np
import cv2
from time import sleep
import executer_debug
def worker(queue):
pExecutor = executer_debug.Worker()
pExecutor.set()
while True:
print("-->{}<--".format(pExecutor.get()))
sleep(1)
try:
income = queue.get_nowait()
break
except Queue.Empty:
pass
pExecutor.set()
print("<1>{}<1>".format(pExecutor.get()))
print("<2>{}<2>".format(pExecutor.get()))
def main():
queue = mp.Queue()
currProcess = mp.Process(target = worker, args=(queue,))
currProcess.start()
frame = np.zeros((480,640), dtype=np.uint8)
while True:
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
print("stopped")
queue.put("stop")
currProcess.join()
if __name__ == "__main__":
main()
And here is the second file. Code is very simple just enough to demonstrate the issue.
import collections
from concurrent.futures import ProcessPoolExecutor
from time import sleep
import multiprocessing as mp
def worker():
return 1
class Worker():
def __init__(self):
self.workers_count = 4
self.poolExecutor = ProcessPoolExecutor(max_workers = self.workers_count)
self.executors = collections.deque()
def set(self):
self.executors.append(self.poolExecutor.submit(worker))
def get(self):
if len(self.executors) > 0:
if self.executors[0].done():
return self.executors.popleft().result()
else:
return 0
else:
return -1
Thank you!

Resources