Python - creating a delay that takes in account the execution time - python

i am writing a function that reads N (800*600) frames from a bin file in one sec. the FPS is user controllable
import time
def getFrame(file,N): #read N frames per second, 800X600 pixels each from file
start = time.time()
delay = (1/float(N))
while N:
frame = file.read(480000)
time.sleep(delay)
N -= 1
print time.time()-start
return
the time.sleep() creates the delay, but without taking in account the execution time of the rest of the code.
so in total the running time is always bigger then 1 sec and it increments as i increase my N (fps) value.
is there a way to create a delay that takes into account the processing time ?

ummm .... you need basic math here
time.sleep(delay-(time.time()-start))

Related

How can I write a loop to make the timer run every two seconds

I have a question on how I am able to set the timer so that every time it exits the loop it sets the time back to 2 seconds. The problem is that the first time the sound works after 2 seconds, the next times it is executed immediately. Thank you very much in advance for any advice.
This is my code:
time = 2
while time > 0:
timer = datetime.timedelta(seconds=time)
time -= 1
duration = 1000
freq = 440
winsound.Beep(freq, duration)
I am not sure if you meant that, but for me it seems like you just want to wait 2 seconds before executing the next steps. You can do that like so:
import time
while True:
time.sleep(2) # waits 2 seconds
winsound.Beep(440, 1000)
Anyways I don't recommend you to use a plain infinite loop, without a break statement. Therefore I recommend you to add one, like down below.
import time
while True:
time.sleep(2) # waits 2 seconds
winsound.Beep(440, 1000)
if True: # break on a specific statment
break
Edit: As CrazyChucky mentioned in the comments, this approach should work fine in most of the cases, but it can end up being more than two seconds sometimes. Therefore you should work with timedeltas or take a look at scheduler.
To be more accurate as possible use:
import time
timer = 0
step = 2
t0 = time.time()
while True:
timer = time.time() - t0
wait = step - timer
time.sleep(wait)
print(time.time())
winsound.Beep(freq, duration)
t0 = time.time()
This script take in count the execution time of script lines for your computer.
You just have to reinitialize the time at the end of the loop
time = 2
while True:
timer = datetime.timedelta(seconds=time)
time -= 1
duration = 1000
freq = 440
if time == 0:
time = 2
break
winsound.Beep(freq, duration)

Parallelize slow functions that needs to be run only every X iterations in order to not slow the loop

