├── README.md
├── prepare_data.py
├── test_model.py
├── thumbnail.jpg
├── train_model.py
└── utils.py
/README.md:
--------------------------------------------------------------------------------
1 | # emotion-recognition-python-scikit-learn-mediapipe
2 |
3 |
4 |
5 |
6 | Watch on YouTube: Emotion recognition with Python, Scikit Learn and Mediapipe !
7 |
8 |
9 |
10 | ## data
11 |
12 | You can download the same dataset I used in this tutorial [here](https://www.patreon.com/posts/97173398).
13 |
--------------------------------------------------------------------------------
/prepare_data.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import cv2
4 | import numpy as np
5 |
6 | from utils import get_face_landmarks
7 |
8 |
9 | data_dir = './data'
10 |
11 | output = []
12 | for emotion_indx, emotion in enumerate(sorted(os.listdir(data_dir))):
13 | for image_path_ in os.listdir(os.path.join(data_dir, emotion)):
14 | image_path = os.path.join(data_dir, emotion, image_path_)
15 |
16 | image = cv2.imread(image_path)
17 |
18 | face_landmarks = get_face_landmarks(image)
19 |
20 | if len(face_landmarks) == 1404:
21 | face_landmarks.append(int(emotion_indx))
22 | output.append(face_landmarks)
23 |
24 | np.savetxt('data.txt', np.asarray(output))
25 |
--------------------------------------------------------------------------------
/test_model.py:
--------------------------------------------------------------------------------
1 | import pickle
2 |
3 | import cv2
4 |
5 | from utils import get_face_landmarks
6 |
7 |
8 | emotions = ['HAPPY', 'SAD', 'SURPRISED']
9 |
10 | with open('./model', 'rb') as f:
11 | model = pickle.load(f)
12 |
13 | cap = cv2.VideoCapture(2)
14 |
15 | ret, frame = cap.read()
16 |
17 | while ret:
18 | ret, frame = cap.read()
19 |
20 | face_landmarks = get_face_landmarks(frame, draw=True, static_image_mode=False)
21 |
22 | output = model.predict([face_landmarks])
23 |
24 | cv2.putText(frame,
25 | emotions[int(output[0])],
26 | (10, frame.shape[0] - 1),
27 | cv2.FONT_HERSHEY_SIMPLEX,
28 | 3,
29 | (0, 255, 0),
30 | 5)
31 |
32 | cv2.imshow('frame', frame)
33 |
34 | cv2.waitKey(25)
35 |
36 |
37 | cap.release()
38 | cv2.destroyAllWindows()
--------------------------------------------------------------------------------
/thumbnail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/computervisioneng/emotion-recognition-python-scikit-learn-mediapipe/b59c6915e4e2614aa42757df3c058cb51f3c9ab9/thumbnail.jpg
--------------------------------------------------------------------------------
/train_model.py:
--------------------------------------------------------------------------------
1 | import pickle
2 |
3 | import numpy as np
4 | from sklearn.model_selection import train_test_split
5 | from sklearn.ensemble import RandomForestClassifier
6 | from sklearn.metrics import accuracy_score, confusion_matrix
7 |
8 | # Load data from the text file
9 | data_file = "data.txt"
10 | data = np.loadtxt(data_file)
11 |
12 | # Split data into features (X) and labels (y)
13 | X = data[:, :-1] # Features are all columns except the last one
14 | y = data[:, -1] # Labels are the last column
15 |
16 | # Split the data into training and testing sets
17 | X_train, X_test, y_train, y_test = train_test_split(X,
18 | y,
19 | test_size=0.2,
20 | random_state=42,
21 | shuffle=True,
22 | stratify=y)
23 |
24 | # Initialize the Random Forest Classifier
25 | rf_classifier = RandomForestClassifier()
26 |
27 | # Train the classifier on the training data
28 | rf_classifier.fit(X_train, y_train)
29 |
30 | # Make predictions on the test data
31 | y_pred = rf_classifier.predict(X_test)
32 |
33 | # Evaluate the accuracy of the model
34 | accuracy = accuracy_score(y_test, y_pred)
35 | print(f"Accuracy: {accuracy * 100:.2f}%")
36 | print(confusion_matrix(y_test, y_pred))
37 |
38 | with open('./model', 'wb') as f:
39 | pickle.dump(rf_classifier, f)
40 |
41 |
--------------------------------------------------------------------------------
/utils.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import mediapipe as mp
3 |
4 |
5 | def get_face_landmarks(image, draw=False, static_image_mode=True):
6 |
7 | # Read the input image
8 | image_input_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
9 |
10 | face_mesh = mp.solutions.face_mesh.FaceMesh(static_image_mode=static_image_mode,
11 | max_num_faces=1,
12 | min_detection_confidence=0.5)
13 | image_rows, image_cols, _ = image.shape
14 | results = face_mesh.process(image_input_rgb)
15 |
16 | image_landmarks = []
17 |
18 | if results.multi_face_landmarks:
19 |
20 | if draw:
21 |
22 | mp_drawing = mp.solutions.drawing_utils
23 | mp_drawing_styles = mp.solutions.drawing_styles
24 | drawing_spec = mp_drawing.DrawingSpec(thickness=2, circle_radius=1)
25 |
26 | mp_drawing.draw_landmarks(
27 | image=image,
28 | landmark_list=results.multi_face_landmarks[0],
29 | connections=mp.solutions.face_mesh.FACEMESH_CONTOURS,
30 | landmark_drawing_spec=drawing_spec,
31 | connection_drawing_spec=drawing_spec)
32 |
33 | ls_single_face = results.multi_face_landmarks[0].landmark
34 | xs_ = []
35 | ys_ = []
36 | zs_ = []
37 | for idx in ls_single_face:
38 | xs_.append(idx.x)
39 | ys_.append(idx.y)
40 | zs_.append(idx.z)
41 | for j in range(len(xs_)):
42 | image_landmarks.append(xs_[j] - min(xs_))
43 | image_landmarks.append(ys_[j] - min(ys_))
44 | image_landmarks.append(zs_[j] - min(zs_))
45 |
46 | return image_landmarks
--------------------------------------------------------------------------------