Reputation: 123
I working with R-Pi
and cam
. I have made code that iterate procedure over an hour.
import numpy as np
import cv2
import time
ret, frame = cam0.read()
timecheck = time.time()
future = 60
runNo = 0
while ret:
if time.time() >= timecheck:
ret, frame = cam0.read()
#Do something here
timecheck = time.time()+future
runNo=runNo+1
if(runNo> 60):
break
else:
ret = cam0.grab()
#save log as .txt file
with open("acc_list.txt", "w") as output:
output.write(str(acc_list))
But sometimes, it takes less than hour to finish work. I want to quit the iteration before runNo
get to 60
. Because I have to save acc_list.txt
file, I can't just shut the program down.
If it was video streaming, I would use this:
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
if cv2.waitKey(1) & 0xFF == ord('q'):
break
But I have encountered errors while modifying this to my code.
Is there nice way to do this?
Upvotes: 1
Views: 411
Reputation: 191
you can put in the loop:
if cv2.waitKey(1) & 0xFF == ord('q'):
break
this will let you exit when hitting q.
Upvotes: 0
Reputation: 207405
There are lots of possible approaches, some are cleaner and some are dirtier :-)
In no particular order, here are some. I will probably add code for them as I find spare time to explain them properly.
Method 1 - Use a sentinel file
An easy (and "hacky") way to do this is to check inside the loop for the existence of a file called stop
. Then in the shell/Terminal, just do:
touch stop
and the program will exit. If you happen to use bash
, you can just type:
> stop
Remember to delete the file called stop
at the beginning and end of your program.
I am no Python programmer but this works:
#!/usr/local/bin/python3
import os
from time import sleep
# Remove any sentinel "stop" files from previous runs
def CleanUp():
try:
os.remove('stop')
except:
pass
CleanUp()
runNo=0
while True:
print("Running...")
sleep(1)
if runNo>60 or os.path.exists('stop'):
break
runNo=runNo+1
print("Writing results")
CleanUp()
Method 2 - Use a second thread
Another way to do it is to start a second thread that does a blocking read from the terminal, and when the user enters something, it sets a flag which the main thread checks on each iteration through its loop the same as it checks runNo
.
This demonstrates:
#!/usr/local/bin/python3
import threading
import os
from time import sleep
ExitRequested=False
def InputHandlerThread():
global ExitRequested
s=input('Press Enter/Return to exit\n')
print("Exit requested")
ExitRequested=True
# Start user input handler - start as daemon so main() can exit without waiting
t=threading.Thread(target=InputHandlerThread,daemon=True)
t.start()
runNo=0
while True:
print('runNo: {}'.format(runNo))
sleep(1)
if runNo>60 or ExitRequested:
break
runNo=runNo+1
print("Writing results")
This may not work best with OpenCV because the imshow()
function somehow uses spare time (given as the milliseconds parameter) in the waitKey()
function to update the screen. You will see this if you call imshow()
without any following waitKey()
- nothing will appear on the screen.
So, if you are using imshow()
you must use waitKey()
and that will interfere with reading the keyboard in the second thread. If that's the case, use one of the other methods.
Method 3 - Write results incrementally
A third way to do it is to open your results file for append inside the loop and add each new result as it comes available rather than waiting till the end.
I don't know enough about your algorithm to know if this is a possibility for you.
I'm still no Python programmer, but this works:
#!/usr/local/bin/python3
import os
from time import sleep
runNo=0
while True:
print("Running...")
# Append results to output file
with open("results.txt", "a") as results:
results.write("Result {}\n".format(runNo))
sleep(1)
if runNo>60:
break
runNo=runNo+1
Method 4 - Use a signal
A fourth way to do it is to set up a signal handler and when it receives the signal it sets a flag which the main loop checks on every iteration. Then in the terminal you use:
pkill -SIGUSR1 yourScript.py
Here is some working code:
#!/usr/local/bin/python3
import signal
import os
from time import sleep
def handler(signum,stack):
print("Signal handler called with signal ",signum)
global ExitRequested
ExitRequested=True
ExitRequested=False
# Install signal handler
signal.signal(signal.SIGUSR1,handler)
runNo=0
while True:
print('runNo: {} Stop program with: "kill -SIGUSR1 {}"'.format(runNo,os.getpid()))
sleep(1)
if runNo>60 or ExitRequested:
break
runNo=runNo+1
print("Writing results")
Sample Output
runNo: 0 Stop program with: "kill -SIGUSR1 16735"
runNo: 1 Stop program with: "kill -SIGUSR1 16735"
runNo: 2 Stop program with: "kill -SIGUSR1 16735"
runNo: 3 Stop program with: "kill -SIGUSR1 16735"
runNo: 4 Stop program with: "kill -SIGUSR1 16735"
runNo: 5 Stop program with: "kill -SIGUSR1 16735"
runNo: 6 Stop program with: "kill -SIGUSR1 16735"
runNo: 7 Stop program with: "kill -SIGUSR1 16735"
Signal handler called with signal 30
Writing results
Discussion
YMMV, but my feeling is that Method 3 is the cleanest, and that Method 1 is the biggest hack. Method 2 is probably closest to what you asked for and I did Method 4 (and all the others, in fact) so I could learn something.
If any real Python programmers have any comments, I'd be happy to learn.
Upvotes: 2