Skip to content

Commit b78e23b

Browse files
committed
Update Chapter 2 4 5
1 parent 6e911d9 commit b78e23b

File tree

24 files changed

+761
-5
lines changed

24 files changed

+761
-5
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# This script can only detect gestures of the right hand
2+
import cv2
3+
import time
4+
import os
5+
import HandTrackingModule as htm
6+
7+
# Set the width and height of the camera, i.e., resolution
8+
wCam, hCam = 640, 480
9+
10+
# Open the camera
11+
cap = cv2.VideoCapture(0)
12+
cap.set(3, wCam) # Set camera width
13+
cap.set(4, hCam) # Set camera height
14+
15+
# Specify the path to the finger image folder
16+
folderPath = "E:\\Advance Computer Vision with Python\\main_en\\Project 2 Finger Counter\\FingerImages"
17+
myList = os.listdir(folderPath) # Get a list of all file names in the folder
18+
print(myList)
19+
20+
overlayList = [] # List to store finger images
21+
for imPath in myList:
22+
# Read each finger image
23+
image = cv2.imread(f"{folderPath}/{imPath}")
24+
overlayList.append(image) # Add image to the list
25+
26+
print(len(overlayList)) # Output the number of images
27+
28+
pTime = 0 # Initialize previous frame time
29+
30+
# Create a hand detector object, set detection confidence to 0.75
31+
detector = htm.handDetector(detectionCon=0.75)
32+
33+
# List of fingertip IDs
34+
tipIds = [4, 8, 12, 16, 20]
35+
36+
while True:
37+
success, img = cap.read() # Read frame from camera
38+
img = cv2.flip(img, 1) # Horizontally flip the image
39+
img = detector.findHands(img) # Detect hands and draw hand keypoints
40+
lmList = detector.findPosition(
41+
img, draw=False
42+
) # Get list of hand keypoint positions
43+
44+
if len(lmList) != 0:
45+
fingers = []
46+
47+
# Detect thumb (based on x-coordinates of thumb tip and second joint)
48+
if lmList[tipIds[0]][1] < lmList[tipIds[0] - 1][1]:
49+
# If following the source code, if lmList[tipIds[0]][1] > lmList[tipIds[0] - 1][1] determines the extension of the right thumb before flipping
50+
# So if I choose img = cv2.flip(img, 1), then if lmList[tipIds[0]][1] > lmList[tipIds[0] - 1][1] determines the extension of the left thumb after horizontal flipping, to keep detecting the right hand, change greater than to less than
51+
# Therefore, this script can only detect gestures of the right hand
52+
fingers.append(1) # 1 indicates the finger is extended
53+
else:
54+
fingers.append(0) # 0 indicates the finger is bent
55+
56+
# Detect the other four fingers (based on y-coordinates of fingertip and finger root)
57+
for id in range(1, 5):
58+
if lmList[tipIds[id]][2] < lmList[tipIds[id] - 2][2]:
59+
fingers.append(1)
60+
else:
61+
fingers.append(0)
62+
63+
totalFingers = fingers.count(1) # Count the number of extended fingers
64+
print(totalFingers)
65+
66+
# Select the image corresponding to the number of fingers and overlay it
67+
h, w, c = overlayList[totalFingers - 1].shape
68+
# totalFingers - 1 is because list indices start from 0, while totalFingers represents the number of fingers (starting from 1). So subtract 1 to correctly access the corresponding image in the list
69+
# Therefore, put 0 at the end of the list, because at this time no fingers are extended, totalFingers is 0, subtracting 1 gets -1, which is the last one in the list
70+
img[0:h, 0:w] = overlayList[
71+
totalFingers - 1
72+
] # Place the image of the corresponding number of fingers in the top-left corner of the camera image
73+
74+
# Draw a rectangle and display the number of fingers
75+
cv2.rectangle(img, (20, 225), (170, 425), (0, 255, 0), cv2.FILLED)
76+
cv2.putText(
77+
img,
78+
str(totalFingers),
79+
(45, 375),
80+
cv2.FONT_HERSHEY_PLAIN,
81+
10,
82+
(255, 0, 0),
83+
25,
84+
)
85+
86+
cTime = time.time() # Get current frame time
87+
fps = 1 / (cTime - pTime) # Calculate frame rate
88+
pTime = cTime # Update previous frame time
89+
90+
# Display frame rate on the image
91+
cv2.putText(
92+
img, f"FPS: {int(fps)}", (400, 70), cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 0), 3
93+
)
94+
95+
# Display the processed image
96+
cv2.imshow("Image", img)
97+
cv2.waitKey(1) # Wait for a key press, 1 millisecond
16.9 KB
Loading
17.4 KB
Loading
19 KB
Loading
19 KB
Loading
20.7 KB
Loading
14.7 KB
Loading
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
"""
2+
Hand Tracing Module
3+
By: Murtaza Hassan
4+
Youtube: http://www.youtube.com/c/MurtazasWorkshopRoboticsandAI
5+
Website: https://www.computervision.zone
6+
7+
Modified by: Diraw
8+
Date: 20240812
9+
Description:
10+
1. Modified the initialization of the `Hands` object to use named parameters for better clarity and compatibility with the latest version of the mediapipe library. This change ensures that the parameters are correctly mapped to the expected arguments in the `Hands` class.
11+
2. Added a line to flip the image horizontally using `cv2.flip(img, 1)` to ensure the hand movements appear mirrored, which is more intuitive for user interaction
12+
"""
13+
14+
import cv2
15+
import mediapipe as mp
16+
import time
17+
18+
19+
# Hand detector class
20+
class handDetector:
21+
def __init__(self, mode=False, maxHands=2, detectionCon=0.5, trackCon=0.5):
22+
# Initialize parameters
23+
self.mode = mode # Whether to use static mode
24+
self.maxHands = maxHands # Maximum number of hands to detect
25+
self.detectionCon = detectionCon # Detection confidence
26+
self.trackCon = trackCon # Tracking confidence
27+
28+
# Initialize MediaPipe hand model
29+
self.mpHands = mp.solutions.hands
30+
# self.hands = self.mpHands.Hands(
31+
# self.mode, self.maxHands, self.detectionCon, self.trackCon
32+
# )
33+
self.hands = self.mpHands.Hands(
34+
static_image_mode=self.mode,
35+
max_num_hands=self.maxHands,
36+
min_detection_confidence=self.detectionCon,
37+
min_tracking_confidence=self.trackCon,
38+
)
39+
40+
# Initialize drawing tools
41+
self.mpDraw = mp.solutions.drawing_utils
42+
43+
def findHands(self, img, draw=True):
44+
# Convert the image to RGB
45+
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
46+
# Process the image to detect hands
47+
self.results = self.hands.process(imgRGB)
48+
49+
# If hands are detected
50+
if self.results.multi_hand_landmarks:
51+
for handLms in self.results.multi_hand_landmarks:
52+
# Draw hand keypoints and connections
53+
if draw:
54+
self.mpDraw.draw_landmarks(
55+
img, handLms, self.mpHands.HAND_CONNECTIONS
56+
)
57+
return img
58+
59+
def findPosition(self, img, handNo=0, draw=True):
60+
lmList = [] # Store hand keypoint positions
61+
if self.results.multi_hand_landmarks:
62+
myHand = self.results.multi_hand_landmarks[handNo]
63+
for id, lm in enumerate(myHand.landmark):
64+
# Get image dimensions
65+
h, w, c = img.shape
66+
# Calculate pixel position of keypoints
67+
cx, cy = int(lm.x * w), int(lm.y * h)
68+
lmList.append([id, cx, cy])
69+
# Draw keypoints
70+
if draw:
71+
cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)
72+
return lmList
73+
74+
75+
# Main function
76+
def main():
77+
pTime = 0 # Previous frame time
78+
cTime = 0 # Current frame time
79+
cap = cv2.VideoCapture(0) # Open the camera
80+
detector = handDetector() # Create hand detector object
81+
82+
while True:
83+
success, img = cap.read() # Read camera frame
84+
img = cv2.flip(img, 1) # Horizontally flip the image
85+
img = detector.findHands(img) # Detect hands and draw
86+
lmList = detector.findPosition(img) # Get hand keypoint positions
87+
if len(lmList) != 0:
88+
print(lmList[4]) # Print coordinates of the thumb tip
89+
90+
cTime = time.time() # Get current time
91+
fps = 1 / (cTime - pTime) # Calculate frame rate
92+
pTime = cTime # Update previous frame time
93+
94+
# Display frame rate on the image
95+
cv2.putText(
96+
img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 255), 3
97+
)
98+
99+
# Display the image
100+
cv2.imshow("Image", img)
101+
cv2.waitKey(1)
102+
103+
104+
if __name__ == "__main__":
105+
main()
Binary file not shown.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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

Comments
 (0)