Music Recommendation By Detecting Human Emotion 😁😥🥰😫
All About Music Recommendation by detecting Human.
- Creating Environnment with Python 3.7 and Installing Libreries.
- Performing basic preprocessing on the data.
- Applying KNN algorithm to the data.
- Data preparation for train test split and performing model training with Lightgbm Classifier to check the feature importace.
- Emotion Detection Starts.
Creating Environnment with Python 3.7 and Installing Libreries.
- 
Create a conda environment : conda create -n music python=3.7 -y
- 
Activate the conda environment : conda activate music
- 
Now install following libraries : pip install tensorflowpip install sklearnpip install matplotlibpip install pandaspip install numpypip install opencv-pythonpip install lightgbm
- 
After installing you are good to proceed further to importing required modules. 
- 
You can get the data for this project from here. 
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import lightgbm
import time
import cv2
from sklearn.model_selection import train_test_split
from sklearn.cluster import KMeans
from sklearn.preprocessing import MinMaxScaler
from lightgbm import LGBMClassifier
from tensorflow.keras.utils import img_to_array
from keras.preprocessing import image
from keras.models import load_model
import os
import tensorflow as tf
import time
import imutils
import argparse
from imutils.video import VideoStream
df = pd.read_csv('./Spotify Dataset Analysis/data.csv')
df.drop_duplicates(inplace=True, subset=['name'])
name = df['name']
- We are choosing "danceability", "energy", "valence", "loudness" columns since they are the most important features for our model from data analysis.
column_feat = ["danceability", "energy", "valence", "loudness"]
scaler = MinMaxScaler().fit_transform(df[column_feat])
kmeans = KMeans(init="k-means++",
                n_clusters=3, random_state=15).fit(scaler)
df['kmeans']= kmeans.labels_
# Setting up new column song_name
df['song_name'] = name
cluster = df.groupby(by=df['kmeans'])
X = df.drop(columns=['name','artists','id','release_date','song_name'])
Y = df.pop('kmeans')
X_train,X_test,y_train,y_test = train_test_split(X,
                                                 Y, test_size=0.25)
model = LGBMClassifier().fit(X_train,y_train)
model.score(X_train,y_train)
model.score(X_test,y_test)
- 
We can see our training and testing score of the model is quite good. 
- 
Now visualizing feature importance of the model. - We can see clearly that energy is the most important feature for our model.
 
ax = lightgbm.plot_importance(model,
                              max_num_features=10,
                              figsize=(15,10))
plt.show()
- Here we are sorting the cluster dataframe by papularity of the music and resetting the index.
data=cluster.apply(lambda x: x.sort_values(["popularity"],ascending=False))
data.reset_index(level=0, inplace=True)
Emotion Detection Starts.
- Loading Required model that is haarcascade_frontalface_default.xml for detecting face and epoch_75.hdf5 is for detecting emotion which I have already trained.
- Also giving the labels for different emotions.
- You can download a pretrained model from here
detector = cv2.CascadeClassifier(cv2.data.haarcascades + './haarcascade_frontalface_default.xml')
model = load_model("./epoch_75.hdf5")
EMOTIONS = ["Angry", "Scared", "Happy", "Sad", "Surprised", "Neutral"]
We are applying OpenCV to read a frame from a video and predicting using pre trained model.
def emotion_testing():
    global label
    cap = cv2.VideoCapture(0)
    time.sleep(2.0)
    while True:
        # grab the current Frame.
        _, frame = cap.read()
        # resize the frame and convert it to grayscale
        frame = imutils.resize(frame, width=300)
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        # initialize the canvas for the visualization, then clone
        # the frame so we can draw on it.
        canvas = np.zeros((220, 300, 3), dtype="uint8")
        frameClone = frame.copy()
        # Detect faces in the input frame, then clone the frame so that
        # we can draw on it
        rects = detector.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30), flags = cv2.CASCADE_SCALE_IMAGE)
        # Ensure at least one face was found before continuing.
        if len(rects) > 0:
            # determine the largest face area
            rect = sorted(rects, reverse=True,
                          key=lambda x: (x[2] - x[0]) * (x[3] - x[1]))[0]
            (fX, fY, fW, fH) = rect
            # extract the face ROI from the image, then preprocess
            # it for the network
            roi = gray[fY:fY + fH, fX:fX + fW]
            roi = cv2.resize(roi, (48, 48))
            roi = roi.astype("float") / 255.0
            roi = tf.keras.preprocessing.image.img_to_array(roi)
            roi = np.expand_dims(roi, axis=0)
            # Make a prediction on the ROI,then lookup the class
            # label
            preds = model.predict(roi)[0]
            label = EMOTIONS[preds.argmax()]
            #print(label)
            # Loop over the labels + probabilities and draw them
            for (i, (emotion, prob)) in enumerate(zip(EMOTIONS, preds)):
                # Construct the label text
                text = "{}: {:.2f}%".format(emotion, prob * 100)
                # Draw the label + probability bar on the canvas
                w = int(prob * 300)
                cv2.rectangle(canvas, (5, (i * 35) + 5),
                              (w, (i * 35) + 35), (0, 0, 255), -1)
                cv2.putText(canvas, text, (10, (i * 35) + 23),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.45,
                            (2, 180, 48), 2)
                # draw the label on the frame
                cv2.putText(frameClone, label, (fX, fY - 10),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.45, (252, 247, 48), 2)
                cv2.rectangle(frameClone, (fX, fY), (fX + fW, fY + fH),
                              (0, 0, 255), 2)
        # show our classifications + probabilities
        cv2.imshow("Face", frameClone)
        # cv2.imshow("Probabilities", canvas)
        # if the ’q’ key is pressed, stop the loop
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break
            
    return label
- Here following function generatesemotion code for each detected emotion. They are :- 0 : Neutral
- 1 : Happy
- 2 : Sad
 
def code():
    emotion_word = emotion_testing()
    if emotion_word == 'Neutral':
        emotion_code = 0
        print("Neutral detected ")
    elif emotion_word == 'Happy':
        emotion_code = 1
        print("Happy Detected..")
    elif emotion_word == 'Sad':
        emotion_code = 2
        print("Sad Detected..")
    else:
        print("Hi Deep!!")
    return emotion_code
- Following function is recommending songs according to the generated emotion code and kmeans labels.
def get_results():
    emotion_code = code()
    NUM_RECOMMEND=10
    happy_set=[]
    neutral_set=[]
    sad_set=[]
    if emotion_code==0:
        happy_set.append(data[data['kmeans']==0]['song_name'].head(NUM_RECOMMEND))
        return pd.DataFrame(happy_set).T
    elif emotion_code == 1:
        neutral_set.append(data[data['kmeans']==1]['song_name'].head(NUM_RECOMMEND))
        return pd.DataFrame(neutral_set).T
    else:
        sad_set.append(data[data['kmeans']==2]['song_name'].head(NUM_RECOMMEND))
        return pd.DataFrame(sad_set).T
- Here this function is to run whole model.
get_results()