The project
I am conducting a project where I need to both detect faces (bounding boxes and landmarks) and perform face recognition (identify a face). The detection is really fast (it takes not even a few milliseconds on my laptop) but the recognition can be really slow (about 0.4 seconds on my laptop). I am using the face_recognition Python library to do so. After a few tests, I discovered that it is the embedding of the image that is slow.
Here is an example code to try it out for yourself :
# Source : https://pypi.org/project/face-recognition/
import face_recognition
known_image = face_recognition.load_image_file("biden.jpg")
biden_encoding = face_recognition.face_encodings(known_image)[0]
image = face_recognition.load_image_file("your_file.jpg")
face_locations = face_recognition.face_locations(image)
face_landmarks_list = face_recognition.face_landmarks(image)
unknown_encoding = face_recognition.face_encodings(image)[0]
results = face_recognition.compare_faces([biden_encoding], unknown_encoding)
The problem
What I need to do is to process a video (30 FPS), therefore 0.4s of computation is unacceptable. The idea that I have is that the recognition will only need to be run a few times and not every frame since from one frame to another, if there are no cuts in the video, a given head will be close to its previous position. Therefore, the first time the head appears, we run the recognition which is very slow but then for the next X frames, we won't have to since we'll detect that the position is close to the previous one, therefore it must be the same person that moved. Of course, this approach is not perfect but seems to be a good compromise and I would like to try it.
The only problem is that by doing so the video is smooth until a head appears, then the video freezes because of the recognition and then becomes smooth again. This is where I would like to introduce multiprocessing, I would like to be able to compute the recognition in parallel of looping through the frame of the video. If I manage to do so, I will then only have to process a few frames in advance so that when a face shows up it already computed its recognition a few seconds ago during several frames so that we did not see a reduced frame rate.
Simple formulation
Therefore here is what I have (in python pseudo code so that it is clearer):
def slow_function(image):
# This function takes a lot of time to compute and would normally slow down the loop
return Recognize(image)
# Loop that we need to maintain at a given speed
person_name = "unknown"
frame_index = -1
while True:
frame_index += 1
frame = new_frame() # this is not important and therefore not detailes
# Every ten frames, we run a heavy function
if frame_index % 10 == 0:
person_name = slow_function(image)
# each frame we use the person_name even if we only compute it every so often
frame.drawText(person_name)
And I would like to do something like this :
def slow_function(image):
# This function takes a lot of time to compute and would normally slow down the loop
return Recognize(image)
# Loop that we need to maintain at a given speed
person_name = "unknown"
frame_index = -1
while True:
frame_index += 1
frame = new_frame() # this is not important and therefore not detailes
# Every ten frames, we run a heavy function
if frame_index % 10 == 0:
DO slow_function(image) IN parallel WITH CALLBACK(person_name = result)
# each frame we use the person_name even if we only compute it every so often
frame.drawText(person_name)
The goal is to compute a slow function over several iterations of a loop.
What I have tried
I looked up multiprocessing and Ray but I did not find examples of what I wanted to do. Most of the time I found people using multiprocessing to compute at the same time the result of a function for different inputs. This is not what I want. I want to have in parallel a loop and a process that accepts data from the loop (a frame), do some computation, and returns a value to the loop without interrupting or slowing down the loop (or at least, spreading the slow down rather than having one really slow iteration and 9 fast ones).
I think I found pretty much how to do what I want. Here is an example:
from multiprocessing import Pool
import time
# This seems to me more precise than time.sleep()
def sleep(duration, get_now=time.perf_counter):
now = get_now()
end = now + duration
while now < end:
now = get_now()
def myfunc(x):
time.sleep(1)
return x
def mycallback(x):
print('Callback for i = {}'.format(x))
if __name__ == '__main__':
pool=Pool()
# Approx of 5s in total
# Without parallelization, this should take 15s
t0 = time.time()
titer = time.time()
for i in range(100):
if i% 10 == 0: pool.apply_async(myfunc, (i,), callback=mycallback)
sleep(0.05) # 50ms
print("- i =", i, "/ Time iteration:", 1000*(time.time()-titer), "ms")
titer = time.time()
print("\n\nTotal time:", (time.time()-t0), "s")
t0 = time.time()
for i in range(100):
sleep(0.05)
print("\n\nBenchmark sleep time time:", 10*(time.time()-t0), "ms")
Of course, I will need to add flags so that I do not write a value with the callback at the same time that I read it in the loop.

Have python.sleep variate with computation time

For an animation project, we want to model a variable number of objects. This means that the computation and rendering part will take variable computation time. But we want the frame rate of the animation to remain constant. So we would like to compute how much time a section of code has taken, and if it is less then the expected frame rate, we wait the remainded before calculation the next frame.
Is there an easy way to do this?
One way to do it is by using the time library that has a method time that allows you to count how much time a section of code has taken to execute, an example down below.
import time
start_time = time.time()
#Your code here
end_time = time.time() - start_time
print(end_time)
You stopwatch the time, and sleep it for 1-x seconds.
sleep_time = 1/1 #Second number is frames per unit of time, first number is unit of time. In seconds.
from time import time #Important function: time(): Secs since unix epoch
while True: #Init animation
init_time = time() #Init stopwatch
#Code here Do your code
timer = time()-init_time #End stopwatch and remember time in a variable.
while time() < init_time+sleep_time-timer: pass #Wait ___ seconds
#Restart and go to next frame.
If the code that you coded in lasts longer than 'sleep time', than it will not wait.
Hope this helps, and good luck with animating!

