From b8d22e49f812ffbd048d9fa3cd2e847bb52e15f4 Mon Sep 17 00:00:00 2001 From: Maryne DEY Date: Thu, 16 Feb 2023 10:47:03 +0100 Subject: [PATCH 01/11] Adding documentation --- FFT.m | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 FFT.m diff --git a/FFT.m b/FFT.m new file mode 100644 index 0000000..05be1df --- /dev/null +++ b/FFT.m @@ -0,0 +1,47 @@ +%%%%%%%%%%%%%%%%%%%%% +% Script task: Normalize RGB data and plot FFT using the power spectra +% +% Input : RGB_data.csv -> average RGB values of each image +% +% Output : Fast Fourier Transform of X(t): a graph representing the Single-Sided Amplitude Spectrum of X(t) +% +% Author: Maryne DEY (maryne.dey@ecam.fr) +% Date: 07/02/2023 +%%%%%%%%%%%%%%%%%%%%% + +clear all +close all +clc + +pkg load io %% to be able to extract from external format (excel) + +data = csvread('RGB_database/RGB_data.csv'); +standard_deviation = std(data); +mean_value = mean(data); + +for i = 1:size(data,1) + normalized_data_G(i,1) = (data(i,2)-mean_value(2))/standard_deviation(2); %%2 and not 1 because green is the 2nd color +endfor + +Fs = 970/32; % Sampling frequency = 970 images in 32 seconds +T = 1/Fs; % Sampling period +L = 970; % Length of signal = 32 seconds +t = (0:L-1)*T; % Time vector + +X = normalized_data_G; + +plot(t(1:970),X(1:970)) +title("Signal") +xlabel("t (milliseconds)") +ylabel("X(t)") + +Y = fft(X); +P2 = abs(Y/L); +P1 = P2(1:L/2+1); +P1(2:end-1) = 2*P1(2:end-1) +f = Fs*(0:(L/2))/L + +plot(f(25:end),P1(25:end)) +title("Single-Sided Amplitude Spectrum of X(t)") +xlabel("f (Hz)") +ylabel("|P1(f)|") \ No newline at end of file From 6c08fdc2661fb44c8b26175bf2ab82ed3a2c4709 Mon Sep 17 00:00:00 2001 From: Maryne DEY Date: Thu, 16 Feb 2023 12:04:29 +0100 Subject: [PATCH 02/11] Normalize RGB data, graph FFT using the power spectra and extract the heart rate --- FFT.m | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/FFT.m b/FFT.m index 05be1df..5580dbe 100644 --- a/FFT.m +++ b/FFT.m @@ -13,8 +13,10 @@ clear all close all clc -pkg load io %% to be able to extract from external format (excel) +%To be able to extract from external format (excel) +pkg load io +%Normalization of the data data = csvread('RGB_database/RGB_data.csv'); standard_deviation = std(data); mean_value = mean(data); @@ -23,6 +25,7 @@ for i = 1:size(data,1) normalized_data_G(i,1) = (data(i,2)-mean_value(2))/standard_deviation(2); %%2 and not 1 because green is the 2nd color endfor +%Input characteristics Fs = 970/32; % Sampling frequency = 970 images in 32 seconds T = 1/Fs; % Sampling period L = 970; % Length of signal = 32 seconds @@ -30,18 +33,33 @@ t = (0:L-1)*T; % Time vector X = normalized_data_G; +%Plot of the RGB data in the time domain plot(t(1:970),X(1:970)) title("Signal") xlabel("t (milliseconds)") ylabel("X(t)") +%Finding power spectra P2 and P1 Y = fft(X); P2 = abs(Y/L); P1 = P2(1:L/2+1); -P1(2:end-1) = 2*P1(2:end-1) -f = Fs*(0:(L/2))/L +P1(2:end-1) = 2*P1(2:end-1); +f = Fs*(0:(L/2))/L; -plot(f(25:end),P1(25:end)) +% Finding boudaries +start = find(f==0.75); +stop = find(f==4); +P1_graph = P1(start:stop); +f_graph = f(start:stop); + +%Graph of FFT in function of the frequency +plot(f_graph,P1_graph) title("Single-Sided Amplitude Spectrum of X(t)") xlabel("f (Hz)") -ylabel("|P1(f)|") \ No newline at end of file +ylabel("|P1(f)|") + +%Extracting the heart rate +[heart_rate_Hz, index] = max(P1_graph); +corresponding_frequency = f_graph(index); +heart_rate_bpm = corresponding_frequency*60; +fprintf("Your heart rate is about %d bpm.\n", heart_rate_bpm) \ No newline at end of file From eb51e3914e96e9b663fb0ba31fb1bcbf9bd1910e Mon Sep 17 00:00:00 2001 From: Maryne DEY Date: Thu, 16 Feb 2023 12:07:33 +0100 Subject: [PATCH 03/11] Wrong start --- normalization.m | 38 -------------------------------------- 1 file changed, 38 deletions(-) delete mode 100644 normalization.m diff --git a/normalization.m b/normalization.m deleted file mode 100644 index 88a9594..0000000 --- a/normalization.m +++ /dev/null @@ -1,38 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%% -% Task: Creating FFT of average R,G,B over a period of 30 seconds -% -% Input: -% - CSV file containing the RGB data for each pixels of the region of interest -% -% Output: -% - Fast Fourier Transform of the colors over time -% -% author: Delattre Loïc, Dey Maryne (loic.delattre@ecam.fr, maryne.dey@ecam.fr) -% date: 06/02/2023 -%%%%%%%%%%%%%%%%%%%%% - -pkg load io %% to be able to extract from external format (excel) - -data = csvread('RGB_database/RGB_data.csv') -standard_deviation = std(data) -mean_value = mean(data) - -for i = 1:size(data,1) - normalized_data_G(i,1) = (data(i,2)-mean_value(2))/standard_deviation(2); %%2 and not 1 because green is the 2nd color -endfor - -fft_green = fft(normalized_data_G) - -plot([1:size(fft_green,1)],fft_green) - - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%For all the colors -%%for j = 1:3 -%% for i = 1:size(data,1) -%% normalized_data(i,j) = (data(i,j)-mean_value(j))/standard_deviation(j); -%% endfor -%%endfor -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file From 58b3da59b0fbacaf6243aff385b64fe4dfb3303d Mon Sep 17 00:00:00 2001 From: Maryne DEY Date: Thu, 16 Feb 2023 12:16:25 +0100 Subject: [PATCH 04/11] Normalization of the data, graph of FFT using power spectra and retrieval of the heart rate --- FFT_heart_rate.m | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 FFT_heart_rate.m diff --git a/FFT_heart_rate.m b/FFT_heart_rate.m new file mode 100644 index 0000000..5580dbe --- /dev/null +++ b/FFT_heart_rate.m @@ -0,0 +1,65 @@ +%%%%%%%%%%%%%%%%%%%%% +% Script task: Normalize RGB data and plot FFT using the power spectra +% +% Input : RGB_data.csv -> average RGB values of each image +% +% Output : Fast Fourier Transform of X(t): a graph representing the Single-Sided Amplitude Spectrum of X(t) +% +% Author: Maryne DEY (maryne.dey@ecam.fr) +% Date: 07/02/2023 +%%%%%%%%%%%%%%%%%%%%% + +clear all +close all +clc + +%To be able to extract from external format (excel) +pkg load io + +%Normalization of the data +data = csvread('RGB_database/RGB_data.csv'); +standard_deviation = std(data); +mean_value = mean(data); + +for i = 1:size(data,1) + normalized_data_G(i,1) = (data(i,2)-mean_value(2))/standard_deviation(2); %%2 and not 1 because green is the 2nd color +endfor + +%Input characteristics +Fs = 970/32; % Sampling frequency = 970 images in 32 seconds +T = 1/Fs; % Sampling period +L = 970; % Length of signal = 32 seconds +t = (0:L-1)*T; % Time vector + +X = normalized_data_G; + +%Plot of the RGB data in the time domain +plot(t(1:970),X(1:970)) +title("Signal") +xlabel("t (milliseconds)") +ylabel("X(t)") + +%Finding power spectra P2 and P1 +Y = fft(X); +P2 = abs(Y/L); +P1 = P2(1:L/2+1); +P1(2:end-1) = 2*P1(2:end-1); +f = Fs*(0:(L/2))/L; + +% Finding boudaries +start = find(f==0.75); +stop = find(f==4); +P1_graph = P1(start:stop); +f_graph = f(start:stop); + +%Graph of FFT in function of the frequency +plot(f_graph,P1_graph) +title("Single-Sided Amplitude Spectrum of X(t)") +xlabel("f (Hz)") +ylabel("|P1(f)|") + +%Extracting the heart rate +[heart_rate_Hz, index] = max(P1_graph); +corresponding_frequency = f_graph(index); +heart_rate_bpm = corresponding_frequency*60; +fprintf("Your heart rate is about %d bpm.\n", heart_rate_bpm) \ No newline at end of file From 7f8cd87cbb91b6ecbe5c78dc94a4d83bd2937c3a Mon Sep 17 00:00:00 2001 From: Maryne DEY Date: Thu, 16 Feb 2023 12:20:00 +0100 Subject: [PATCH 05/11] Conflicts due to poor backup --- FFT.m | 65 ----------------------------------------------------------- 1 file changed, 65 deletions(-) delete mode 100644 FFT.m diff --git a/FFT.m b/FFT.m deleted file mode 100644 index 5580dbe..0000000 --- a/FFT.m +++ /dev/null @@ -1,65 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%% -% Script task: Normalize RGB data and plot FFT using the power spectra -% -% Input : RGB_data.csv -> average RGB values of each image -% -% Output : Fast Fourier Transform of X(t): a graph representing the Single-Sided Amplitude Spectrum of X(t) -% -% Author: Maryne DEY (maryne.dey@ecam.fr) -% Date: 07/02/2023 -%%%%%%%%%%%%%%%%%%%%% - -clear all -close all -clc - -%To be able to extract from external format (excel) -pkg load io - -%Normalization of the data -data = csvread('RGB_database/RGB_data.csv'); -standard_deviation = std(data); -mean_value = mean(data); - -for i = 1:size(data,1) - normalized_data_G(i,1) = (data(i,2)-mean_value(2))/standard_deviation(2); %%2 and not 1 because green is the 2nd color -endfor - -%Input characteristics -Fs = 970/32; % Sampling frequency = 970 images in 32 seconds -T = 1/Fs; % Sampling period -L = 970; % Length of signal = 32 seconds -t = (0:L-1)*T; % Time vector - -X = normalized_data_G; - -%Plot of the RGB data in the time domain -plot(t(1:970),X(1:970)) -title("Signal") -xlabel("t (milliseconds)") -ylabel("X(t)") - -%Finding power spectra P2 and P1 -Y = fft(X); -P2 = abs(Y/L); -P1 = P2(1:L/2+1); -P1(2:end-1) = 2*P1(2:end-1); -f = Fs*(0:(L/2))/L; - -% Finding boudaries -start = find(f==0.75); -stop = find(f==4); -P1_graph = P1(start:stop); -f_graph = f(start:stop); - -%Graph of FFT in function of the frequency -plot(f_graph,P1_graph) -title("Single-Sided Amplitude Spectrum of X(t)") -xlabel("f (Hz)") -ylabel("|P1(f)|") - -%Extracting the heart rate -[heart_rate_Hz, index] = max(P1_graph); -corresponding_frequency = f_graph(index); -heart_rate_bpm = corresponding_frequency*60; -fprintf("Your heart rate is about %d bpm.\n", heart_rate_bpm) \ No newline at end of file From 3d977128083d07413ccff229a611ee089cf3008e Mon Sep 17 00:00:00 2001 From: Loic Delattre Date: Sat, 18 Feb 2023 15:25:56 +0100 Subject: [PATCH 06/11] exports all frames from a given video file --- get_frames.py | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/get_frames.py b/get_frames.py index 252c5d9..8d1f010 100644 --- a/get_frames.py +++ b/get_frames.py @@ -3,14 +3,34 @@ import os.path import os from PIL import Image -# Opens the Video file +############### +# def get_frames(input1) +# ex. get_frames(video.mov) +# +# Task: Extracting frames from a video +# +# Inputs: +# - input1: a video +# +# Output: +# -RGB_avg: a directory with all the frames of the video +# +# author: Loic Delattre and Maryne Dey (loic.delattre@ecam.fr, maryne.dey@ecam.fr) +# date: 06/02/2023 +############### + + video = 'my_face.mov' -path_to_script = os.path.dirname(os.path.abspath(__file__)) -if os.path.exists(path_to_script + r"\frames") == False: - os.mkdir(path_to_script + r"\frames") + def get_frames(vid): + path_to_script = os.path.dirname(os.path.abspath(__file__)) + if os.path.exists(path_to_script + r"\frames") == False: + os.mkdir(path_to_script + r"\frames") + + # Opens the Video file cap= cv2.VideoCapture(vid) + i=0 while cap.isOpened(): ret, img = cap.read() @@ -21,15 +41,15 @@ def get_frames(vid): eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) - faces = face_cascade.detectMultiScale(gray, 1.3, 5) + faces = face_cascade.detectMultiScale(gray, 1.3, 5) #detect the face in the frame for (x,y,w,h) in faces: - # To draw a rectangle in a face + # To draw a rectangle in a face for testing purposes cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,0),2) roi_gray = gray[y:y+h, x:x+w] roi_color = img[y:y+h, x:x+w] - eyes = eye_cascade.detectMultiScale(roi_gray) + eyes = eye_cascade.detectMultiScale(roi_gray) #detect the eyes in the frames taking the face as reference list_ex = [] list_ey = [] list_ew = [] @@ -46,10 +66,10 @@ def get_frames(vid): #rectangle on forhead try: - fx = min(list_ex) + list_ew[list_ex.index(min(list_ex))] + fx = min(list_ex) + list_ew[list_ex.index(min(list_ex))] #deducing ROI from the eyes rectangle coordinates fy = max(list_ey) x1 = x + fx - x2 = x + fx + 100 + x2 = x + fx + 100 #extra values in x and y in the parameters are adjustements made after manual testing y1 = y + fy - 150 y2 = y + fy - 20 @@ -59,8 +79,7 @@ def get_frames(vid): i+=1 except: print('error on min value of ex') - #extra values in x and y in the parameters are adjustements made after manual testing - #cv2.rectangle(roi_color, (fx,fy-150),(fx+100,fy-20),(0,127,255),2) + #cv2.rectangle(roi_color, (fx,fy-150),(fx+100,fy-20),(0,127,255),2) #for testing purposes cap.release() cv2.destroyAllWindows() From 00610fcf1bbb759d34a00c52066d0d1f57b50b3a Mon Sep 17 00:00:00 2001 From: Loic Delattre Date: Sat, 18 Feb 2023 15:27:14 +0100 Subject: [PATCH 07/11] find the average RGB values of a given frame --- RGB_traces.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RGB_traces.m b/RGB_traces.m index 6f7ff06..e39dd23 100644 --- a/RGB_traces.m +++ b/RGB_traces.m @@ -10,7 +10,7 @@ % Output: % -RGB_avg: a 1x3 matrix with the RGB average values, format -> [R, G, B] % -% author: Loic Delattre (loic.delattre@ecam.fr) +% author: Maryne Dey and Loic Delattre (maryne.dey@ecam.fr, loic.delattre@ecam.fr) % date: 06/02/2023 %%%%%%%%%%%%%%%%%%%%% From 6bca74a49d237fcae1f7d487341c225e71b70e61 Mon Sep 17 00:00:00 2001 From: Loic Delattre Date: Sat, 18 Feb 2023 15:28:42 +0100 Subject: [PATCH 08/11] outputs a n x 3 matrix of RGB averages for all frames in a given directory --- frames_RGBs.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frames_RGBs.m b/frames_RGBs.m index decc610..b17235d 100644 --- a/frames_RGBs.m +++ b/frames_RGBs.m @@ -29,7 +29,7 @@ function RGB_data = frames_RGBs () endwhile catch disp('scanned all frames') - j = 10001 + j = 10001; end_try_catch endwhile From 9efdbb57bdb52f2c61182cf7f2e279dc696452b3 Mon Sep 17 00:00:00 2001 From: Loic Delattre Date: Sat, 18 Feb 2023 15:29:15 +0100 Subject: [PATCH 09/11] find the average value of a matrix --- matrix_avg.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix_avg.m b/matrix_avg.m index a4f8b32..900ed86 100644 --- a/matrix_avg.m +++ b/matrix_avg.m @@ -10,7 +10,7 @@ % Output: % -RGB_avg: a 1x3 matrix with the RGB average values % -% author: Loic Delattre (loic.delattre@ecam.fr) +% author: Maryne Dey and Loic Delattre (maryne.dey@ecam.fr, loic.delattre@ecam.fr) % date: 06/02/2023 %%%%%%%%%%%%%%%%%%%%% From a9bb0b72a53d8cd5468734a23842e1336b827345 Mon Sep 17 00:00:00 2001 From: Loic Delattre Date: Sat, 18 Feb 2023 15:29:55 +0100 Subject: [PATCH 10/11] finds the user's heartbeat from a set of frames of their face --- FFT_heart_rate.m | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/FFT_heart_rate.m b/FFT_heart_rate.m index 5580dbe..1989734 100644 --- a/FFT_heart_rate.m +++ b/FFT_heart_rate.m @@ -5,7 +5,7 @@ % % Output : Fast Fourier Transform of X(t): a graph representing the Single-Sided Amplitude Spectrum of X(t) % -% Author: Maryne DEY (maryne.dey@ecam.fr) +% Author: Loic Delattre and Maryne DEY (maryne.dey@ecam.fr, loic.delattre@ecam.fr) % Date: 07/02/2023 %%%%%%%%%%%%%%%%%%%%% @@ -17,7 +17,7 @@ clc pkg load io %Normalization of the data -data = csvread('RGB_database/RGB_data.csv'); +data = frames_RGBs ()'; standard_deviation = std(data); mean_value = mean(data); @@ -26,15 +26,16 @@ for i = 1:size(data,1) endfor %Input characteristics -Fs = 970/32; % Sampling frequency = 970 images in 32 seconds +img_num = length(data); +Fs = img_num/32; % Sampling frequency = X images in 32 seconds T = 1/Fs; % Sampling period -L = 970; % Length of signal = 32 seconds +L = img_num; % Length of signal = 32 seconds t = (0:L-1)*T; % Time vector X = normalized_data_G; %Plot of the RGB data in the time domain -plot(t(1:970),X(1:970)) +plot(t(1:L),X(1:L)) title("Signal") xlabel("t (milliseconds)") ylabel("X(t)") From d0f76a60e23a7019af8c38461a7c94752926d45d Mon Sep 17 00:00:00 2001 From: Loic Delattre Date: Sat, 18 Feb 2023 15:43:26 +0100 Subject: [PATCH 11/11] exports all frames from a given video file --- get_frames.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/get_frames.py b/get_frames.py index 8d1f010..0000598 100644 --- a/get_frames.py +++ b/get_frames.py @@ -57,7 +57,7 @@ def get_frames(vid): #To draw a rectangle in eyes for (ex,ey,ew,eh) in eyes: - if ew >= 80 and eh >= 80: + if ew >= 82 and eh >= 82: #cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,127,255),2) list_ex.append(ex) list_ey.append(ey) @@ -80,6 +80,8 @@ def get_frames(vid): except: print('error on min value of ex') #cv2.rectangle(roi_color, (fx,fy-150),(fx+100,fy-20),(0,127,255),2) #for testing purposes + #cv2.imshow('img',roi_color) + #cv2.waitKey(0) cap.release() cv2.destroyAllWindows()