Search code examples
pythonopencvtimersleepbounding-box

time.sleep() not pausing timer in video


Background

I have a video with people walking around different homes. I implemented 3 different timers (for 3 different people) that begin timing when the people are inside the bboxes of the homes and pause when they are outside of the bboxes of the homes. For reference, I have included a visual of what the first frame of the video looks like.

enter image description here

Problem

The check implemented in the code below works fine - it returns True when a person's bbox is inside of a home bbox and returns False otherwise. I'm having difficulties when it comes to pausing the time as a person is walking around outside of the home bbox (i.e. when a person's bbox is not inside of a home bbox). As you can see in the code below, I used time.sleep(1) to pause the timer for a second each time a False is returned, however, this doesn't seem to work. It just keeps the timer running in the background. For example, if person 1's timer is at 15 seconds before a False is returned, its timer should pause. Then, when a True is returned, its timer should resume its time from 15 seconds and increment. However, in my case right now, it keeps running the timer in the background so when a True is returned after a False, the timer suddenly shows up as 24 seconds instead of resuming from where it left off before the time.sleep(). How do I go about solving this issue?

# boxes_houses = [(#, #, #, #), (#, #, #, #), ...]

while cap.isOpened():

    # [...]

    def isInside(person, home):
        # Top-left corner
        if home['x1'] < person['x1'] and home['y1'] < person['y1']:
            # Bottom-right corner
            if person['x2'] + (person['x2'] - person['x1']) < home['x2'] + (home['x2'] - home['x1']) and person['y2'] + (person['y2'] - person['y1']) < home['y2'] + (home['y2'] - home['y1']):
                return True
        else:
            return False

    cnt_person = 0
    cnt_house = 0

    for box_person, box_house in zip(boxes_persons, boxes_houses):
        x_p1 = int(box_person[0])
        y_p1 = int(box_person[1])
        x_p2 = int(box_person[2])
        y_p2 = int(box_person[3])
        person_coords = {'x1': x_p1, 'y1': y_p1, 'x2': x_p2, 'y2': y_p2}
        cv2.rectangle(frame, (x_p1, y_p1), (x_p1 + x_p2, y_p1 + y_p2), (0, 0, 0), 2, 1)
        cv2.putText(frame, "House: {}".format(cnt_house), (x1, y1 - 10), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0, 0, 0), 1)

        x_h1 = int(box_house[0])
        y_h1 = int(box_house[1])
        x_h2 = int(box_house[2])
        y_h2 = int(box_house[3])
        cv2.rectangle(frame, (x_h1 , y_h1), (x_h1 + x_h2, y_h1+ y_h2), (0, 0, 255), 2, 1)
        cv2.putText(frame, "Person: {}".format(cnt_person ), (int(box_house[0]), int(box_house[1] - 5)), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0, 0, 255), 1)

        isinside_checks = []
        for house in houses:
            isinside_checks.append(isInside(person_coords, house))

        ### CHECK ###
        
        if any(inside_checks): #if persons inside the home bbox
            # print ("Person", cnt_person, ": True\n")

            if cnt_person==0:
                cv2.putText(main_frame, "Person 0 Time: {}".format(end_time-start_time), (450, 500), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0,0,0),1)
            elif cnt_person==1:
                cv2.putText(main_frame, "Person 1 Time: {}".format(end_time-start_time), (450, 500), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0,0,0),1)
            elif cnt_person==2:
                cv2.putText(main_frame, "Person 2 Time: {}".format(end_time-start_time), (450, 500), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0,0,0),1)

        else: #if persons outside the home bbox
            print ("Person", cnt_person, ": False\n") 
            time.sleep(1) # should pause the time

        cnt_person = cnt_person + 1
        cnt_house = cnt_house + 1
                       
    # show frame
    cv2.imshow('MultiTracker', frame)

    if cv2.waitKey(1) & 0xFF == 27:  
        break

Solution

  • Interesting challenge you have. Seems like you understand the problem, the timer will continue to check time even when you sleep the execution of the program. I believe this is because the timer is based on the number of milliseconds since an epoch from years ago or something.

    The time() function returns the number of seconds passed since epoch. For Unix system, January 1, 1970, 00:00:00 at UTC is epoch (the point where time begins).

    https://www.programiz.com/python-programming/time

    Therefore, just because you pause your execution, that doesn’t mean that time hasn’t increased since that point in the past.

    How would I handle this problem?

    I would track the amount of time paused and subtract that from the total amount of time passed for each person.

    Outside of the for loop initialise:

    pause_times = [0, 0, 0] # the total time paused for each person
    last_pause = [0, 0, 0] # the times of the last pause for each person
    paused = False
    

    Then where you check whether people are inside or outside the houses, update the pause times or total times appropriately:

    if any(inside_checks): #if persons inside the home bbox
        # print ("Person", cnt_person, ": True\n")
        paused = False
        if cnt_person==0:
                cv2.putText(main_frame, "Person 0 Time: {}".format(end_time-start_time-pause_times[0]), (450, 500), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0,0,0),1)
        elif cnt_person==1:
                cv2.putText(main_frame, "Person 1 Time: {}".format(end_time-start_time-pause_times[1]), (450, 500), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0,0,0),1)
        elif cnt_person==2:
                cv2.putText(main_frame, "Person 2 Time: {}".format(end_time-start_time-pause_times[2]), (450, 500), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0,0,0),1)
    
    else: #if persons outside the home bbox
        print ("Person", cnt_person, ": False\n")
        if not paused:  # the timer hasn't been paused for a while
            last_pause[cnt_person] = end_time # updating the pause point
            paused = True
        pause_times[cnt_person] += end_time - last_pause[cnt_person] # track the total amount of time paused for each person
        last_pause[cnt_person] = end_time
    

    Disclaimer:

    I feel obligated to say I might not totally understand your problem and I'm not an expert so my solution might be flawed. I hope that it offers you a different perspective at the very least. Cheers.