How to make a timer more efficient

I am quite new to coding and i am wondering how to make it more efficient. I am running it on a raspberry pi which will have other tasks so i want this to be as easy to run as possible. The code will use a magnetic sensor to record passes made by a magnet mounted on a wheel and from there determine the speed of the outside diameter of the wheel. It would be useful to implement something that takes the five last speed outputs and gives sort of an average but only if it does not affect the complexity of the code much. Would be really greatful for any help!
from gpiozero import Button
import time
global t0
t0 = time.clock()
raduis = 300
button = Button (21)
from signal import pause
def calculate_speed(radius):
global t0
t1 = time.clock
interval = t1 - t0
speed = radius/interval
print (speed, 'mm/sek')
y = True
while y == True:
button.when_pressed = calculate_speed(radius)
time.sleep(0.2)
#used to prevent one pass of the magnet from recording many passes
You should store five last speed outputs in an array (list) and then you can calculate the average speed
speed_records = []
def calculate_speed(radius):
global t0
t1 = time.clock
interval = t1 - t0
speed = radius/interval
print (speed, 'mm/sek')
speed_records.append(speed) # Adds one speed record to the list
if len(speed_records) >= 5: # checks if there are 5 five records available
last_five_records = speed_records[-5:] # Seperates five last records
average = sum(last_five_records) / 5
print('Average Speed:',average) # Prints out the average
if len(speed_records) > 10: # Free Up some memory
speed_records = list(set(speed_records) - set(speed_records[:5])) #removes the first five records
The following code uses modular arithmetic to iterate through a single list, adding and overwriting values, and printing the averaged speed. Adjust iterations to control how many passes to average over.
from gpiozero import Button
from signal import pause
import time
radius = 300
button = Button (21)
iterations = 5
speeds = [0] * iterations
speed_idx = 0
def calculate_speed(radius):
global speeds, speed_idx
t1 = time.time()
speeds[speed_idx] = radius / (t1- t0)
print (sum(speeds) / iterations, 'mm/sek')
speed_idx += 1
speed_idx %= iterations
t0 = time.time()
while True:
button.when_pressed = calculate_speed(radius)
time.sleep(0.2)
t0 = time.time()
Note this takes 5 measurements to "ramp up" in a sense. If you want- you could add an if statement to avoid printing out the first 4 recordings.
Additionally, if you wanted a smoother measurement of speeds, it occurred to me that you could use a single value to hold the sum of the speeds of the last N passes, and each time subtract off the average (assuming N sums), and add the new speed. It would a few extra passes to stabilize, but afterwards it should smooth the reported speeds a bit.

What's the proper way to write a game loop in Python?

I'm trying to write a python game loop that hopefully takes into account FPS. What is the correct way to call the loop? Some of the possibilities I've considered are below. I'm trying not to use a library like pygame.
1.
while True:
mainLoop()
2.
def mainLoop():
# run some game code
time.sleep(Interval)
mainLoop()
3.
def mainLoop():
# run some game code
threading.timer(Interval, mainLoop).start()
4.
Use sched.scheduler?
If I understood correctly you want to base your game logic on a time delta.
Try getting a time delta between every frame and then have your objects move with respect to that time delta.
import time
while True:
# dt is the time delta in seconds (float).
currentTime = time.time()
dt = currentTime - lastFrameTime
lastFrameTime = currentTime
game_logic(dt)
def game_logic(dt):
# Where speed might be a vector. E.g speed.x = 1 means
# you will move by 1 unit per second on x's direction.
plane.position += speed * dt;
If you also want to limit your frames per second, an easy way would be sleeping the appropriate amount of time after every update.
FPS = 60
while True:
sleepTime = 1./FPS - (currentTime - lastFrameTime)
if sleepTime > 0:
time.sleep(sleepTime)
Be aware thought that this will only work if your hardware is more than fast enough for your game. For more information about game loops check this.
PS) Sorry for the Javaish variable names... Just took a break from some Java coding.

Categories

Resources