|
| 1 | +import cv2 |
| 2 | +import numpy as np |
| 3 | +import HandTrackingModule as htm |
| 4 | +import time |
| 5 | +import autopy |
| 6 | + |
| 7 | +########################## |
| 8 | +wCam, hCam = 640, 480 |
| 9 | +frameR = 100 # Frame reduction |
| 10 | +smoothening = 7 # Smoothing factor |
| 11 | +######################### |
| 12 | +# The above are comments used to create visual separators in the code. They can help developers to more clearly separate different parts of the code, making it more readable. These lines themselves have no function, just to improve code readability |
| 13 | + |
| 14 | +pTime = 0 |
| 15 | +plocX, plocY = 0, 0 |
| 16 | +clocX, clocY = 0, 0 |
| 17 | + |
| 18 | +cap = cv2.VideoCapture(0) |
| 19 | +cap.set(3, wCam) |
| 20 | +cap.set(4, hCam) |
| 21 | +detector = htm.handDetector(maxHands=1) |
| 22 | +wScr, hScr = autopy.screen.size() # Get screen width and height |
| 23 | +# autopy.screen.size() returns the screen size in pixels |
| 24 | +# wScr is the screen width, hScr is the screen height |
| 25 | +# print(wScr, hScr) |
| 26 | + |
| 27 | +while True: |
| 28 | + # 1. Detect hand landmarks |
| 29 | + success, img = cap.read() |
| 30 | + img = cv2.flip(img, 1) # Horizontally flip the image |
| 31 | + img = detector.findHands(img) |
| 32 | + lmList, bbox = detector.findPosition(img) |
| 33 | + |
| 34 | + # 2. Get positions of index and middle fingertips |
| 35 | + if len(lmList) != 0: |
| 36 | + x1, y1 = lmList[8][1:] |
| 37 | + x2, y2 = lmList[12][1:] |
| 38 | + # print(x1, y1, x2, y2) |
| 39 | + |
| 40 | + # 3. Check which fingers are up |
| 41 | + fingers = detector.fingersUp() |
| 42 | + # print(fingers) |
| 43 | + cv2.rectangle( |
| 44 | + img, (frameR, frameR), (wCam - frameR, hCam - frameR), (255, 0, 255), 2 |
| 45 | + ) |
| 46 | + |
| 47 | + # 4. Only index finger up: Moving mode |
| 48 | + if fingers[1] == 1 and fingers[2] == 0: |
| 49 | + # 5. Convert coordinates |
| 50 | + x3 = np.interp(x1, (frameR, wCam - frameR), (0, wScr)) |
| 51 | + y3 = np.interp(y1, (frameR, hCam - frameR), (0, hScr)) |
| 52 | + # np.interp() is a function for linear interpolation. Its basic usage: np.interp(x, xp, fp) |
| 53 | + # Where x is the point to interpolate, xp is the range of input data points (known x values), fp is the range of output data points (known y values) |
| 54 | + # Here, x1 and y1 are the positions of the finger in the camera image, (frameR, wCam - frameR) is the range of finger movement in the camera image, (0, wScr) and (0, hScr) are the screen coordinate ranges |
| 55 | + # Through np.interp(), the program maps the finger position in the camera image to the screen coordinates, thus achieving the correspondence between finger movement and mouse cursor movement. This allows finger movement in the camera to control the mouse cursor on the screen |
| 56 | + |
| 57 | + # 6. Smooth the values |
| 58 | + clocX = plocX + (x3 - plocX) / smoothening |
| 59 | + clocY = plocY + (y3 - plocY) / smoothening |
| 60 | + # clocX and clocY are the current smoothed coordinates, plocX and plocY are the previous frame coordinates |
| 61 | + # x3 and y3 are the target coordinates after interpolation in the current frame, smoothening is a smoothing factor to control the degree of smoothing |
| 62 | + # Each update, the current position (clocX, clocY) moves a small part towards the target position (x3, y3), smoothening controls the step size of the movement, the larger the value, the slower and smoother the movement |
| 63 | + # Smoothing makes the mouse pointer move a bit slower, but the purpose is to reduce jitter and make the movement smoother |
| 64 | + # If you feel the movement is too slow, you can try reducing the value of smoothening, so the pointer will follow the finger movement faster |
| 65 | + |
| 66 | + # 7. Move the mouse |
| 67 | + # autopy.mouse.move(wScr - clocX, clocY) |
| 68 | + # Use the above statement if not flipped |
| 69 | + autopy.mouse.move(clocX, clocY) |
| 70 | + cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED) |
| 71 | + plocX, plocY = clocX, clocY |
| 72 | + |
| 73 | + # 8. Both index and middle fingers up: Clicking mode |
| 74 | + if fingers[1] == 1 and fingers[2] == 1: |
| 75 | + # 9. Calculate the distance between the two fingers |
| 76 | + length, img, lineInfo = detector.findDistance(8, 12, img) |
| 77 | + print(length) |
| 78 | + |
| 79 | + # 10. If the distance is short, click the mouse |
| 80 | + if length < 40: |
| 81 | + cv2.circle(img, (lineInfo[4], lineInfo[5]), 15, (0, 255, 0), cv2.FILLED) |
| 82 | + autopy.mouse.click() |
| 83 | + |
| 84 | + # 11. Frame rate |
| 85 | + cTime = time.time() |
| 86 | + fps = 1 / (cTime - pTime) |
| 87 | + pTime = cTime |
| 88 | + cv2.putText(img, str(int(fps)), (20, 50), cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 0), 3) |
| 89 | + |
| 90 | + # 12. Display |
| 91 | + cv2.imshow("Image", img) |
| 92 | + cv2.waitKey(1) |
0 commit comments