3

I've seen ways of using the time.sleep() function, however that stops the rest of the code from running.

I'm making a hand recognition script and want the video output to be hindered by a certain value being printed every second.

This is my code:

import cv2
from cvzone.HandTrackingModule import HandDetector
import time

cap = cv2.VideoCapture(0)
detector = HandDetector(maxHands=1, detectionCon=0.7)
length = 0
while True:
    success, img = cap.read()
    hands, img = detector.findHands(img)

    if hands:
        hand1 = hands[0]
        lmlist1 = hand1["lmList"]
        bbox = hand1["bbox"]
        cp1 = hand1["center"]
        HandType = hand1["type"]
        #fingers1 = detector.fingersUp(hand1)
        #print(fingers1)
        length, info, img = detector.findDistance(lmlist1[8], lmlist1[5], img)
        
    
    print(length)
    time.sleep(1)
        
    
    cv2.imshow("Image", img)
    cv2.waitKey(1) 
    if cv2.waitKey(1) == ord("q"):
        break
    

cap.release()
cv2.destroyAllWindows()

The problem is that because of:

print(length) 
time.sleep(1) 

the frame rate of the video is reduced to 1fps.

Is there a way to run the printing command so that it doesn't affect the frame rate?

Thanks.

EDIT

This is the new code and fps is still low on my computer.

import cv2
from cvzone.HandTrackingModule import HandDetector
import time
import threading
import math
#Resolution: 720 x 1280

cap = cv2.VideoCapture(0)

detector = HandDetector(maxHands=1, detectionCon=0.7)
length = 0

fingerpos = [1,1,1,1,1]

    
def index(img):
    
    lil, info, img = detector.findDistance(lmlist1[8], lmlist1[5], img)
    
    lib, info, img = detector.findDistance(lmlist1[6], lmlist1[5], img)
    
    lit, info, img = detector.findDistance(lmlist1[8], lmlist1[6], img)
    
    
    index_angle = (lib**2 + lit**2 - lil**2) / (2 * lib * lit)
    
    index_angle = math.degrees(math.acos(index_angle))
    return int(index_angle)

def middle(img):
    lml, info, img = detector.findDistance(lmlist1[12], lmlist1[9], img)
    
    lmb, info, img = detector.findDistance(lmlist1[12], lmlist1[10], img)
    
    lmt, info, img = detector.findDistance(lmlist1[10], lmlist1[9], img)
    
    
    middle_angle = (lmb**2 + lmt**2 - lml**2) / (2 * lmb * lmt)

    middle_angle = math.degrees(math.acos(middle_angle))
    return int(middle_angle)

def ring(img):

    lrl, info, img = detector.findDistance(lmlist1[16], lmlist1[13], img)
    
    lrb, info, img = detector.findDistance(lmlist1[16], lmlist1[14], img)
    
    lrt, info, img = detector.findDistance(lmlist1[14], lmlist1[13], img)
    
    
    ring_angle = (lrb**2 + lrt**2 - lrl**2) / (2 * lrb * lrt)
    
    ring_angle = math.degrees(math.acos(ring_angle))
    return int(ring_angle)

def pinky(img):
    lpl, info, img = detector.findDistance(lmlist1[20], lmlist1[17], img)
    
    lpb, info, img = detector.findDistance(lmlist1[20], lmlist1[18], img)
    
    lpt, info, img = detector.findDistance(lmlist1[18], lmlist1[17], img)
    
    
    pinky_angle = (lpb**2 + lpt**2 - lpl**2) / (2 * lpb * lpt)
    
    pinky_angle = math.degrees(math.acos(pinky_angle))
    return int(pinky_angle)

def thumb(img):
    ltl, info, img = detector.findDistance(lmlist1[4], lmlist1[2], img)
    
    ltb, info, img = detector.findDistance(lmlist1[4], lmlist1[3], img)
    
    ltt, info, img = detector.findDistance(lmlist1[3], lmlist1[2], img)
    
    
    thumb_angle = (ltb**2 + ltt**2 - ltl**2) / (2 * ltb * ltt)
    
    thumb_angle = math.degrees(math.acos(thumb_angle))
    return int(thumb_angle)

def data(img):
        
    print(str(thumb(img)) + ", " + str(index(img)) + ", " + str(middle(img)) + ", " + str(ring(img)) + ", " + str(pinky(img)))
    time.sleep(0.5)                

threading.Thread(target=data).start()    

while True:
    success, img = cap.read()
    #img = cv2.resize(img, (640, 420)) 
    hands, img = detector.findHands(img)
    
    #print('Resolution: ' + str(img.shape[0]) + ' x ' + str(img.shape[1]))
    if hands:
        hand1 = hands[0]
        lmlist1 = hand1["lmList"]
        bbox = hand1["bbox"]
        cp1 = hand1["center"]
        HandType = hand1["type"]
        
        data(img)
        #print(str(thumb(img)) + ", " + str(index(img)) + ", " + str(middle(img)) + ", " + str(ring(img)) + ", " + str(pinky(img)))
            
    cv2.imshow("Image", img)
    cv2.waitKey(1) 
    if cv2.waitKey(1) == ord("q"):
        break
    

cap.release()
cv2.destroyAllWindows()
Roger Mas
  • 47
  • 1
  • 1
  • 6

1 Answers1

4

One way is to use time.time to measure how much time has passed (will print 'hi' every 5 seconds or so, this is less precise because if some part of the loop takes more time, it may print later than expected):

import time


start = time.time()
while True:
    # run some code

    current_time = time.time()
    if current_time - start >= 5:
        print('hi')
        start = current_time

Or use threading module to run a loop concurrently (will print 'hi' every 5 seconds, this is also more precise, because the time measurement is not affected by the speed of the "main" loop (as is the case with the above code)):

import time
import threading


def loop():
    while True:
        time.sleep(5)
        print('hi')


threading.Thread(target=loop).start()

while True:
    # run some code
    pass  # this can be removed after you add the actual code
Matiiss
  • 5,970
  • 2
  • 12
  • 29
  • Thanks. It works now, but the fps is still extremely low. I think it's because my m1 doesn't have enough processing capabilities. – Roger Mas Dec 31 '21 at 18:19
  • @RogerMas well neither method takes up any reasonable amount of processing power, especially the first one, if you have low fps it could be because of other functions that take longer than you expect or indeed the limitations of your hardware – Matiiss Dec 31 '21 at 18:35
  • Hmmm, it could be that I'm implementing your method wrong. I have updated my question with the new code. Would you be so kind as to have a look? Thanks. – Roger Mas Jan 01 '22 at 01:55
  • @RogerMas you do call your `data` method in the `if hands:` block, which means that it is gonna block the entire loop for 0.5 seconds, considering that `img` is a global variable, you can first of remove the argument from `data` function (also why doesn't it raise an error because you don't start thread with that argument?) and just not call `data` in the main loop or just use the first method with time measurement instead of threading, otherwise your current implementation as far as threading goes (except for that argument which you haven't given to the thread) seems completely fine to me – Matiiss Jan 01 '22 at 02:06
  • Thanks, I used your first method with time measurement, and it works perfectly. Sorry for not having checked first. As for the `img` argument, it seems to be necessary for the individual fingers, as otherwise it says that `local variable 'img' referenced before assignment`. – Roger Mas Jan 01 '22 at 02:50
  • @RogerMas great, no, I was wondering how it didn't raise an exception for this line: `threading.Thread(target=data).start()` because `data` _requires_ one positional argument and it is not provided here (btw for positional arguments you would use `args=(var1, ...)`), but great that the first method worked for you – Matiiss Jan 01 '22 at 02:54